Upload
others
View
1
Download
0
Embed Size (px)
Citation preview
情報システム基盤学 基礎1
アルゴリズムとデータ構造
Elements of Information
Systems Fundamentals1
1
第5回:貪欲法と最小全域木
目次
貪欲法とは
グラフの最小全域木
Kraskalのアルゴリズム
Primのアルゴリズム
ビンソート、Radix ソート
付録:ヒープソート
2
貪欲法(Greedy Algorithm)
最適化問題において解を逐次的に構成する際に、その時点で利益を最大化する選択を行う
将来のことを考えず局所的に最適な選択を実行
利点:アルゴリズムが単純
最適解を得られるかわからない
最適解が得られる問題もある
例:最小全域木問題
近似アルゴリズムになる問題も多い
3
Greedy Algorithmの例
有向グラフGにおけるs,t間の最短経路問題
DAG(Directed Acyclic Graph): cycle(閉路)を持たない有向グラフ
cycleを持たない無向グラフ⇒木
Greedy Algorithm place=s //place: 現在いる場所
while(place が t でない)
placeから最短の辺を選択して隣接ノード(aと記述)に進む
place = a 4
1
4
8 7
2
6
2
8 7
14
10
9
t s
最適解
貪欲法は最適解でない
貪欲法が最適解となる問題の条件
最適化問題を
選択
選択の結果、残る部分問題
の組み合わせとみなす
1. 部分構造最適性
問題の最適解が部分問題の最適解を含む
2. 貪欲選択性
貪欲な選択を含む最適解が必ず存在する
貪欲な選択+残りの部分問題の最適解
⇒元の問題の最適解 5
ナップサック問題 ナップサック 容量W
品物の集合={m1,m2,...,mn} vi: miの価値
wi: miの重さ
目的:ナップサックに入れる品物の価値を最大化
制約条件:入れた品物の重さの合計≤ 𝑊
𝑣𝑖
𝑤𝑖 (重さあたりの価値)が大きい品物を入れるのが得
6
m1 m2 m3 knapsack
価値 60 100 120
重さ(kg) 10 20 30 50
価値/重さ 6 5 4
0-1ナップサック問題
各商品miを入れるか入れないかを判定
入れる⇒1
入れない⇒0
7
有理ナップサック問題 各商品miをどれだけ入れるかを判定
0≤入れる量≤ 𝑤𝑖
貪欲法が最適解
貪欲法が最適解にならない
貪欲アルゴリズム
m1 m2 m3 knapsack
価値 60 100 120
重さ(kg) 10 20 30 50
価値/重さ 6 5 4
8
1. 重さあたりの価値が最大の品物を入れるだけ入れる
2. ナップサックに空きがあれば、重さあたりの価値が次に大きい品物を入れる
0-1ナップサック問題:
m1,m2を入れる ⇒ 価値=160, 最適解ではない
最適解: m2,m3を入れる⇒ 価値=220
有理ナップサック問題: m1:10kg, m2: 20kg, m3:20kg ⇒価値60+100+ 20x4= 240, 最適
m2
m2 m3
m1
ナップサック
m2 m1 m3
ナップサック問題の部分構造最適性
部分構造最適性を持つ
有理ナップサック問題も同様
9
0-1ナップサック問題の最適解:{m2,m3}
• m3を入れることを選択
• 残る部分問題 • ナップサックの容量: 50-30=20
• 商品: m1,m2のみ 最適解: {m2}
ナップサックの容量=50
m2 m3 部分問題
ナップサップ問題の貪欲選択性
0-1ナップサップ問題は持たない
有理ナップサック問題は持つ
10
m1 部分問題
最適解は「m1の選択」と「残りの部分問題の最適解」では構成できない
最適解は「m1の選択」と「残りの部分問題の最適解」で構成可
貪欲法が最適解となる問題の条件
最適化問題を
選択
選択の結果、残る部分問題
の組み合わせとみなす
1. 部分構造最適性
問題の最適解が部分問題の最適解を含む
2. 貪欲選択性
貪欲な選択を含む最適解が必ず存在する
貪欲な選択+残りの部分問題の最適解
⇒元の問題の最適解 11
問題
最小全域木を求める問題
12
重み付き無向グラフ G の最小全域木を求める
G の全域木: G の全頂点を含む部分木
G の最小全域木: G の全域木のうち,
総重みが最小のもの
4
8
11 7
1 2
6
2
8 7
4 14
10
9
最小全域木
4
8
11 7
1 2
6
2
8 7
4 14
10
9
(ただの)全域木 (総和: 8+1+2+4+2+8+7+9=41) (総和: 8+1+2+4+2+4+7+9=37)
1
Kruskalアルゴリズムの概要
性質:木はcycleを含まない⇒cycleを含むグラフは木でないので最小全域木ではない
cycleができないという条件下で
13
• 貪欲アルゴリズム(greedy algorithm)
4
8
11 7
1 2
6
2
8 7
4 14
10
9 4
8
11 7
2
6
2
8 7
4 14
10
9 4
8
11 7
1 2
6
2
8 7
4 14
10
9 最小
最小全域木
対偶
重み最小の辺を1つずつ追加して全域木を作る
最小
アルゴリズムの流れ
14
初期状態: n 個の集合
• 各頂点=「1頂点からなる集合」
全域木ができるまで、辺を1本追加することを繰り返す
繰り返し:
異なる集合に属する頂点を結ぶ重み最小辺を
追加して2個の集合を統合
終了状態: 集合が1つだけになる(全域木を得る)
4
8
11 7
1 2
6
2
8 7
4 14
10
9 4
8
11 7
1 2
6
2
8 7
4 14
10
9 4
8
11 7
1 2
6
2
8 7
4 14
10
9
cycleを作らないと同値
Kruskalのアルゴリズム
15
アルゴリズム
全ての辺を重み順にソート
for each v ∈ V
for all edges (u,v) ∈ E (重みが小さい辺から順番に)
if 頂点 u が属する集合≠ 頂点 v が属する集合
4
8
11 7
1 2
6
2
8 7
4 14
10
9 4
8
11 7
1 2
6
2
8 7
4 14
10
9 4
8
11 7
1 2
6
2
8 7
4 14
10
9
点v のみからなる集合を生成
then A ← A ∪ {(u,v)} // A に辺(u,v)を追加
u が属す集合と v が属す集合を統合
A ← Φ
return A // このとき A は最小全域木の辺を含む
A:現在選んでいる辺
からなる集合
初期化/前処理 貪欲戦略
if文の意味 アルゴリズム実行の任意の時点で
各集合はAの辺によって構成された木 帰納法で証明
1. 異なる木間に辺追加
cycle発生しない。より大きな木が出来る
2. 同じ木内に辺追加⇒cycle発生
17
木T1 木T2
違う木内で辺
Aの辺によって構成されたより大きな木
T1とT2が連結
if文の意味 アルゴリズム実行の任意の時点で
各集合はAの辺によって構成された木 帰納法で証明
1. 異なる木間に辺追加
cycle発生しない。より大きな木が出来る
2. 同じ木内に辺追加⇒cycle発生
18
木T1 木T2
同じ木内で辺
cycle発生
木T1 木T2
if文で防止
Kruskalのアルゴリズム: 動作例 1/2
19
4
8
11 7
1 2
6
2
8 7
4 14
10
9 4
8
11 7
1 2
6
2
8 7
4 14
10
9 4
8
11 7
1 2
6
2
8 7
4 14
10
9
(1) 初期状態 (2) 辺(g,h)追加
a
b
h
i
c
g
d
f
e a
b
h
i
c
g
d
f
e a
b
h
i
c
g
d
f
e
(3) 辺(c,i)追加
4
8
11 7
1 2
6
2
8 7
4 14
10
9
a
b
h
i
c
g
d
f
e
(4) 辺(f,g)追加
4
8
11 7
1 2
6
2
8 7
4 14
10
9
a
b
h
i
c
g
d
f
e
(5) 辺(a,b)追加
4
8
11 7
1 2
6
2
8 7
4 14
10
9
a
b
h
i
c
g
d
f
e
(6) 辺(c,f)追加
4
8
11 7
1 2
6
2
8 7
4 14
10
9
a
b
h
i
c
g
d
f
e
(7) 辺(g,i)選ばない
4
8
11 7
1 2
6
2
8 7
4 14
10
9
a
b
h
i
c
g
d
f
e
(8) 辺(c,d)追加
4
8
11 7
1 2
6
2
8 7
4 14
10
9
a
b
h
i
c
g
d
f
e
(9) 辺(i,h)選ばない
Kruskalのアルゴリズム: 動作例 2/2
20
4
8
11 7
1 2
6
2
8 7
4 14
10
9
a
b
h
i
c
g
d
f
e
(10) 辺(a,h)追加
4
8
11 7
1 2
6
2
8 7
4 14
10
9
a
b
h
i
c
g
d
f
e
(11) 辺(b,c)選ばない
4
8
11 7
1 2
6
2
8 7
4 14
10
9
a
b
h
i
c
g
d
f
e
(12) 辺(d,e)追加
(全域木は完成!!)
4
8
11 7
1 2
6
2
8 7
4 14
10
9
a
b
h
i
c
g
d
f
e
(13) 辺(e,f)選ばない
4
8
11 7
1 2
6
2
8 7
4 14
10
9
a
b
h
i
c
g
d
f
e
(14) 辺(b,h)選ばない
4
8
11 7
1 2
6
2
8 7
4 14
10
9
a
b
h
i
c
g
d
f
e
(15) 辺(d,f)選ばない
(答えを返してから)
アルゴリズム終了
Cut Property(カットの性質)
21
𝑒を含む最小全域木が存在
Kruskalのアルゴリズムの正しさの土台
任意の𝑆 ⊆ 𝑉に対するカットC(𝑆, 𝑉 − 𝑆)
𝑒 ∈ 𝐶(𝑆, 𝑉 − 𝑆): 𝑆と𝑉 − 𝑆を結ぶ重み最小辺
グラフGのカット
22
𝑆 ⊆ 𝑉: Gの頂点集合Vの部分集合
カット:Gから辺を除去して𝑆と𝑉 − 𝑆に分割
C 𝑆, 𝑉 − 𝑆 ⊆ 𝐸: 除去される辺の集合
4
8
11 7
1 2
6
2
8 7
4 14
10
9
a
b
h
i
c
g
d
f
e
𝑆 𝑉 − 𝑆 C(S,V-S)
Cut Propertyの証明
23
背理法:カットの重み最小辺𝑒を含む最小全域木がない 𝑒 = argmin
𝑏𝜖𝐶(𝑆,𝑉−𝑆)𝑤(𝑏)
𝑇:最小全域木
𝑒と異なる𝑒′ ∈ 𝐶 𝑆, 𝑉 − 𝑆 を含み、𝑤(𝑒) ≤ 𝑤(𝑒′)
𝑇 = 𝑇𝑠⋃𝑒′⋃𝑇𝑉−𝑆
𝑇𝑆: Sの全域木(最小全域木とは限らない)
𝑇𝑉−𝑆: V-Sの全域木
𝑆 𝑉 − 𝑆 C(S,V-S)
e
e'
木𝑇𝑠
木𝑇𝑉−𝑆
24
𝑇∗ = 𝑇𝑠⋃𝑒⋃𝑇𝑉−𝑆を考える
T*はグラフGの全域木
1. 𝑤(𝑒) < 𝑤(𝑒′) ⇒ 𝑇∗の重み< 𝑇の重み
𝑇が最小全域木であることに矛盾
2. 𝑤 𝑒 = 𝑤(𝑒′) ⇒ 𝑇∗も最小全域木
eを含む最小全域木が存在するので矛盾
𝑆 𝑉 − 𝑆 C(S,V-S)
e
e'
木𝑇𝑠
木𝑇𝑉−𝑆
Kruskalのアルゴリズムの正しさ 辺の選択方法
u は集合𝑆𝑢に属し、v は集合𝑆𝑢に属さない
𝑢, 𝑣 ∈ 𝐶 𝑆𝑢, 𝑉 − 𝑆𝑢
𝑢, 𝑣 は𝐶(𝑆𝑢, 𝑉 − 𝑆𝑢)で最初に選択された
重みが最小の辺
⇒ (𝑢, 𝑣)は最小全域木に含まれる 25
for all edges (u,v) ∈ E (重みが小さい辺から順番に)
if 頂点 u が属する集合≠ 頂点 v が属する集合
then A ← A ∪ {(u,v)} // A に辺(u,v)を追加
u が属す集合と v が属す集合を統合
(A:現在、選択済みの辺からなる集合)
e
𝑆𝑢 V-𝑆𝑢
u v
u' v'
𝑆𝑢: if文成立時点でuが属する集合
アルゴリズムの計算量
集合操作は𝑂 log 𝑉 で出来る
全体の計算量は𝑂 |𝐸| log 𝐸 = 𝑂 |𝐸| log 𝑉
𝐸 < 𝑉 2に注意 26
アルゴリズム
全ての辺を重み順にソート
for each v ∈ V
for all edges (u,v) ∈ E (重みが小さい辺から順番に)
if 頂点 u が属する集合≠ 頂点 v が属する集合
点v のみからなる集合を生成
then A ← A ∪ {(u,v)} // A に辺(u,v)を追加
u が属す集合と v が属す集合を統合
A ← Φ
return A // このとき A は最小全域木の辺を含む
(A:現在選んでいる辺からなる集合)
|E|log|E|
|V|
|E|回の集合操作
Primのアルゴリズム
Cut Propertyを直接的に使用 Dijkstraアルゴリズムと似ている
27
始点 s と最小全域木で連結済の頂点(S と書く)
グラフ G の全頂点を次の2つのグループに分ける
そうでない頂点(Q と書く)
• Cut Propertyを使って最小全域木の辺を1つずつ確定
• カットC(S,Q)で最小重みの辺を追加してSを拡大
(1) 初期状態 (2) 辺(s,b)追加 (3) 辺(b,c)追加
4
8
11 7
1 2
6
2
8 7
4 14
10
9
s
b
h
i
c
g
d
f
e
4
8
11 7
1 2
6
2
8 7
4 14
10
9
s
b
h
i
c
g
d
f
e
4
8
11 7
1 2
6
2
8 7
4 14
10
9
s
b
h
i
c
g
d
f
e
Primのアルゴリズム
28
s: 始点
d(v): Sに属する頂点とvを結ぶ辺の最小重み
p(v): 現段階の v のpredecessor
アルゴリズム
while Q ≠ Φ do
S ← Φ, Q ← V
Q の中からd(x) が最小の頂点 x を取り出す
for 各頂点 v ∈ Q について, d(v) ← ∞ // 初期化
S に x を追加
for 各 x の隣接点 y について,
if 𝑦 ∈ Q
then d(y) ← min{d(y), w(x,y)}, 𝑝(𝑦) = 𝑥
d(s) ← 0 // s:始点
28
S
Q
(ほとんどの辺を省略してあります)
S
Q
更新
更新 更新
x
x
y
y
y
:SとQのカット
短い方を残す
動作例
29
(1) 初期状態 (2) 辺(s,b)追加 (3) 辺(b,c)追加
4
8
11 7
1 2
6
2
8 7
4 14
10
9
s
b
h
i
c
g
d
f
e
4
8
11 7
1 2
6
2
8 7
4 14
10
9
s
b
h
i
c
g
d
f
e
4
8
11 7
1 2
6
2
8 7
4 14
10
9
s
b
h
i
c
g
d
f
e
(4) 辺(c,i)追加
4
8
11 7
1 2
6
2
8 7
4 14
10
9
s
b
h
i
c
g
d
f
e
(5) 辺(c,f)追加
4
8
11 7
1 2
6
2
8 7
4 14
10
9
s
b
h
i
c
g
d
f
e
(6) 辺(f,g)追加
4
8
11 7
1 2
6
2 4
14
10
9
s
b
h
i
c
g
d
f
e
8 7
(7) 辺(g,h)追加
4
8
11 7
1 2
6
2 4
14
10
9
s
b
h
i
c
g
d
f
8 7
(8) 辺(c,d)追加
e
4
8
11 7
1 2
6
2 4
14
10
9
s
b
h
i
c
g
d
f
8 7
e
4
8
11 7
1 2
6
2 4
14
10
s
b
h
i
c
g
d
f
8 7
e
9
(9) 辺(d,e)追加
Primのアルゴリズムの計算量
Dijkastraのアルゴリズムと同じ
30
while Q ≠ Φ do
S ← Φ, Q ← V
Q の中からd(x) が最小の頂点 x を取り出す
for 各頂点 v ∈ Q について, d(v) ← ∞ // 初期化
S に x を追加
for 各 x の隣接点 y について,
if 𝑦 ∈ Q
then d(y) ← min{d(y), w(x,y)}, 𝑝(𝑦) = 𝑥
d(s) ← 0 // s:出発点
計算時間: 𝑂(|𝑉|2 + |𝐸| ) → 𝑂( (|𝑉| + |𝐸|)log |𝑉 |) (ヒープ使用)
• 疎なグラフ 𝐸 = 𝑂 𝑉 ならヒープを使用した方が高速
• 密なグラフなら単純な実装でも遜色なし
|V|回
|Q|回
合計で|E|回
貪欲法が最適解となる問題の条件
最適化問題を
選択
選択の結果、残る部分問題
の組み合わせとみなす
1. 部分構造最適性
問題の最適解が部分問題の最適解を含む
2. 貪欲選択性
貪欲な選択を含む最適解が必ず存在する
貪欲な選択+残りの部分問題の最適解
⇒元の問題の最適解 31
cut
property
最小全域木問題の部分問題
最適性
選択後の部分問題=縮退グラフの最小全域木問題
縮退グラフ:選択された辺の両端をマージしたグラフ
自己ループ辺:除去
多重辺は重み最小の辺のみ残す
32
縮退グラフ
8 7
1 2
6
2
8 7
4 14
10
9 s b
h
i
c
g
d
f
e
(2) 辺(s,b)追加
4
8
11 7
1 2
6
2
8 7
4 14
10
9
s
b
h
i
c
g
d
f
e 11
4
ビンソート
マージソート、クイックソート: 計算量O(n log n)
ソーティングの計算量はO(n log n)を超えられないのか?
33
問題によっては越えることが可能!
整列対象のデータの値域が有限個に
限られている場合
問題例:
整列対象:S={𝑎1, 𝑎2,...., 𝑎𝑛} n個のデータの集合
値域: 0~9999までの整数
ビンソートのアイデア
要素の値ごとに用意された有限個の箱(bin)を用意
データをbinに振り分けるだけで要素毎の比較を直接行わないで整列
34
ビンソートの疑似コード
35
アルゴリズム
n:データ数、 m:取り得る値の種類数
a[ ]: n個のデータを格納する配列
for i= 1 to n
list[a[i]]にインデックスiをつなげる
for j= 0 to m-1 // 初期化
空の線形リスト list[j] を生成
i=0
for j= 0 to m-1
while(list[j]に要素がある){
b[i] = a[list[j]の要素]
list[j]を辿る
i= i+1;
}
for i= 1 to n a[i]= b[i]
ビンソートの動作例:
36
4 1 3 2 2 8 7 0 8 7
1 2 4 3 5 6 7 8 9 10
𝐴, - :0~8までの整数集合
list0
list1
list2
list3
list4
list5
list6
list7
list8
2
1
3
4
7
5
6
8
9
10
ビンソートの動作例:
37
4 1 3 2 2 8 7 0 8 7
1 2 4 3 5 6 7 8 9 10
𝐴, -
list0
list1
list2
list3
list4
list5
list6
list7
list8
2
1
3
4
7
5
6
8
9
10
0 1 2 2 3 4 7 7 8 8
1 2 4 3 5 6 7 8 9 10
B, -
同じ値を持つデータ間では元のデータ順序を維持
ビンソートの計算量
38
アルゴリズム
n:データ数、 m:取り得る値の種類数
a[ ]: n個のデータを格納する配列
for i= 1 to n
list[a[i]]にインデックスiをつなげる
for j= 0 to m-1 // 初期化
空の線形リスト list[j] を生成
i=0
for j= 0 to m-1
while(list[j]に要素がある){
b[i] = a[list[j]の要素]
list[j]を辿る
i= i+1;
}
for i= 1 to n a[i]= b[i]
O(m)
O(n) 全リストの要素数の合計=n
while文はn回しか実行されない
O(n)
全体では
𝑂(max *𝑛,𝑚+)
ビンソートの性質
ビンソートはmが大きくなると使えない
時間計算量大: 𝑂(max *𝑚, 𝑛+)
使用メモリ量大: m本のリスト
有効なアプリケーション 画像処理:画素の輝度値は0~255までの整数
39
実数データでも整数データに丸めて適用可能
同じビンに入ったデータ間で厳密に順位付け
実数用アルゴリズムを適用するデータ数を小さくできる
40
4.1 1.2 3.3 2.4 2.5 8.3 7.7 0.8 8.4 7.5
1 2 4 3 5 6 7 8 9 10
𝐴, - :0以上9未満の実数集合
整数の位に着目してビンソート
O(n)
0.8 1.2 2.4 2.5 3.3 4.1 7.7 7.5 8.4 8.3
1 2 4 3 5 6 7 8 9 10
B, -
同順位 同順位 同順位
0.8 1.2 2.4 2.5 3.3 4.1 7.5 7.7 8.3 8.4
1 2 4 3 5 6 7 8 9 10
B, -
同順位間でマージソート
• 要素数2の問題が3個
Radixソート
ビンソートはmが大きくなると使えない
時間計算量大: 𝑂(max *𝑚, 𝑛+)
使用メモリ量大: m本のリスト
符号なし32bitの整数 m=232
Radixソートの概要
1. 各データxをk個に分解
条件:上位部が下位部より順位付けを支配(dominate)
2. 下位側から順にビンソートを適用
41
32bit=8bit x 4 lsb(最下位) msb(最上位)
𝑥 = 𝑥,1-, 𝑥,2-, … 𝑥,𝑘-
𝑥,1- 𝑥,2- 𝑥,3- 𝑥,4-
Radixソートのアルゴリズム
for 𝑖 = 𝑘 𝑡𝑜 1
𝑥,𝑖-を対象としてビンソートにより集合Sを整列
(注意:x[i]の順序変更時は、x[i]以外も一緒に入れ替え)
ビンソートにおける𝑚: 𝑥,𝑖-の値の種類数
データ分割により削減成功
例題では28=256
計算量 𝑂(𝑘 max*𝑚, 𝑛+) ≅ 𝑂(𝑘𝑛)
理由:mが十分小さい
42
動作例: 16bitの整数のソート
43
k=2
a[1]=(3,2)
a[2]=(4,2)
a[3]=(4,1)
a[4]=(3,1)
a[1]=(4,1)
a[2]=(3,1)
a[3]=(3,2)
a[4]=(4,2)
a[1]=(3,1)
a[2]=(3,2)
a[3]=(4,1)
a[4]=(4,2)
a[1]= 770= 256*3 + 2
a[2]=1026= 256*4 + 2
a[3]=1025= 256*4 + 1
a[4]= 769= 256*3 + 1
a[1]=(3,2)
a[2]=(4,2)
a[3]=(4,1)
a[4]=(3,1)
(x[1],x[2])
x[2]に関するビンソート
a[1]=(4,1)
a[2]=(3,1)
a[3]=(3,2)
a[4]=(4,2)
x[1]に関するビンソート
Radixソートの動作原理 • ビンソート:同じ値を持つデータ間では元のデータ順序を維持
• 𝑥,𝑖-に関するビンソート後
• 𝑥,𝑖-の値が同じデータは𝑥 𝑖 + 1 の大小で順序が決まる
(バイナリ)ヒープ
44
16
14 10
8 7 9 3
2 4 1
1
2 3
4 5 6 7
8 9 10
16 14 10 8 7 9 3 2 4 1
1 2 4 3 5 6 7 8 9 10
添字𝑖が与えられたとき,
その親 𝑃𝐴𝑅𝐸𝑁𝑇 𝑖 = 𝑖 2
左の子 𝐿𝐸𝐹𝑇 𝑖 = 2𝑖
右の子 𝑅𝐼𝐺𝐻𝑇 𝑖 = 2𝑖 + 1
と簡単に計算可能
配列𝐴, -
部分順序付き木を配列に表現したもの
• 親子間に順序が定義される
木のノードは以下の2つによって定義される
• インデックス:木の中のノードの位置
• 値:実数
ヒープソート:アイデア • ヒープ: 最大値取り出しはO(log n)で出来る
• i番目に大きいデータの取り出しはO(i log n)で出来る
• 1~𝑖 − 1番目に大きいデータを取り出して除去した後に最大値取り出し実行
45
根(最大値)を 末尾と交換し, 取り出す
ソートしたい数値列
ヒープ構造を構築
ヒープソートの処理
46
(1) 与えられたデータをヒープ構造に変換
(2) 根に格納された最大値を取り出して除去
(3) ヒープ構造を維持
(4) (2)と(3)を繰り返す
𝐴, -
データをヒープ構造に変換
47
データを木構造に挿入する
4
1 3
2 16 9 10
14 8 7
2 3
4 5 6 7
8 9 10
4 1 3 2 16 9 10 14 8 7
1 2 4 3 5 6 7 8 9 10
1
データをヒープ構造に変換
48
ヒープ条件を満たす構造に変換
𝐴, -
4
1 3
2 16 9 10
14 8 7
2 3
4 5 6 7
8 9 10
4 1 3 2 16 9 10 14 8 7
1 2 4 3 5 6 7 8 9 10
1
7
16
14 10
8 9 3
2 4 1
2 3
4 5 6 7
8 9 10
16 14 10 4 7 9 3 2 8 1
1 2 4 3 5 6 7 8 9 10
1
𝐴, -
ヒープ構造への変換の疑似コード
49
BUILD-MAX-HEAP (A)
1 for i ← heapsize/2 to 1
2 do
子を持たない節点を
末尾から根までについて, 節点 i を根とする部分木が
max-ヒープ条件を維持するように変換
変換処理例
50
𝐴, -
4
1 3
2 16 9 10
14 8 7
2 3
4 5 6 7
8 9 10
4 1 3 2 16 9 10 14 8 7
1 2 4 3 5 6 7 8 9 10
1
16
変換処理例
51
𝐴, -
4
1 3
2 9 10
14 8 7
2 3
4 5 6 7
8 9 10
4 1 3 2 16 9 10 14 8 7
1 2 4 3 5 6 7 8 9 10
1
16
変換処理例
52
𝐴, -
4
1 3
14 9 10
2 8 7
2 3
4 5 6 7
8 9 10
4 1 3 14 16 9 10 2 8 7
1 2 4 3 5 6 7 8 9 10
1
16
変換処理例
53
𝐴, -
4
1 3
14 9 10
2 8 7
2 3
4 5 6 7
8 9 10
4 1 3 14 16 9 10 2 8 7
1 2 4 3 5 6 7 8 9 10
1
16
変換処理例
54
𝐴, -
4
1 10
14 9 3
2 8 7
2 3
4 5 6 7
8 9 10
4 1 10 14 16 9 3 2 8 7
1 2 4 3 5 6 7 8 9 10
1
最大値の取り出し
55
根をヒープから取り除く。配列上では
1. A[1]をA[heapsize]と交換
2. heapsizeを1減らす
7
16
14 10
8 9 3
2 4 1
2 3
4 5 6 7
8 9 10
16 14 10 8 7 9 3 2 4 1
1 2 4 3 5 6 7 8 9 10
1
𝐴, -
7
1
14 10
8 9 3
2 4 16
2 3
4 5 6 7
8 9
1 14 10 8 7 9 3 2 4 16
1 2 4 3 5 6 7 8 9
1
𝐴, -
56
7
1
14 10
8 9 3
2 4 16
2 3
4 5 6 7
8 9
1 14 10 8 7 9 3 2 4 16
1 2 4 3 5 6 7 8 9
1
𝐴, -
7
14
8 10
4 9 3
2 1 16
2 3
4 5 6 7
8 9
14 8 10 4 7 9 3 2 1 16
1 2 4 3 5 6 7 8 9
1
𝐴, -
ヒープ構造を維持
根ノードをdownheap(1)で下に降ろす。
ノード番号
2番目に
大きい値
2番目に大きい値の取り出し
57
7
14
8 10
4 9 3
2 1 16
2 3
4 5 6 7
8 9
14 8 10 4 7 9 3 2 1 16
1 2 4 3 5 6 7 8 9
1
𝐴, -
(4) (2)と(3)を繰り返す
7
10
8 9
4 1 3
2 14 16
2 3
4 5 6 7
8
10 8 9 4 7 1 3 2 14 16
1 2 4 3 5 6 7 8
1
𝐴, -
3番目に
大きい値
3番目に大きい値の取り出し
58
7
10
8 9
4 1 3
2 14 16
2 3
4 5 6 7
8
10 8 9 4 7 1 3 2 14 16
1 2 4 3 5 6 7 8
1
𝐴, -
(4) (2)と(3)を繰り返す
7
9
8 3
4 1 2
10 14 16
2 3
4 5 6 7
9 8 3 4 7 1 2 10 14 16
1 2 4 3 5 6 7
1
𝐴, -
4番目に
大きい値
ヒープソートの疑似コード
59
ヒープ条件を満たす
ヒープ構造を構築
HEAPSORT (A)
1 BUILD-MAX-HEAP(A)
2 for i ← heapsize to 2
3 do 値の交換 A[1] A[i]
4 heapsize← heapsize – 1
5 downheap(1)
最大値を取り出して、heapsize
を減らす
ヒープ再構性:
• 根にあるノードをヒープ条件を
満たすまで下に下げる
}
ヒープソートの計算量
60
HEAPSORT (A)
1 BUILD-MAX-HEAP(A)
2 for i ← heapsize to 2
3 do 値の交換 A[1] A[i]
4 heapsize← heapsize – 1
5 downheap(1)
O (n )
O ( log n )
n-1回実行
BUILD-MAX-HEAPの呼び出しにO(n)時間
downheap(1): O(log n)時間かかり,n-1回実行
HEAPSORT手続きは O(n log n)時間を要する