スライド タイトルなし

データ構造とアルゴリズム
第10回
整列
~ バブルソート,挿入ソート,選択ソート~
1
解答(1):半順序木(ヒープ)
2, 7, 4, 9, 7, 4, 12, 10, 13, 11
子が2つとも親より
小さいときは,小さ
い方の子と交換
2
4
7
9
4
7
10 13 11
4
7
12
9
4
7
11
12
10 13
DeleteMinした結果
2
解答(2) 2分探索木
左部分木<根<右部分木
3
1
2分探索木を
通りがけ順に
なぞるとデータが
昇順に並ぶ
3
2
1
2
1
3
2
行きがけ順
1 3 2
3 1 2
2 1 3
通りがけ順
1 2 3
1 2 3
1 2 3
帰りがけ順
2 3 1
2 1 3
1 3 2
3
補足:ヒープとヒープメモリ




半順序木:節点vの優先度がvの子の優先度より必ず小さいか
等しい
heap [英語] つみかさねた山のようなもの,かたまり
アルゴリズムの分野で 「ヒープ」という場合は,半順序木また
はそれを配列で表現したものを指す
計算機の構造の話ででてくる「ヒープメモリ」or「ヒープ領域」と
は意味が異なるので混同しないこと
2
7
9
静的メモリ領域
4
7
4
12
スタック領域
10 13 11
ヒープ領域
4
正解者の割合
100.0
90.0
80.0
70.0
60.0
50.0
40.0
30.0
20.0
10.0
0.0
査
探
索
木
の
走
残
り
を
記
載
果
in
の
結
1 De
問
題
2 2分
問
問
1 数
列
が
le
te
M
あ
ら
わ
す
木
正解者の割合
5
本日の内容

整列アルゴリズム

単純な整列アルゴリズム



バブルソート
挿入ソート
選択ソート
6
整列(ソーティング,sorting)


レコードの集まりを,キーの値の大小関係に従って
昇順(または降順)に並べかえる操作
ソートの対象は,複数の欄からなるレコード
氏名と身長欄か
ら成るレコード.
Cでは,構造体
を用いて記述
青木
小田
金子
佐藤
177
158
170
174
渡辺
170
身長をキーとして
降順にソート
青木
佐藤
金子
渡辺
177
174
170
170
小田
158
同じキーをもつレコードが
複数ある時は連続して並ぶ
7
昇順、降順

昇順(ascending order)



数値の場合、小さいものから大きいものへ
1,3,5,8,10
文字列の場合、辞書式順序
a, aa, abc, g, zz, zzzz
降順(descending order)


数値の場合、大きいものから小さいものへ
10,8,5,3,1
文字列の場合、辞書式順序の逆
zzzz, zz, g, abc, aa, a
8
整列アルゴリズムの要件

計算量 (時間的,空間的)

内部ソート / 外部ソート


ランダムアクセス可能なメモリの利用を前提とする方式か
否か
安定 / 不安定

キーの値が同じデータを整列した場合に整列前の位置関
係が維持されるか
10, 3, 5, 3, 1 ⇒ 1, 3, 3, 5, 10 安定
10, 3, 5, 3, 1 ⇒ 1, 3, 3, 5, 10 不安定
9
2
O(n )とO(n

log n)の比較
n が大きいとき,O(n2)とO(n log n)の差は顕著
例)

n = 32 = 25のとき
n2 = 210 = 1024
6.4倍
n log2 n = 32×log2 25 = 32×5 = 160
10
 n = 1024 = 2 のとき
100倍
n2 = 220 = 1048576 ≒ 100万
n log2 n = 1024×log2 210 = 1024×10 = 10240 ≒ 1万
10
内部ソートと外部ソート
主記憶
(メモリ)
ランダム
1
2
5
6
7
2
5
1
6
7
外部記憶
(磁気テープなど)
シーケンシャル
主記憶
(メモリ)
ランダム
整列したい
データ
2
5
1
6
7
主記憶にコピー
入りきらない
外部記憶
(磁気テープなど)
シーケンシャル
整列したい
データ
2
5
1
6
7
10
40
3
4
35
11
安定な整列

同じキーをもつレコードが2つ以上ある場合に,整列
前の位置関係が整列後も保たれているアルゴリズム
を安定である(stable)という
5A 7 4 8 5B 3 2
安定なアルゴリズムによる整列結果
不安定なアルゴリズムによる整列結果
2 3 4 5A 5B 7 8
2 3 5B 5A 7 8
12
整列アルゴリズムの分類
名称
計算量
内部/
外部
安定/
不安定
バブルソート
O(n2)
内部
安定
挿入ソート
O(n2)
内部
安定
選択ソート
O(n2)
内部
不安定
クイックソート O(n log n) 内部
備考
不安定 最悪O(n2)
ヒープソート
O(n log n) 内部
不安定
マージソート
O(n log n) 外部
安定
ビンソート
O(n)
内部
安定
データに制限有
基数ソート
O(mn)
内部
安定
データに制限有
13
バブルソート(bubble sort)
[1]
[2]
[3]
[4]
[5]
7
3
5
9
6
4
[n-1]
8
9
2
a [0]

配列の後ろから先頭に向かって
スキャンし,隣り合う2つの要素の
大小関係が逆であったら入れか
える
2
2 8
9
14
バブルソートの疑似コード
整数を昇順に並べる場合
void bubble_sort(int a[], int n)
{
int i, j;
for (i = 0; i < n - 1; i++){
for (j = n - 1; j > i; j--){
if(a[j] < a[j-1])
a[j]とa[j-1]を交換;
}
}
}
i → a [0]
[1]
[2]
[3]
[4]
[5]
j → [n-1]
15
バブルソートの実行例
a[0] a[1]
整列前
i=0のあと
i=1のあと
i=2のあと
i=3のあと
i=4のあと
i=5のあと
i=6のあと
i=7のあと
a[8]
9
3
2
1
4
7
5
5 8
1
1
1
1
1
1
2
2
2
2
2
2
3
3
3
3
3
3
9
4
4
4
4
4
4
9
5
5
5
5
5
5
9
5
5
5
5
5
5
9
7
7
7
7
7
7
9
8
8
8
8
8
8
9
整列済 ←
16
バブルソートの実行例
a[0] a[1]
整列前
i=0のあと
i=1のあと
i=2のあと
i=3のあと
i=4のあと
i=5のあと
i=6のあと
i=7のあと
9
1
1
1
1
1
1
1
1
3
9
2
2
2
2
2
2
2
a[8]
2
3
9
3
3
3
3
3
3
1
2
3
9
4
4
4
4
4
4
4
4
4
9
5
5
5
5
7
5
5
5
5
9
5
5
5
5
7
5
5
5
5
9
7
7
5
5
7
7
7
7
7
9
8
8
8
8
8
8
8
8
8
9
整列済 ←
17
バブルソートの実行例
a[0] a[1]
整列前
i=0のあと
i=1のあと
i=2のあと
i=3のあと
i=4のあと
i=5のあと
i=6のあと
i=7のあと
9
1
1
1
1
1
1
1
1
3
9
2
2
2
2
2
2
2
a[8]
2
3
9
3
3
3
3
3
3
1
2
3
9
4
4
4
4
4
4
4
4
4
9
5
5
5
5
7
5
5
5
5
9
5
5
5
5
7
5
5
5
5
9
7
7
5
5
7
7
7
7
7
9
8
8
8
8
8
8
8
8
8
9
整列済 ←
安定なソート
18
問題1

次のデータをバブルソートで昇順に並べ替える経
過を示しなさい。
a[5] = {9,3,4,1,4};
19
i
j
初期状態
0
4
0
0
3
2
0
1
1
1
4
3
1
2
2
2
4
3
3
4
a[0]
9
a[1]
3
a[2]
4
a[3]
1
a[4]
4
20
i
j
初期状態
0
4
0
0
0
1
1
1
2
2
3
3
2
1
4
3
2
4
3
4
a[0]
9
9
a[1]
3
3
a[2]
4
4
a[3]
1
1
a[4]
4
4
9
9
1
1
1
1
1
1
1
3
1
9
9
9
3
3
3
3
1
3
3
3
3
9
9
4
4
4
4
4
4
4
4
4
9
4
4
4
4
4
4
4
4
4
9
21
バブルソートの計算量
i=0
a [0]
i=1
i のループ
n-1回
i=n-2
[1]
[2]
[3]
j:
n-1回
j:
n-2回
[n-1]
j:
1回
全体
O(n2)
n 1
比較:
 (n  k )  {n(n  1)}/ 2 ⇒ O(n2)
k 1
交換:(a[j]<a[j-1])の個数: 逆順の場合、比較の回数分
交換も起こる ⇒ O(n2)
22
挿入ソート(insertion sort)


0〜(i-1)番目まではすでにソート済
i番目の要素を0〜iの間の適切な位置に挿入する
ソート済
a
[0]
[1]
3
5
[i-1] [i]
8
10 11
[n-1]
7
23
挿入ソートの疑似コード
void insertion_sort(int a[], int n)
{
int i, j;
for (i = 1;i < n; i++){
j = i;
while (j >= 1 && a[j] < a[j-1]){
a[j]とa[j-1]を交換;
j--;
}
}
j >= 1を満たさな
いのでwhileルー
プを抜ける
a[0]
j → i → [1]
[2]
[3]
[4]
2
3
1
4
}
[n-1]
24
挿入ソートの疑似コード
void insertion_sort(int a[], int n)
{
int i, j;
for (i = 1;i < n; i++){
j = i;
while (j >= 1 && a[j] < a[j-1]){
a[j]とa[j-1]を交換;
j--;
}
}
j >= 1を満たさな
いのでwhileルー
プを抜ける
a[0]
j→
[1]
i → [2]
[3]
[4]
1
3
2
2
1
3
4
}
[n-1]
25
挿入ソートの疑似コード
void insertion_sort(int a[], int n)
{
int i, j;
a[0]
[1]
[2]
j → i → [3]
[4]
1
3
2
3
1
2
1
3
4
for (i = 1;i < n; i++){
j = i;
while (j >= 1 && a[j] < a[j-1]){
a[j]とa[j-1]を交換;
jは i ~ 1までの全て
j--;
について繰りかえし調
べるのではなく,適切な
}
挿入位置で止まる
}
}
[n-1]
26
番兵(Sentinel)


配列の範囲を超えないよう見張るために使用
決してa[j]とa[j-1]の交換が起きないような値
を入れておくことで,コードを簡略化できる
a
[0]
i
↓
[i-1] [i]
[1]
-∞ 3
5
8
10
[n-1] [n]
1
← j
番兵
27
挿入ソートの疑似コード2
a [0] -∞
番兵を使う場合
void insertion_sort(int a[], int n)
{
int i, j;
a[0] = -∞;
for (i = 2;i <= n; i++){
j = i;
while (a[j] < a[j-1]){
a[j]とa[j-1]を交換;
j--;
}
}
}
j → [1]
i → [2]
[3]
[4]
2
3
2
3
1
4
[5]
必ずa[1]>a[0]
になり,ループを
脱出
[n]
28
挿入ソートの実行例
整列前
1回実行後
2回実行後
iの
ループ 3回実行後
4回実行後
5回実行後
6回実行後
7回実行後
8回実行後
4
5
5
7
8
1 2
9
3
4
4
1
1
1
1
5
5
4
2
2
2
5
5
5
4
4
3
7
7
5
5
5
4
8
8
7
5
5
5
1
1
8
7
7
5
9
9
9
9
9
8
3
3
3
3
3
9
2
2
2
8
8
7
整列済 ←
29
挿入ソートの実行例
整列前
1回実行後
2回実行後
iの
ループ 3回実行後
4回実行後
5回実行後
6回実行後
7回実行後
8回実行後
4
4
4
4
4
1
1
1
1
5
5
5
5
5
4
2
2
2
5
5
5
5
5
5
4
4
3
7
7
7
7
7
5
5
5
4
8
8
8
8
8
7
5
5
5
1
1
1
1
1
8
7
7
5
2
2
2
2
2
2
8
8
7
9
9
9
9
9
9
9
9
8
3
3
3
3
3
3
3
3
9
整列済 ←
安定なソート
30
問題2

次のデータを挿入ソートで昇順に並べ替える経過
を示しなさい。
a[5] = {9,3,4,1,4};
31
i
j
初期状態
1
1
2
3
2
3
3
3
4
2
1
4
a[0]
a[1]
a[2]
a[3]
a[4]
9
3
4
1
4
32
i
j
初期状態
1
1
2
3
3
3
4
2
3
2
1
4
a[0]
9
3
a[1]
3
9
a[2]
4
4
a[3]
1
1
a[4]
4
4
3
3
3
1
1
4
4
1
3
3
9
1
4
4
4
1
9
9
9
4
4
4
4
4
9
33
挿入ソートの計算量
i のループ n-1回
i=2
i=3
i=4
i=n
a [0]
[1]
[2]
[3]
[n]
j
j のループは
適切な挿入位置
で止まる
内側(j)のループ回数
Min:0回
Max:i-1回
平均:約(i-1)/2回
n
比較:
全体
O(n2)
 (i 1) / 2  {n(n  1)}/ 4 ⇒O(n2)
i 2
交換:(a[j]<a[j-1])の個数≒ c・n
⇒ O(n)
34
選択ソート(selection sort)

整列されていない部分から最小要素を選び,先頭と
入れかえる処理を繰り返す
i (着目位置)
a
[0]
[1]
1
3
未ソート
[n-1]
5
9
10
入れかえ
7
20 17 18
整列されていない部分の最小値
35
選択ソートの疑似コード
void selection_sort(int a[], int n)
{
int i, j, lowest, lowkey;
for (i = 0;i < n - 1; i++){
lowest = i;
lowkey = a[i];
for (j = i + 1; j < n; j++){
if (a[j] < lowkey){
lowest = j;
lowkey = a[j];
}
}
a[i]とa[lowest]を交換;
}
}
a [0] 1
[1]
i → [2]
[3]
[4]
lowest→ [5]
2
9
3
7
3
9
j → [n-1]
36
選択ソートの実行例
整列前
1回実行後
2回実行後
iの
ループ 3回実行後
4回実行後
5回実行後
6回実行後
7回実行後
8回実行後
9
3
4
9
7
2 5
8
1
1
1
1
1
1
1
2
2
2
2
2
2
3
3
3
3
3
3
9
4
4
4
4
4
7
7
5
5
5
5
4
9
9
7
7
7
8
8
8
8
9
9
9
9
9
9
9
9
5
5
7
9
8
8
整列済 ←
37
選択ソートの実行例
整列前
1回実行後
2回実行後
iの
ループ 3回実行後
4回実行後
5回実行後
6回実行後
7回実行後
8回実行後
9
1
1
1
1
1
1
1
1
3
3
2
2
2
2
2
2
2
4
4
4
3
3
3
3
3
3
9
9
9
9
4
4
4
4
4
7
7
7
7
7
5
5
5
5
2
2
3
4
9
9
7
7
7
5
5
5
5
5
7
9
8
8
8
8
8
8
8
8
8
9
9
1
9
9
9
9
9
9
9
9
整列済 ←
不安定なソート
38
問題3

次のデータを選択ソートで昇順に並べ替える経過
を示しなさい。
a[5] = {9,3,2,1,4,8,7};
39
i
初期状態
a[0]
9
a[1]
3
a[2]
2
a[3]
1
a[4]
4
a[5]
8
a[6]
7
0
1
2
3
4
5
40
i
初期状態
0
a[0]
9
1
a[1]
3
3
a[2]
2
2
a[3]
1
9
a[4]
4
4
a[5]
8
8
a[6]
7
7
1
2
3
4
5
1
1
1
1
1
2
2
2
2
2
3
3
3
3
3
9
9
4
4
4
4
4
9
7
7
8
8
8
8
8
7
7
7
9
9
41
選択ソートの計算量
i のループ
n-1回
i=0
i=1
i=2
i=n-2
a [0]
[1]
[2]
[3]
j
j:
n-1回
j:
n-2回
j:
1回
[n-1]
n 1
比較:
 (n  k )  {n(n  1)}/ 2 ⇒
k 1
O(n2)
交換:各iの最後に1回→全体でn-1回 ⇒O(n)
全体
O(n2)
42
まとめ
全体の計算量
比較
交換
バブルソート
O(n2)
n(n-1)/2 回
(a[j]<a[j-1])の
個数回
挿入ソート
O(n2)
約n(n-1)/4 回
(a[j]<a[j-1])の
個数回
選択ソート
O(n2)
n(n-1)/2 回
n-1回
挿入ソートは,整列済みのデータに
新しいデータを追加してから並べかえるときなど,
ほぼ整列済みのデータのソートが得意
43
次回の予定

バケットソート

基数ソート

ヒープソート
44
本日の課題(1)


下記の疑似コードにしたがってソートする時,外側の
forループの各 i での配列aの内容を記せ.
配列の要素数nは6とし,配列aの初期値は先頭から
順に{ 8, 4, 3, 9, 1, 5 }であるものとする.
void sort(int a[], int n)
{
int i, j;
for (i = 0; i < n - 1; i++)
for (j = n - 1; j > i; j--)
if(a[j] > a[j-1])
a[j]とa[j-1]を交換;
}
45
付録:C言語の豆知識(1)
三項演算子“? :”
x = (a > b)? a : b;
()内の条件が真なら:の左側
()内の条件が偽なら:の右側
の値が返される.
a=5, b=3 なら,条件が真なのでxに5が入る.

#define MAX(a, b) (a > b)? (a) : (b)
46