整列の基本
algorithmfoundationundergraduatelecture
data/lecture/information/algorithm/foundation/recursion-basics.lecture.n.md
1導入
この講義では、整列の仕様と評価基準を定義し、挿入整列と併合整列の正当性および計算量を説明する。整列済みの配列は、後続する二分探索の前提となる。
2整列の仕様
要素列 A=(a_0,\ldots,a_{n-1}) と、要素の鍵を全順序集合へ対応させる関数 k を考える。昇順整列は、出力列 B=(b_0,\ldots,b_{n-1}) が次の二条件を満たす算法である。
- B は A の置換である。すなわち、各要素の個数が保存される。
- k(b_0)\leq k(b_1)\leq\cdots\leq k(b_{n-1}) が成立する。
第一条件は要素の欠落や重複生成を禁止し、第二条件は出力順序を規定する。
3評価基準
3.1安定性
安定な整列は、i<j かつ k(a_i)=k(a_j) である二要素の相対順序を出力でも保存する。複数の鍵で段階的に整列する場合、この性質によって先の整列結果を維持できる。
3.2原位置性
入力長 n に比例する別配列を使用せず、追加領域 O(1) で入力配列内を更新する整列を原位置整列という。再帰呼出しの記憶領域を含めるかは解析で明示する。
3.3比較モデル
比較整列では、鍵に関する情報を k(x)\leq k(y) などの比較結果からだけ取得する。以下では一回の比較と代入を O(1) とし、最悪時の時間計算量を評価する。
4挿入整列
挿入整列は、i=1,2,\ldots,n-1 の順に a_i を取り出し、整列済みの接頭辞 A[0,i) の適切な位置へ挿入する。鍵が挿入要素より大きい要素だけを右へ移動する。
4.1正当性
反復開始時に「A[0,i) は、元の A[0,i) の要素を昇順に整列した列である」を不変条件とする。
- i=1 では、一要素の接頭辞は整列済みである。
- a_i より大きい要素を右へ移動し、その直前へ a_i を挿入すると、要素を保存したまま A[0,i+1) が昇順になる。
- i=n では接頭辞が配列全体と一致する。
したがって、挿入整列は整列の仕様を満たす。同一鍵の要素を追い越さないため安定であり、一時変数だけで実装できるため原位置である。
4.2計算量
既に整列済みなら各反復の比較回数は定数であり、時間計算量は \Theta(n) である。逆順では i 番目の挿入に i 回の移動を要するため、合計は \sum_{i=1}^{n-1}i=\Theta(n^2) となる。
5併合整列
併合整列は、列を長さが高々 1 になるまで二分し、各部分列を再帰的に整列した後、二つの整列済み列を併合する。併合では両列の先頭を比較し、小さい方を出力へ移す。
5.1正当性
併合では、「出力済みの列は昇順であり、両入力列から取り除いた要素を過不足なく含む」を不変条件とする。両先頭の小さい方は未出力要素全体の最小要素であるため、この要素を追加しても不変条件は保存される。終了時には全要素が出力される。
列長に関する帰納法を適用すると、長さ 0 または 1 の列は自明に整列済みであり、短い二列の再帰結果と正しい併合から元の列も正しく整列される。したがって算法全体が正当である。
同一鍵では左側の要素を先に出力すれば安定性を保持できる。標準的な配列実装は併合用の O(n) 領域を使用するため、原位置ではない。
5.2計算量
長さ n の併合は \Theta(n) 時間を要する。時間計算量 T(n) は
T(0)=T(1)=\Theta(1),\qquad
T(n)=T(\lfloor n/2\rfloor)+T(\lceil n/2\rceil)+\Theta(n)\quad(n\geq2)
を満たす。再帰木の高さは \lceil\log_2 n\rceil であり、同一深度にある部分列長の合計は n である。したがって各深度の併合費用は高々 O(n) であり、上界は O(n\log n) となる。また、0\leq d<\lfloor\log_2 n\rfloor の各深度では長さ 2 以上の部分列の合計長が \Theta(n) であるため、下界は \Omega(n\log n) となる。よって、T(n)=\Theta(n\log n) である。
標準的な配列実装では、再利用する併合用配列が \Theta(n)、呼出しスタックが \Theta(\log(n+1)) の領域を使用する。したがって、呼出しスタックを含む総補助空間計算量は \Theta(n) である。空列は直ちに終了する。
6比較整列の下界
互いに異なる鍵をもつ n 個の要素には n! 通りの入力順序がある。決定的比較整列の二分決定木は、これらを識別するために少なくとも n! 枚の葉を必要とし、その高さは少なくとも \lceil\log_2(n!)\rceil である。n\geq2 では n!\geq(n/2)^{n/2} であるため、\log_2(n!)=\Omega(n\log n) が成立する。したがって、任意の決定的比較整列は最悪時に \Omega(n\log n) 回の比較を要する。併合整列の \Theta(n\log n) はこの比較モデルで漸近的に最適である。
7二分探索への接続
二分探索は、A_0\leq A_1\leq\cdots\leq A_{n-1} が成立する配列を前提とする。未整列の入力に一度だけ探索するなら、整列の費用が利益を上回る場合がある。同じ配列を反復探索するなら、最初に O(n\log n) で整列し、その後の各探索を O(\log n) で実行する構成が有効となる。
data/lecture/information/algorithm/search/binary-search.lecture.n.md
Sorting Basics
data/lecture/information/algorithm/foundation/recursion-basics.lecture.n.md
1Introduction
This lecture defines the specification and evaluation criteria of sorting and explains the correctness and complexity of insertion sort and merge sort. A sorted array is a prerequisite for the subsequent binary-search lecture.
2Sorting specification
Let A=(a_0,\ldots,a_{n-1}) be a sequence, and let a key function k map each element to a totally ordered set. An ascending sorting algorithm produces B=(b_0,\ldots,b_{n-1}) satisfying both conditions below.
- B is a permutation of A; the multiplicity of every element is preserved.
- k(b_0)\leq k(b_1)\leq\cdots\leq k(b_{n-1}).
The first condition prohibits lost or duplicated elements, and the second specifies the output order.
3Evaluation criteria
3.1Stability
A stable sort preserves the relative output order of any two elements satisfying i<j and k(a_i)=k(a_j). This property preserves the result of an earlier sort when sorting by several keys in stages.
3.2In-place operation
An in-place sort updates the input array using O(1) auxiliary space rather than an additional array proportional to n. An analysis must state whether it includes recursive call-stack space.
3.3Comparison model
A comparison sort obtains information about keys only through results such as k(x)\leq k(y). Below, each comparison and assignment takes O(1) time, and complexity denotes worst-case time unless stated otherwise.
4Insertion sort
Insertion sort takes a_i for i=1,2,\ldots,n-1 and inserts it into its proper position in the sorted prefix A[0,i). It shifts right only elements whose keys are greater than the inserted key.
4.1Correctness
Use the following loop invariant: at the start of iteration i, A[0,i) contains exactly the original elements of that prefix in nondecreasing order.
- For i=1, a one-element prefix is sorted.
- Shifting elements greater than a_i and inserting a_i immediately before them preserves all elements and makes A[0,i+1) sorted.
- At i=n, the prefix is the entire array.
Thus insertion sort satisfies the sorting specification. It is stable because equal-key elements do not pass each other, and it is in-place because it requires only a temporary variable.
4.2Complexity
For an already sorted input, every iteration performs a constant number of comparisons, so the time complexity is \Theta(n). In reverse order, insertion i requires i shifts, giving \sum_{i=1}^{n-1}i=\Theta(n^2) total work.
5Merge sort
Merge sort divides a sequence until every part has length at most 1, recursively sorts the parts, and merges two sorted sequences. A merge compares their first remaining elements and transfers the smaller one to the output.
5.1Correctness
For merging, maintain the invariant that the produced sequence is sorted and contains exactly the elements removed from the two inputs. The smaller of the two first remaining elements is a minimum among all remaining elements, so appending it preserves the invariant. At termination, every element has been produced.
Induction on sequence length now proves the whole algorithm correct. Sequences of length 0 or 1 are trivially sorted. The inductive hypothesis gives two correctly sorted shorter sequences, and the correct merge produces a sorted permutation of the original sequence.
If equal keys are resolved by taking the left element first, merge sort is stable. A standard array implementation uses O(n) auxiliary merge storage and is therefore not in-place.
5.2Complexity
Merging a total of n elements takes \Theta(n) time. The time complexity T(n) satisfies
T(0)=T(1)=\Theta(1),\qquad
T(n)=T(\lfloor n/2\rfloor)+T(\lceil n/2\rceil)+\Theta(n)\quad(n\geq2).
The recursion tree has height \lceil\log_2 n\rceil, and the subproblem lengths at any one depth sum to n. Hence the merge cost at each depth is at most O(n), giving an O(n\log n) upper bound. At every depth 0\leq d<\lfloor\log_2 n\rfloor, subproblems of length at least 2 have total length \Theta(n), giving an \Omega(n\log n) lower bound. Therefore, T(n)=\Theta(n\log n).
In a standard array implementation, a reusable merge array uses \Theta(n) space and the call stack uses \Theta(\log(n+1)) space. Thus, the total auxiliary-space complexity, including the call stack, is \Theta(n). An empty sequence terminates immediately.
6Lower bound for comparison sorting
There are n! input orders of n elements with mutually distinct keys. The binary decision tree of a deterministic comparison sort needs at least n! leaves to distinguish these orders, so its height is at least \lceil\log_2(n!)\rceil. For n\geq2, the inequality n!\geq(n/2)^{n/2} implies \log_2(n!)=\Omega(n\log n). Hence every deterministic comparison sort requires \Omega(n\log n) comparisons in the worst case. Merge sort's \Theta(n\log n) bound is asymptotically optimal in this model.
7Connection to binary search
Binary search assumes A_0\leq A_1\leq\cdots\leq A_{n-1}. For a single query on unsorted input, the cost of sorting may exceed its benefit. For repeated queries on the same array, sorting once in O(n\log n) time and then performing each query in O(\log n) time can be effective.
data/lecture/information/algorithm/search/binary-search.lecture.n.md