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

第四回 (2010年11月4日)

ヒープとヒープソート

http://www.sw.it.aoyama.ac.jp/2011/DA/lecture4.html

Martin J. Dürst

AGU

© 2008-11 Martin J. Dürst 青山学院大学

目次

前回のまとめ

前回の宿題 (1)

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

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

正解: O(n log log n), O(n log n), O(n2), O(20n), O(n!)

f(n) g(n) n0 (正解例) c (正解例)
n log log n n log n 2 1
n log n n2 2 1
n2 20n 1 1
20n n! 52 1
20n n! 20 2020/20!

ヒント: Ruby は Bignum がある為に馬鹿でかい数字の計算に便利

 

前回の宿題 (2)

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

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

正解例: 4prioQ.rb

順位キュー

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

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

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

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

単純な実装

各操作の計算量
実装 Array (常順) Array (探索) LinearList (常順) LinearList (探索)
新規作成 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
子と比較、必要であれば優先度の高い子と交換、交換されたら子で続く

実装: 4heap.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 './4heap'
=> 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>
 ...

その他のヒープ

今回のまとめ

次回のための準備