データ構造

ヒープソート

最大ヒープを作り、根の最大値を末尾へ移した後、残りの範囲でヒープ条件を復元します。親子の位置は配列内で計算できるため、別の木は保存しません。

配列と木を同期して表示するヒープソートシミュレーター

再生・ステップ実行・スライダーで操作できます。下の木は、棒グラフと同じ配列の別の見方です。

最良O(n log n)
平均O(n log n)
最悪O(n log n)
追加領域O(1)
安定いいえ
ヒープ構築O(n)

配列そのものが木になる

位置iの子は2i+1と2i+2、親は(i−1)//2です。sift_downは大きい方の子と交換し、ヒープ条件を満たすまで下がります。1回の移動はO(log n)段なので、繰り返し取り出すとO(n log n)になります。

初期構築では最後の親から根へ向かってsift_downします。大半のノードは下層にあり移動距離が短いため、構築全体はO(n)です。

演習:優先度付きキューとしてのヒープ

ヒープソートを自作するより、優先度付きキューを使う場面が一般的です。Pythonの heapqは最小ヒープです。数値の符号を反転すると最大ヒープとして使えます。大きい方からk個を求めるには、サイズkの最小ヒープでO(n log k)にできます。

import heapq
h = []
for x in a:
    heapq.heappush(h, x)
    if len(h) > k:
        heapq.heappop(h)    # ヒープの最小値を除く
# hには大きい方からk個が残る