ソート1:バブルソート、選択ソート、挿入ソート
選択ソートは、10個の値のリストならどんなものでも、はじめがばらばらでもすでに整列していても、ちょうど45回比較します。
順番に並べる
ソート(整列)とは、リストの値が小さいものから大きいものへ(あるいは名前順、日付順、値段順など、比べられるどんな順でも)並ぶように並べかえることです。コンピューターがする仕事の中でも特によくあるものです。スマートフォンの連絡先、関連の高い順に並んだ検索結果、日付順に並べたスプレッドシートの列などがそうです。ソートは、ほかの仕事も楽にします。前のユニットで見たように、整列したリストは二分探索で探せますし、整列したリストでは重複した値が隣どうしに並びます。
このユニットでは3つの簡単な方法を扱います。どれも2つの値を一度に比べ、同じリストの中で値を動かして進めます。短く書けて追いやすいのですが、3つとも長いリストでは急に遅くなります。なぜ遅くなるのかを見ておくことが、次のユニットのもっと速い方法へのいちばんの準備になります。ここではずっと、比較(「この値はあの値より大きいか?」と問うこと)と交換(2つの値を入れかえること)の2つを数えます。
バブルソート:順番が逆の隣どうしを交換する
バブルソートは、リストにそって隣どうしの組を順に比べていきます。左のほうが大きければ、2つを交換します。1回の走査が終わると、最大の値が泡が浮かぶように一歩ずつ右端まで運ばれ、もう動かす必要はなくなります。次の走査は1つ手前で止められます。よくある改良は、交換が1回もない走査に気づくことです。それはすべてがもう順に並んでいるという意味なので、ソートを早めに終えられます。
リスト [5, 1, 4, 2, 8] で追ってみましょう。1回目の走査では、5と1(交換)、5と4(交換)、5と2(交換)、5と8(そのまま)を比べます。リストは [1, 4, 2, 5, 8] になり、8は正しい位置に来ました。2回目の走査では1と4、4と2(交換)、4と5を比べて、[1, 2, 4, 5, 8] になります。3回目の走査では1と2、次に2と4を比べ、交換がないので止まります。合計は比較 4 + 3 + 2 = 9 回、交換4回です。
function bubbleSort(a) {
for (let pass = 0; pass < a.length - 1; pass++) {
let swapped = false;
for (let j = 0; j < a.length - 1 - pass; j++) {
if (a[j] > a[j + 1]) {
[a[j], a[j + 1]] = [a[j + 1], a[j]]; // 交換
swapped = true;
}
}
if (!swapped) break; // 整列済み
}
return a;
}選択ソート:最小のものを見つけて次に置く
選択ソートは、多くの人が手持ちのトランプを並べるやり方と同じです。リスト全体から最小の値を探し、それを先頭の位置と交換します。次に残りから最小の値を探して2番目の位置と交換し、これを続けます。[5, 1, 4, 2, 8] では、1回目の探索で1を見つけて5と交換し、2回目で2を見つけて5と交換します。最後の2回の探索では、4と5がもう正しい位置にあるとわかります。交換は2回だけですが、探索での比較は 4 + 3 + 2 + 1 = 10 回あります。
選択ソートは途中で止まりません。すでに整列したリストでも、最小の値を手にしていると確かめるために、残りの値をすべて調べなければなりません。n個の値では、比較の回数はいつも (n − 1) + (n − 2) + … + 1 = n(n − 1)/2 になります。10個なら45回、100個なら4,950回、1,000個なら499,500回です。強みは交換の少なさで、多くてもn − 1回です。値を動かすのに手間がかかるときには、これが効いてきます。
挿入ソート:新しい値を正しい位置へすべりこませる
挿入ソートは、リストの左側を整列した状態に保ち、それを1つずつ広げていきます。次の値を取り、隣の値が大きくなくなるまで、隣と交換しながら左へ動かします。するとその値は、整列した値の中で正しい位置に入ります。すでにほぼ整列したリストでは、新しい値はそれぞれ1〜2歩しか動かないので、挿入ソートはとても速くなります。[5, 1, 4, 2, 8] では、比較7回、交換4回です。
ドラッグで回転、スクロールまたはピンチで拡大・縮小。
交換を数える:転倒
バブルソートと挿入ソートの交換の回数を予想する、うまい方法があります。転倒、つまりおたがいの順番が逆になっている値の組を数えるのです。[5, 1, 4, 2, 8] の転倒は (5, 1)、(5, 4)、(5, 2)、(4, 2) の全部で4つです。順番が逆の隣どうしを1回交換すると、転倒がちょうど1つ直り、新しい転倒はできません。だからどちらの方法も、交換はちょうど4回です。n個の値の逆順のリストでは、すべての組が転倒していて、転倒は n(n − 1)/2 個です。これが最悪の場合です。
| 方法 | 例 | 整列済み(5個) | 逆順(4個) |
|---|---|---|---|
| バブルソート | 9 / 4 | 4 / 0 | 6 / 6 |
| 選択ソート | 10 / 2 | 10 / 0 | 6 / 2 |
| 挿入ソート | 7 / 4 | 4 / 0 | 6 / 6 |
各マスは 比較 / 交換 の回数です。例のリストは [5, 1, 4, 2, 8] です。ここでのバブルソートは、交換のない走査の後で止まる版です。
3つの方法には同じ弱点があります。最悪の場合、どれもほぼすべての値の組を比べ、比較は約 n²/2 回になります。リストを2倍にすると仕事量は4倍になります。リストが10倍なら仕事量は100倍です。数十個の値ならほとんど問題になりませんが、100万個ではお手上げです。次のユニットでは、ずっとうまいやり方を見ていきます。
| 比較 | ある値が別の値より大きいかどうかを問うこと |
| 交換 | 2つの値の位置を入れかえること |
| 走査(パス) | リストにそって1回通ること |
| バブルソート | 順番が逆の隣どうしを交換する。走査のたびに最大の値が端へ上がっていく |
| 選択ソート | 残りの中の最小の値を見つけ、次の位置と交換する |
| 挿入ソート | 新しい値を、整列した部分の中へ左にすべりこませる |
| 転倒 | おたがいの順番が逆になっている値の組 |
| n(n − 1)/2 | n個の値からできる組の数 |
- 10個の値のリストで、選択ソートは何回比較しますか?
- [3, 1, 2] の転倒はいくつありますか?
- [4, 3, 2, 1] で挿入ソートは何回交換しますか?
- バブルソートの1回目の走査の後、確実に最終的な位置にある値はどれですか?
- 最小の値(先頭)
- 最大の値(末尾)
- 真ん中の値
- まだどれもない
- [5, 1, 4, 2, 8] で交換がいちばん少ないのはどの方法ですか?
- バブルソート
- 選択ソート
- 挿入ソート
- リストはすでに整列しています。それでも n(n − 1)/2 回比較するのはどの方法ですか?
- 途中で止まるバブルソート
- 選択ソート
- 挿入ソート
- [5, 1, 4, 2, 8] で、(途中で止まる)バブルソートは何回比較しますか?
- 1,000個の値のリストが2,000個になりました。挿入ソートの最悪の場合の仕事量は、おおよそどう変わりますか?
- 2倍になる
- 約4倍になる
- 1,000ステップ増える
- 変わらない
- ほぼ整列済みのリストにいちばん向いているのはどの方法ですか?
- 挿入ソート
- 選択ソート
- どれでも同じ
- 100個の値から組はいくつ作れますか(最悪の場合の比較回数 n(n − 1)/2)?
- リスト [3, 1, 2] が挿入ソートの途中でたどる並びを順に並べましょう。
- バブルソートは隣どうしを交換し、走査のたびに最大の値を末尾へ運びます。
- 選択ソートの比較はいつも n(n − 1)/2 回で、交換は多くても n − 1 回です。
- 挿入ソートはほぼ整列したリストで速くなります。
- バブルソートと挿入ソートは、転倒1つにつき交換を1回行います。
- 3つとも、最悪の場合は約 n² ステップかかります。
このコースの出典 (11)
- MIT OpenCourseWare 6.006 Introduction to Algorithms, Spring 2020 (Demaine, Ku, Solomon)
- lecture notes 1 Introduction, 3 Sorting, 9 Breadth-First Search, 10 Depth-First Search (ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/pages/lecture-notes) and Fall 2011 lecture 13 BFS notes (ocw.mit.edu/courses/6-006-introduction-to-algorithms-fall-2011)
- Cormen, Leiserson, Rivest, Stein, Introduction to Algorithms (MIT Press)
- with the CLRS-based Khan Academy algorithms unit by Thomas Cormen and Devin Balkcom of Dartmouth (khanacademy.org/computing/computer-science/algorithms: binary search, selection sort analysis, merge sort, quicksort overview and analysis)
- MacTutor History of Mathematics, Al-Khwarizmi (mathshistory.st-andrews.ac.uk/Biographies/Al-Khwarizmi: word algorithm from the Latin title Algoritmi de numero Indorum)
- D. E. Joyce, Euclid's Elements Book VII Propositions 1 and 2 (mathcs.clarku.edu/~djoyce/elements/bookVII)
- Wolfram MathWorld, Merge Sort (mathworld.wolfram.com/MergeSort.html: proposed by John von Neumann in 1945, after Knuth 1998 p. 159)
- Stanford CS "Tony Hoare: Quicksort" (cs.stanford.edu/people/eroberts/courses/soco/projects/2008-09/tony-hoare/quicksort.html: devised while a student at Moscow State University for Russian-English machine translation with a tape dictionary, programmed in Algol 60 and published 1961; the year 1959 from the Wikipedia Quicksort article and its cited sources)
- Bodleian Libraries, Ada Lovelace (blogs.bodleian.ox.ac.uk/adalovelace: 1843 paper, Note G Bernoulli numbers)
- Fourmilab text of Menabrea's Sketch with Lovelace's notes (fourmilab.ch/babbage/sketch.html)
- Seven Bridges of Konigsberg (Euler 1736) and Tower of Hanoi (Edouard Lucas, 1883) checked against the Wikipedia articles and their cited sources.
確認日: 2026-10-17