← ブログ一覧

ヒープソート、最大ヒープで最大値を一つずつ取り出す - AlgoNote

ソートヒープヒープソート優先度付きキューAlgoNote

ヒープソートとは?

ヒープソート(Heap Sort)は、配列を最大ヒープ(max-heap)にしてから、最大値であるルートを末尾へ取り出す作業を繰り返す整列です。追加配列なしでその場整列しながら、入力に関係なく常にO(n log n)を保証します。

核心の一行: 「最大値を速く取り出して後ろから積む」。 ヒープは最大値をO(1)で確認しO(log n)で取り出せる構造なので、これをn回繰り返すと整列が完成します。


まず、ヒープ構造の復習

配列を完全二分木として見ます。インデックス i に対して

  • 左の子 = 2i + 1、右の子 = 2i + 2
  • 親 = (i - 1) / 2

最大ヒープは「すべての親が子以上」という規則を守る木なので、ルート(インデックス0)が常に全体の最大値です。


動作原理

ステップ1. ヒープ構築(build heap). 最後の親ノードからインデックス0まで逆向きに、各ノードにsift-down(heapify)を適用して配列全体を最大ヒープにします。これはO(n)です。

ステップ2. 最大値の取り出し. ルート(arr[0])とヒープの末尾要素を交換し、最大値を配列末尾の定位置へ送ります。

ステップ3. ヒープの復元. ヒープサイズを1減らし、ルートからsift-downを1回行って最大ヒープ性を復元します。

ステップ4. ヒープサイズが1になるまでステップ2〜3を繰り返します。後ろから大きな値が積まれ昇順になります。

AlgoNoteの可視化は「ヒープ構築」と「取り出し&復元」を別ステップで示すので流れが一目でわかります。


時間計算量と空間計算量

計算量
時間O(n log n)
空間O(1)

ヒープ構築はO(n)、その後のn回の取り出しが各O(log n)なので全体はO(n log n)です。マージソートのように常にO(n log n)を保証しつつ、追加配列なしでその場整列するため空間はO(1)です。


例で追ってみる

[3, 1, 4, 1, 5] を最大ヒープにするとルートに 5 が来ます。

  • 5 と末尾を交換 → 末尾に 5 確定、復元 → ルート 4
  • 4 と末尾から2番目を交換 → ...4 5、復元 → ルート 3
  • 繰り返すと [1, 1, 3, 4, 5] 完成

毎回「現在のヒープの最大値」が抜けて後ろから整列されます。


よくあるミス

  • sift-down/upの混同: 整列段階でルートを沈めるときはsift-downです。挿入(押し上げ)と混同しないように。
  • ヒープサイズの管理: 既に取り出した要素(整列済みの末尾)をヒープ範囲に再び含めると整列が壊れます。
  • 子インデックスの式: 2i+1/2i+2 の範囲チェックを忘れると配列外を参照します。

AlgoNoteで直接確認しましょう

配列が最大ヒープになり、ルートが末尾へ抜け、ヒープが再編成される過程をAlgoNoteでステップごとに確認できます。

ヒープソートの可視化へ →

ヒープソート、最大ヒープで最大値を一つずつ取り出す - AlgoNote - AlgoNote | 알고노트(AlgoNote)