データ構造とアルゴリズム

第五回 (2013年10月25日)

ヒープとヒープソート

http://www.sw.it.aoyama.ac.jp/2013/DA/lecture5.html

Martin J. Dürst

AGU

© 2009-13 Martin J. Dürst 青山学院大学

目次

前回のまとめ

前回の宿題 (1)

次の関数をオーダの順にならべ、理由を付けなさい。

O(n2), O(n!), O(n log log n), O(n log n), O(20n)

[都合により削除]

 

前回の宿題 (3)

順位キュー (priority queue) という ADT を実装しなさい
(Ruby でも他言語でもよい)

順位キューは各要素ごとに優先度 (整数など) が付く。一番簡単な場合にデータ項目は優先度だけ。優先度の高いものが先にキューから出る。実装は配列でも連結リストでもよい。

正解例: 5prioQ.rb

順位キュー

(priority queue, 優先順位キュー、優先順位付き待ち行列)

IT の例
プロセス管理など
操作
作成 (new, init)、空かどうかのテスト (empty?)

insert (add,...): 項目の追加、getNext/delMax/...: 最優先項目の返しと削除

findMax/peekAtNext/...: 最優先項目を返すだけ

単純な実装

各操作の計算量
実装 配列 (常順) 配列 (探索) 連結リスト (常順) 連結リスト (探索)
新規作成 O(1) O(1) O(1) O(1)
項目追加 O(n) O(1) O(n) O(1)
最優先項目 O(1) O(n) O(1) O(n)
項目削除 O(1) O(n) O(1) O(n)
empty? O(1) O(1) O(1) O(1)
長さ O(1) O(1) O(n) O(n)

実装によって操作の計算量が違うが、必ずどこかで O(n) の計算量になる

改善は可能でしょうか

 

順位キューの改善のための発想

 

 

 

完全二分木

木構造に基づく定義:

別の定義 (Knuth):

ヒープ

(heap)

⇒ ルートは常に一番優先

各操作の実現:

普遍条件

(英語: invariant)

ヒープの普遍条件の修復

ある場所で、優先度が高かすぎる可能性の場合: heapify_up
親と比較、必要であれば交換、交換されたら親で続く

ある場所で、優先度が低くすぎる可能性の場合: heapify_down
子と比較、必要であれば優先度の高い子と交換、交換された子で続く

実装: 5heap.rb

ヒープによる順位キューの実装

各操作の計算量
実装 Heap (Array による実装)
新規作成 O(1)
項目追加 O(log n)
最優先項目 O(1)
項目削除 O(log n)
empty? O(1)
長さ O(1)

ヒープソート

(heap sort)

irb の使い方

irb: Interactive Ruby, Ruby 用のコマンドプロンプト

使用例:

C:\Algorithms>irb
irb(main):001:0> require './5heap'
=> true
irb(main):002:0> h = Heap.new
=> #<Heap:0x2833d60 @array=[nil], @size=0>
irb(main):003:0> h.add 3
=> #<Heap:0x2833d60 @array=[nil, 3], @size=1>
irb(main):004:0> h.add(5).add(7)
=> #<Heap:0x2833d60 @array=[nil, 7, 3, 5], @size=3>
 ...

その他のヒープ

今回のまとめ

次回のための準備