zatsu na benkyou matome saito

勉強したことをまとめるだけのサイト、数学、プログラミング、機械学習とか

データ構造とアルゴリズム:cocktail(シェーカーソート)

cocktail(シェイクソート)

カクテルをシェークするような動きをするのでこのような名前がつけられている。bubbleソートの改良版でbubbleソートにかなり類似しておりbubbleソートを振る、ようなイメージ。

まず、左から右に配列を見ていって小さければ入れ替え、というのはbubbleソートの時と同様。 ただ、swap = Falseというフラグがあり、その周回の時に入れ替えが起きたらSwapをTrueに変更する。一番右のlimitまできたらswapをFalseに直して、今度は右から左に数字を見る。

この時に左の方が大きければ、右と入れ替える。という作業を行う。一番大きい数値は最初の段階で一番右にくるのでlimitを一つ下げる。 スクリーンショット 2020-11-25 0.54.25.png (223.0 kB)

スクリーンショット 2020-11-25 0.54.58.png (239.5 kB)

右から左に来るときは、一番左の数値が一番小さい数値になるので左側のlimitを一つ上げるようにする。

スクリーンショット 2020-11-25 0.57.47.png (244.1 kB)

一度もswapがTrueにならなかったらその時点でソートを完了して良い。そのため、swapが Trueにならない周回があったらその時点でソートが完了しているとみなしても良いため、全てのパターンを行う必要がなくBubbleソートよりも早く処理が完了する。 スクリーンショット 2020-11-25 0.58.54.png (309.7 kB)

  • まずswapの初期値がTrueなのでwhile swappedの箇所でwhilteのloopに入る。
  • 通常のbubbleソート同様に左の数値が大きければ右の数値と入れ替えるというのを1重のfor文で実現する
  • ①の最後でもしswappが起こればswappedフラグをTrueにする。
    • この時点で、swappedがFalseのままであれば、その時点でソート完了し、breakとなる
    • 初期でendを−1している理由は、最初のfor文で一番後ろに最大値が移動するので一番後ろまで処理する必要がないから
  • そのご②に入る
    • ②に入る前にend - 1をしてあげることで、limitを一つずらす
  • for i in range(end-1, start-1, -1):というfor文は配列を逆順に入れる作業をしている
    • この逆順にする作業で、for文を逆から読み込ませる作業を行なっている。実際に行っているのは通常のbubbleソートの逆順にしたバージョンである。
    • 最後にもしswapped = Trueになれば再度一番上に戻り①からやり直しswapped = Falseのまま続くまで行う。
from typing import List

def cocktail_sort(numbers: List[int]) -> List[int]:
    len_numbers = len(numbers)
    swapped = True
    start = 0
    end = len_numbers - 1
    
    while swapped:
        swapped = False
        # 右方向に進むときの for loop
        # for①=============================start
        for i in range(start, end):
            if numbers[i] > numbers[i+1]:
                numbers[i], numbers[i+1] = numbers[i+1], numbers[i]
                swapped = True
        # for①=============================end
        
        # swappが変更されなければfalseのままなのでここで処理が終了
        if not swapped:
            break

        swapped = False
        end = end - 1
        
        # for②=============================start
        for i in range(end-1, start-1, -1):
            if numbers[i] > numbers[i+1]:
                numbers[i], numbers[i+1] = numbers[i+1], numbers[i]
                swapped = True
        # for②=============================end
        start = start + 1
    
    return numbers


import random
arry = [random.randint(0, 100) for i in range(10)]
print(cocktail_sort(arry))


[0, 5, 36, 44, 53, 55, 68, 83, 84, 96]

このサイトのgif?がすごくわかりやすいのだが、右に行くときは大きいものを一番右に押しやる作業、左に行くときは小さいものを一番左に押しやる作業を行なっているのがわかる。 眺めていられるシェーカーソートのシミュレーション|JavaScript

ダウンロード.png (32.9 kB)