📛

シェルソートまとめ

2024/10/09に公開

シェルソートとは?

シェルソート(Shell sort)は以下のような特徴を持つソートアルゴリズムです:

  1. 基本原理:

    • 挿入ソートを改良したアルゴリズムです。
    • 大きな間隔で要素を比較・交換し、徐々に間隔を狭めていきます。
  2. アルゴリズムの流れ:

    • 適切な間隔(ギャップ)を選択します。
    • その間隔ごとに要素をグループ化し、各グループ内で挿入ソートを行います。
    • 間隔を小さくし、再度ソートを行います。
    • 間隔が1になるまでこのプロセスを繰り返します。
  3. 性能:

    • 平均的な時間計算量: O(n^(1.3)) から O(n^(1.5))(間隔の選び方に依存)
    • 最悪の場合の時間計算量: O(n^2)
    • 空間計算量: O(1)(インプレースソート)

インプレースソート(In-place sort)とは

https://zenn.dev/btc/articles/241009_in_place_sort

  1. 特徴:

    • 挿入ソートの改良版で、大きな配列に対してより効率的です。
    • 不安定ソート:同じ値の要素の相対的な順序が保たれない可能性があります。
    • インプレースソート:追加のメモリをほとんど必要としません。
  2. 利点:

    • 中規模のデータセットに対して効率的です。
    • 実装が比較的簡単です。
    • 挿入ソートよりも高速です。
  3. 欠点:

    • 大規模なデータセットに対しては、クイックソートやマージソートほど効率的ではありません。
    • 最適な間隔列の選択が難しく、性能に大きく影響します。
  4. 間隔列の選択:

    • 一般的な間隔列には、シェルの元々の間隔(n/2, n/4, ..., 1)や、Knuthの間隔(1, 4, 13, 40, ...)などがあります。
    • 間隔列の選択により、アルゴリズムの性能が大きく変わります。

シェルソートは、その簡単な実装と中規模データセットに対する効率性から、実用的なソートアルゴリズムとして広く使用されています。特に、ほぼソートされているデータや、小さな要素が大きな要素の後ろにある場合に効果的です。

コード例

シェルソートの具体的なPythonコード例を以下に示します:

def shell_sort(arr):
    n = len(arr)
    gap = n // 2

    while gap > 0:
        for i in range(gap, n):
            temp = arr[i]
            j = i
            while j >= gap and arr[j - gap] > temp:
                arr[j] = arr[j - gap]
                j -= gap
            arr[j] = temp
        gap //= 2

    return arr

# 使用例
arr = [64, 34, 25, 12, 22, 11, 90]
print("ソート前:", arr)
sorted_arr = shell_sort(arr)
print("ソート後:", sorted_arr)

このコードの主な特徴は以下の通りです:

  1. ギャップ(間隔)の初期化:

    • 初期ギャップを配列の長さの半分に設定します(gap = n // 2)。
  2. ギャップを徐々に減少:

    • while ループでギャップが0より大きい間、処理を続けます。
    • 各イテレーションの最後でギャップを半分にします(gap //= 2)。
  3. 挿入ソート的な処理:

    • 現在のギャップを使用して、配列の要素を比較・交換します。
    • temp変数を使用して、現在の要素を一時的に保存します。
  4. 要素の移動:

    • 内側のwhileループで、ギャップ間隔で離れた要素を比較し、必要に応じて交換します。
  5. インプレース処理:

    • 追加の配列を使用せず、元の配列内で直接ソートを行います。

このアルゴリズムは、平均的にO(n log n)よりも悪い時間計算量を持ちますが、実際には多くの場合で効率的に動作します。特に、ほぼソートされているデータや中規模のデータセットに対して効果的です。

実行結果は以下のようになります:

ソート前: [64, 34, 25, 12, 22, 11, 90]
ソート後: [11, 12, 22, 25, 34, 64, 90]

このコードは理解しやすく、効率的なシェルソートの実装例となっています。ギャップの選択方法を変更することで、さらにパフォーマンスを向上させることも可能です。

Discussion