整列のアルゴリズム
このノートの問いがそのまま復習カードになり、忘れかけたころに出題されます。
0. どういうまとまりか
データを大きさの順に並べ替えるのが整列(ソート)です。小さい順を昇順、大きい順を降順といいます。
どのやり方も「比べる」と「動かす(交換する)」の組み合わせで、何を選んでどこへ動かすかが違います。
| 名前 | 1 回の手順 | 比較の回数(データ n 個) |
|---|---|---|
| 選択ソート | 未整列の部分から最小値を選び、その先頭と交換する | 常に 回 |
| バブルソート(交換ソート) | 隣どうしを比べ、順が逆なら交換する | 常に 回(途中で打ち切る工夫をしない場合) |
| 挿入ソート | 次の 1 つを、整列済みの部分の正しい位置に挿し込む | 最大 回。ほぼ整列済みなら少ない |
| クイックソート | 基準値(ピボット)より小さいものと大きいものに分け、それぞれを同じように整列 | 平均で に比例 |
分かれ目は次の 3 つ。
- 選択ソートは「最小値を選んで先頭へ」、バブルソートは「隣どうしを比べて交換」。
- 選択・バブル・挿入の比較の回数は、n の 2 乗に比例して増える。
- 同じ値どうしの並び順が、整列の前後で変わらないものを安定なソートという。
1. 選択ソート
根拠: 学習指導要領 情報Ⅰ-(3)-ア-(イ)
選択ソートは、まだ整列していない部分から最小値を探し、その部分の先頭と入れ替えます。
1 回ごとに先頭から 1 つずつ確定していきます。
選択ソートは、1 回の手順で何をするか?
未整列の部分から最小値を探し、その部分の先頭の要素と交換する
これを繰り返すと、先頭から小さい順に確定していく。
n 個のデータを選択ソートするとき、交換の回数は最大で何回か?
n−1 回
1 回の手順で交換は 1 回だけ。比較は 回と多いが、交換は少ない。
2. バブルソート
根拠: 学習指導要領 情報Ⅰ-(3)-ア-(イ)
バブルソート(交換ソート)は、隣り合う 2 つを比べ、順が逆なら交換する、を端から端まで繰り返します。
1 回通すごとに、いちばん大きい値が末尾へ移ります(泡が浮かぶように動くのが名前の由来)。
バブルソートは、どうやってデータを並べ替えるか?
隣り合う 2 つの要素を比べ、順が逆なら交換する、を繰り返す
昇順なら、1 回端まで通すごとに最大値が末尾に確定する。交換ソートともいう。
昇順のバブルソートで、先頭から末尾まで 1 回通すと、何が確定するか?
最大値が末尾に確定する
次の回は、確定した末尾を除いた範囲で同じことをする。
バブルソートの交換の回数は、何で決まるか?
順が逆になっている 2 つの組の数
1 回の交換で、逆順の組がちょうど 1 つ減るため。すでに整列済みなら交換は 0 回。
3. 挿入ソートとクイックソート
根拠: 学習指導要領 情報Ⅰ-(3)-ア-(イ)
挿入ソートは、手持ちのトランプを並べるときのように、1 枚ずつ正しい位置に差し込むやり方です。
クイックソートは、基準値で「小さいグループ」と「大きいグループ」に分け、それぞれを同じ方法で整列します。
挿入ソートは、1 回の手順で何をするか?
整列済みの部分の正しい位置に、次の要素を挿し込む
挿し込む位置より大きい要素を 1 つずつ後ろへずらしてから入れる。
挿入ソートが特に速く終わるのは、データがどんな並びのときか?
ほぼ整列済みのとき
挿し込む位置を探す比較がすぐ終わるため。すでに整列済みなら、比較は n−1 回で済む。
クイックソートは、どうやってデータを並べ替えるか?
基準値(ピボット)を 1 つ選び、それより小さいものと大きいものに分け、分けたそれぞれを同じ方法で整列する
平均的には非常に速い(比較の回数が に比例)。基準値の選び方が悪いと遅くなる。
4. 比較の回数と安定なソート
根拠: 学習指導要領 情報Ⅰ-(3)-ア-(イ)
選択ソートでは、1 回目に n−1 回、2 回目に n−2 回……と比べるので、比較は全部で
回、すなわち 回になります。
n 個のデータを選択ソートするとき、比較の回数は全部で何回か?
回
の和。データの並び方によらず同じ。
安定なソートとは何か?
同じ値を持つ要素どうしの並び順が、整列の前後で変わらない整列の方法
例えば、先に名前順に並べた名簿を点数で整列し直しても、同じ点数の人は名前順のまま残る。
バブルソート・挿入ソート・選択ソートのうち、ふつうの作り方で安定でないものはどれか?
選択ソート
離れた位置の要素と交換するため、同じ値の順番が入れ替わることがある。バブルソートと挿入ソートは隣どうしの比較・移動なので安定。
練習問題
問 1 次のバブルソートで、外側の繰り返しの 1 回目(i が 0)が終わったときの a と、最後に表示される内容を答えよ。
a = [5, 3, 8, 1]
swaps = 0
for i in range(len(a) - 1):
for j in range(len(a) - 1 - i):
if a[j] > a[j + 1]:
a[j], a[j + 1] = a[j + 1], a[j]
swaps = swaps + 1
print(a, swaps)
i が 0)が終わったときの a と、最後に表示される内容を答えよ。a = [5, 3, 8, 1]
swaps = 0
for i in range(len(a) - 1):
for j in range(len(a) - 1 - i):
if a[j] > a[j + 1]:
a[j], a[j + 1] = a[j + 1], a[j]
swaps = swaps + 1
print(a, swaps)
1 回目の後は [3, 5, 1, 8]。表示は「[1, 3, 5, 8] 4」
1 回目: 5 と 3 を交換、5 と 8 はそのまま、8 と 1 を交換して [3, 5, 1, 8]。最大の 8 が末尾に確定する。
2 回目で [3, 1, 5, 8]、3 回目で [1, 3, 5, 8]。
交換の回数は、順が逆の組(5 と 3、5 と 1、3 と 1、8 と 1)の数と同じ 4 回。
問 2 次の選択ソートで、外側の繰り返しが 2 回(i が 0 と 1)終わったときの a を答えよ。
a = [29, 10, 14, 37, 13]
for i in range(len(a) - 1):
m = i
for j in range(i + 1, len(a)):
if a[j] < a[m]:
m = j
a[i], a[m] = a[m], a[i]
i が 0 と 1)終わったときの a を答えよ。a = [29, 10, 14, 37, 13]
for i in range(len(a) - 1):
m = i
for j in range(i + 1, len(a)):
if a[j] < a[m]:
m = j
a[i], a[m] = a[m], a[i]
[10, 13, 14, 37, 29]
i が 0: 全体の最小値 10(添字 1)を先頭の 29 と交換して [10, 29, 14, 37, 13]。i が 1: 添字 1 から後ろの最小値 13(添字 4)を 29 と交換して [10, 13, 14, 37, 29]。
m は最小値の添字を覚えておく変数で、交換は 1 回の手順につき 1 回だけ。
問 3 次の挿入ソートで、i が 2 の回が終わったときの a を答えよ。
a = [7, 3, 5, 2]
for i in range(1, len(a)):
x = a[i]
j = i - 1
while j >= 0 and a[j] > x:
a[j + 1] = a[j]
j = j - 1
a[j + 1] = x
i が 2 の回が終わったときの a を答えよ。a = [7, 3, 5, 2]
for i in range(1, len(a)):
x = a[i]
j = i - 1
while j >= 0 and a[j] > x:
a[j + 1] = a[j]
j = j - 1
a[j + 1] = x
[3, 5, 7, 2]
i が 1: 3 を取り出し、7 を後ろへずらして先頭に入れ [3, 7, 5, 2]。i が 2: 5 を取り出し、7 だけを後ろへずらす(3 は 5 より小さいので止まる)。7 の元の位置に 5 を入れ [3, 5, 7, 2]。
最後の i が 3 で 2 が先頭に入り、[2, 3, 5, 7] になる。