ティムソートで配列を並び替える
ティムソートを使用する
ティムソート (Timsort) は、Tim Peters が Python の list.sort() 向けに設計した 安定 な比較ソートである。
マージソートの分割・併合の枠組みに、すでに整列している連続区間(ラン) を活かす仕組みと、短いランを伸ばす 挿入ソート を組み合わせた ハイブリッド アルゴリズムである。
Python 3 の組み込みソートや、Java のオブジェクト配列向け Arrays.sort など、実用の標準ソートとして広く採用されている。
- ランの検出: 配列を左から走査し、昇順 または 厳密な降順 の連続区間(ラン)を見つける。降順ランはその場で反転し、昇順ランにそろえる。
- ランの拡張: ランの長さが 最小ラン長
minRun未満なら、二分探索付き挿入ソートでminRunまで(または配列末尾まで)伸ばす。minRunは配列長から計算され、おおむね 32〜64 付近になる(デモでは見やすさのため 4 に固定している)。 - スタックへの積み上げ: 整えたランを
(開始, 長さ)としてスタックに push する。 - マージの抑制: push のたびに、スタック上のラン長のバランスを見て 隣接ランをマージ する。最後に残ったランをすべて併合して全体を整列する。
procedure timsort(A)
n = length(A)
minRun = compute_min_run(n)
stack = empty list of runs
i = 0
while i < n
runLen = count_run(A, i)
if A[i .. i+runLen-1] is descending then
reverse(A, i, i + runLen - 1)
if runLen < minRun then
extend_run_with_insertion(A, i, min(i + minRun, n) - 1)
runLen = min(minRun, n - i)
push stack with (i, runLen)
merge_collapse(stack, A)
i = i + runLen
merge_force_collapse(stack, A)
マージ自体はマージソートと同様に 2 本の昇順列の先頭を比較しながら確定させる。実装では ガロップ(一方の列が連続して勝つときにまとめて取り込む)などの最適化も入るが、デモでは基本的な 2 路マージまでを追えるようにしている。
最悪時間計算量 は O(n log n)。すでに昇順に近い入力ではランが長く取れ、最良は O(n) に近づく。安定ソート であり、等しいキーの相対順序を保つ。補助領域はマージ用に O(n) が必要になることが多い。
クイックソートのように最悪 O(n²) に落ちにくく、マージソートのように 安定 で O(n log n) を保てる点が実データ向けの強みである。一方でラン管理やマージ用バッファなど実装は重く、教育用の最小例としてはマージソートや挿入ソート単体のほうが追いやすい。ティムソートは「実世界の偏りのある入力でも速く・安定に」という目的で標準ライブラリに組み込まれるタイプのソートである。