アルゴリズムとデータ構造
第3章 ヒープ
6月7日分(解決編)
情報知能学科
白井英俊
いろいろな木
• 木はグラフの特殊なもので、二進木は木の特殊なも
のである。つまり、これらには「上位・下位」(含む、
含まれる)という関係がある。
• 講義で取り扱ういろいろな木の関係を図で表す
データ構造
グラフ
Nodeクラス
木
Vertexクラス
二進木
強平衡二進木
ヒープ
配列
強平衡二進木
差が0か1
• 教科書 p.27
強平衡二進木:すべての不完全頂点の深さ
は「高々1しか違わない」ような二進木
• 用語(二進木において)
完全頂点:子の数が2の頂点
不完全頂点:子の数が0か1の頂点
強平衡二進木の練習
以下のうち、強平衡二進木はどれか?
(1)
(2)
(3)
(4)
強平衡二進木(続き)
完全頂点
不完全頂点
(2)
(3)
深さ0
深さ1
深さ2
不完全頂点の差は高々1
不完全頂点の差は最大2
練習問題
前回調べた、高さ2の二進木において、
強平衡二進木はどれか?
予習問題:ヒープの条件(i)を満たすものは
どれか?
不完全頂点を
マーク
高さ 2 の二進木
(1)
(2)
(3)
(8)
(7)
(10)
(11)
(4)
(5)
(6)
(9)
(12)
高さ 2 の二進木(続き)
これらはみな強平衡二進木
(13)
(16)
(19)
(14)
(17)
(20)
(15)
(18)
(21)
ヒープ
• ヒープ(heap)とは、特殊な二進木
定義3.2 高さkの二進木Tがヒープであるための
必要十分条件は次の(i), (ii)を満たすこと
(i) 深さ0 ~ k-1 の可能な頂点はすべて使われ、
深さkの頂点は左から順に使われている
(ii) 頂点uが頂点vの親なら
uの値( f(u) ) ≧ vの値( f(v) )
親
子
「可能な頂点」と「使われている」
高さ 1 の二進木を考える
①
「可能な頂点」は3個
②
③
(1)
実際に木の
頂点になっ
ている
②
①
木の頂点になりうるもの
(2) ①
③
①と②が使われ③
は使われていない
①と③が使われ②
は使われていない
ヒープ(続き)
• ヒープの条件の(i)は「強平衡二進木」の条
件よりもキツイ
• 木Tがヒープならば、Tは強平衡二進木で
もある
ヒープ(続き)
• 高さ2の二進木のいくつか:ヒープの条件(i)を満たすの
はどれか?
深さ0,1の頂点はすべて使われ、
深さ2の頂点は左から使われている
演習問題
• 高さ2のヒープ条件(i)を満たす二進木をすべ
て書き下す
(ヒント: 4通りある)
高さ 2 の二進木
(1)
(2)
(3)
(8)
(7)
(10)
(11)
(4)
(5)
(6)
(9)
(12)
高さ 2 の二進木(続き)
(13)
(16)
(19)
(14)
(17)
(20)
(15)
(18)
(21)
ヒープ(続き)
• ヒープの条件(ii) 共にヒープ条件(i)
は満たしている
8
5
3
8
7
5
7
10
5 ≧ 10 が不成立!
ヒープの条件(ii):
親の頂点の値 ≧ 子の頂点の値
ヒープの作成
• 二分探索木を作ってソートするのではな
く、ヒープを作ってソートするメリット
頂点数(=入力データ数)をnとすると、
木の高さは常に O(log n)
⇒ 二分探索木を使った場合の最悪のケー
スが起こらない
最悪のケース:
葉以外のどの頂点も
配列を使ってヒープを表現可能 子が1つしかないような
場合。二分探索が使え
(教科書p.31-32)
ず、木の高さもO(n)にな
る。
配列を用いたヒープの表現
①
⑤ ⑥
⑧
⑨
根
{
②
④
0
1
2
深さ1
3
③
4
深さ2
5
⑦
6
7
深さ3 8
9
偶数:
左の子
奇数:
右の子
…
…
二進木による表現
{
{
根以外は
注目:深さkの一番左の子の番号は 2k 配列による表現
それでは一番右の子の番号は ?
ヒープの特徴
頂点の番号のつけ方:
1
二進木
上から下、左から右
3
2
4
8
5
9
6
7
10
この番号の付け方から、高さ n (> k)のヒープでは、
★深さ k の最も左の頂点の番号は 2k
★深さ k の最も右の頂点の番号は 2(k+1) - 1
ヒープの演習
1. ヒープの条件(i)を持つ
高さ2、頂点数6の二進木
を書け
定義3.2 高さkの二進木Tにおいて
(i) 深さ0 ~ k-1 の可能な頂点はすべて使われ、
深さkの頂点は左から順に使われている
1
(20)
3
2
4
5
6
ヒープの演習(続)
2. ヒープの条件(i)を持つ
高さ3、頂点数 11 の二進木 を書け
1
3
2
4
8
5
9
10
6
7
11
ヒープの演習(続)
3. 右の配列に対応する二進木を書け。
ただし、ヒープを配列で表す規則に従うと
する。
これはヒープの条件を満たしているか?
1
3
2
4
8
5
9
6
7
0
1
2
3
4
5
6
7
8
9
10
11
30
30
25
25
28
20
24
26
18
18
19
11
これらはみな、親のノードの値が子のノードの値より
大きいので、ヒープの条件をみたしている
ヒープの演習(続)
4. 以下の二進木に対応する配列をかけ。
ただし、ヒープを配列で表す規則に従う
とする。これはヒープの条件をすべて
満たすか?
20
15
10
44
1
7
3
5
11
11
6
2
これらはみな、親のノードの値が子のノードの値より
大きいので、ヒープの条件をみたしている
0
1
2
3
4
5
6
7
8
9
10
11
12
ヒープへの要素の追加(挿入)手続き
手続き:以下の2ステップで行う
• 新たな要素を値とする頂点をヒープに追加
⇒ 条件(i)を満たすところに
(2) 次に、ヒープ条件(ii)を満たすように修
正する
定義3.2 二進木Tにおいて
(ii) 頂点uが頂点vの親なら
uの値≧ vの値
ヒープへの要素の追加(1)
例:
定義3.2 二進木Tにおいて
(ii) 頂点uが頂点vの親なら
uの値≧ vの値
8
5
3
7
10
に3を追加する…
それには、ここしかない
そして、ヒープ条件(ii)を満たし
ているのでヒープが完成
さらに、 10を追加する。。。
これは、ヒープ条件(ii)を満たして
いないので『修正』が必要
ヒープへの要素の追加(1)続き
ヒープの条件(i)を満たすように要素を追加する
ことは、
(b)二進木で表す場合、「可能な頂点を左から順
に使う」
(a) 配列で表す場合は分かりやすい
⇒ ヒープの最後の要素のインデックスを
x とすれば、x+1 番目に要素を追加すれ
ばよい
ヒープへの要素の追加(2)「修正」
• 追加した頂点を v とする
• ヒープの条件(ii)は、
親頂点の値≧子頂点の値
だから、これが満たされていればOK.
そうでなければ、上の条件を満たすように、頂
点を入れ替えていく(修正する)
ヒープへの要素の追加(2)続き
ヒープへの要素の追加の完成
条件を破ってい
る
8
5
3
7
10
条件を破ってい
る
具体的に例を用いてヒープを作る
入力データ:
8
5
3
1
7
10
20
{ 8 5 7 3 10
9 6 1 20 }
9
6
ヒープ条件(ii)を破っ
ているので、『修正』
が必要
問題: ヒープ条件(ii)が成り立つようにす
るには、どのように『修正』したらよいか?
答え:
ヒープの演習(続)
5 (a) 問題(4)において、10番目の要素として
「15」が入っているとする。1~10番目までの要
素からなる配列は、ヒープの条件を満たしてい
るか?その理由も述べよ。
(b)問題(4)において、10番目の要素として「40」
が入っているとする。1~10番目までの要素から
なる配列は、ヒープの条件を満たしているか?
その理由も述べよ。
(b) (5a), (5b)で、「ヒープになっていないも
の」に対し、1~10番目までの要素からなる配列
をヒープにする(演習3.6)ことを考える。その
結果のヒープを示せ。
ヒープの演習(続)
6. 以下の配列はヒープの条件を満たしているか?満たしていなけれ
ば(i)を行え。
(i) 1番目の要素から順に10番目までの要素をヒープにする操作を
行い、最終的に得られたヒープを示せ。
(ii) 次に、1番目の要素と10番目の要素を入れ替え、1~9番目の要
素からなる配列をヒープに修復せよ(演習3.7)
(iii) これに続けて9,8,…,2と順に一番目の要素と入れ替えてはヒープ
に修復する操作を行い、最終的に得られた配列を示せ。
(iv) n 個の要素を持つ配列(1~n番目に要素があるとする)に対し、
(i)の操作でヒープを作る計算量のオーダーはどのくらいか、また
(ii)の手順で最終の配列を得るための計算量のオーダーはどのく
らいか?
1
2
30 25
3
4
5
6
20 16 24 18
7
8
9
12 10
8
10
15
ヒープソート(Heap Sort)
ヒープを用いてソート(並び替え)を行う
手続き:
(1) x1, x2, …, xn からヒープ(木)を作る
計算量は O(n * log n)
ヒープ木においては根が最大の値の頂点
(2) 根と『最も深い頂点のうち最も右端の頂点』とを交
換し、『根だった頂点をヒープから切り離し』てから
ヒープを作り直す。この操作一回ごとの計算量は
O(log n)
(3) (2)を繰り返し、切り離された頂点をすべて並べると
ソート完成(新しく切り離された頂点が最小、古いも
のが最大)
ヒープソート(続き)
ヒープの作り直し(ヒープソートのステップ(2))
20
10
5 ≦ 8
1
3
≧
9
7
1. 根と『最も深く右側の頂
点』とを交換し、根だった頂
点を切り離す
2. ヒープ条件(ii)を満たすよ
う、ヒープを作り直す
親頂点と、子頂点のう
ち大きいほうを交換。
6
問題: ヒープをどのように作り直すか?
問題: この後ヒープをどのように作り直すか?
ヒープソートの真髄
ヒープを配列で表わす
⇒『木』よりも簡単なデータ構造で実行可能
インデックスによって、根の頂点を簡単に求めること
ができる
また、注目している頂点のインデックスから、その親
や子の頂点が何かが簡単に計算できる
問題: 注目している頂点のインデックスをxとすると、
その親と子の頂点のインデックスは?
演習問題
配列を用いてヒープソートするプログラムを作る。
(1) 入力データからヒープ(配列で表現)を作る関数
(makeHeap)を作れ
(2) ヒープにおいて、根と最後の要素とを交換する
コード(swapNodes)を書け
(3) 最後の要素のインデックスを x とすると、
1~(x-1) までの要素をヒープに作り直すコード
(remakeHeap)を書け
(4) 以上を組み合わせて、ヒープソートを行う関数
(heapSort)を書け
ダウンロード

Chap3-3Review