INPUT: An array of n integers, say A[0..n-1];
OUTPUT: The items of A in increasing order.
方法1.将其分为n-1长度的数列和一个元素
第一种方法可以从最简单的case入手,从n=2,n=3,到逐步解决原问题
分离出一个元素
1 2 3 4 5 6 7 8 9 10
InsertionSort( A, n ) for j = 0 to n - 1 do key = A[j]; i = j - 1; while i >= 0 and A[i] > key do A[i + 1] = A[i]; i --; end while A[i + 1] = key; end for
MergeSort(A; l; r) //从l到r之间排序 // To sort part of the array A[l::r] if l < r then m = (l + r)=2; //m denotes the middle point MergeSort(A; l; m ); MergeSort(A; m + 1; r); Merge(A; l; m; r); //Combining the sorted arrays end if Merge (A; l; m; r) //将左端最小与右端最小比较 //Merge A[l::m] (denoted as L) and A[m + 1::r](denoted as R). i = 0; j = 0; for k = l to r do if L[i] < R[j] then A[k] = L[i]; i + +; else A[k] = R[j]; j + +; end if end for
时间复杂度:O(n)
mergesort
三、迭代的时间复杂度的分析方法:
Unrolling the recurrence 硬展开
Guess and substitution 猜然后验证
Master theorem
technique 1: Unrolling the
recurrence
We have \(T(n) = 2T(\frac{n}{2}) + O(n)
<= 2T(\frac{n}{2}) + cn\) for a constant c. Let unrolling a
few levels to find a pattern, and then sum over all levels.
Unrolling
technique 2: Guess and
substitution
Guess and substitution: guess a solution, substitute it into the
recurrence relation, and justify that it works.
Guess
technique 3:Master theorem
主定理
Let T(n) be defined by \(T(n)=aT(\frac{n}{b})+O(n^d)\) for a > 1,
b > 1 and d > 0, 其中n为问题规模,a为递推的子问题数量,\(\frac{n}{b}\)为每个子问题的规模(假设每个子问题的规模基本一样),
为递推以外进行的计算工作. then T(n) can be bounded by:
If d < \(\log_b a\), then \(T(n)=O(n^{\log_b a})\);
If d = \(\log_b a\), then \(T(n)=O(n^{\log_b a} \log n)\);
If d > \(\log_b a\), then \(T(n)=O(n^d)\).
四、Counting Inversion
Problem 数逆序对
To count inversions in an array of n integers
INPUT: An array $A[0..n]$ with n distinct numbers;
OUTPUT:the number of inversions. A pair of indices i and j constitutes an inversion if i < j butA[i] > A[j].
Sort-and-Count(A) Divide A into two sub-sequences L and R; (RCL, L) = Sort-and-Count(L); (RCR, R) = Sort-and-Count(R); (C, A) = Merge-and-Count(L, R); return (RC = RCL + RCR + C, A); Merge-and-Count (L; R) RC = 0; i = 0; j = 0; for k = 0 to ∥L∥ + ∥R∥ - 1 do if L[i] > R[j] then A[k] = R[j]; j + +; RC+ = (n/2 - i); else A[k] = L[i]; i + +; end if end for return (RC, A);
时间复杂度为:\(T(n)=2T(\frac{n}{2})+O(n)=O(n\log n)\)
五、The general
Divide and Conquer paradigm
Basic Idea
Many problems are recursive in structure, i.e., to solve a given
problem, they call themselves several times to deal with closely related
sub-problems. These sub-problems have the same form to the original
problem but a smaller size.
Three Steps
Divide a problem into a number of
independent sub-problems;
Conquer the subproblems by solving them
recursively;
Combine the solutions to the subproblems
into the solution to the original problem.
Quick Sort algorithm
Divide according to a randomly-selected
pivot.根据随机选取的轴进行分割。
1 2 3 4 5 6 7 8 9 10
QuickSort(A) S_ = {}; S+ = {}; Choose a pivot A[j] uniformly at random; for i = 0 to n - 1 do //将比A[j]小的放在左边,大的放在右边 Put A[i] in S_ if A[i] < A[j]; Put A[i] in S+ if A[i] >= A[j]; end for QuickSort(S+); QuickSort(S_); Output S_, then A[j], then S+;
ModifiedQuickSort(A) while TRUE do Choose a pivot A[j] uniformly at random; S_ = {}; S+ = {}; for i = 0 to n - 1 do Put A[i] in S_ if A[i] < A[j]; Put A[i] in S+ if A[i] > A[j]; end for if ∥S+∥ >= n/4 and ∥S_∥ >= n/4 then break; end if end while ModifiedQuickSort(S+); ModifiedQuickSort(S_); Output S_, then A[j], and finally S+;
\\Lomuto’s implementation \\in-place sort 不花内存。 QuickSort(A; l; h) if l < h then p =Partition(A; l; h); QuickSort(A; l; p - 1); QuickSort(A; p + 1; h); end if Partition(A; l; h) pivot = A[h]; i = l - 1; for j = l to h - 1 do if A[j] < pivot then i + +; Swap A[i] with A[j]; end if end for if A[h] < A[i + 1] then Swap A[i + 1] with A[h]; end if return i + 1;
\\Hoare’s implementation QuickSort(A; l; h) if l < h then p =Partition(A; l; h); QuickSort(A; l; p); //Reason: A[p] might not be at its correct position QuickSort(A; p + 1; h); end if Partition(A; l; h) i = l - 1; j = h + 1; pivot = A[l]; while TRUE do repeat j = j - 1; until A[j] <= pivot or j == l; repeat i = i + 1; until A[i] >= pivot or i == h; if i >= j then return j; end if Swap A[i] with A[j]; end while
INPUT:An array A = [A0, A1,.., An_1], and a number k < n;
OUTPUT:The k-th smallest item in general case (or the median of A as a specical case).
若先将A排序再寻找第k个值,时间复杂度为\(O(nlog
n)\)。相反地,若使用分治法,则有可能开发出更快的算法(e.g.deterministic
linear algorithm by Blum et al.)。时间复杂度为\(O(n)\)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Select(A; k) Choose an element Ai from A as a pivot; S+ = {}; S_ = {}; for j = 1 to n do if Aj > Ai then S+ = S+ U {Aj}; else S_ = S_ U {Aj}; end if end for if |S_| = k - 1 then return Ai; else if |S_| > k - 1 then return Select(S_; k); \\S的size越小越好 else return Select(S+; k - |S_| + 1); end if
Selecting a central pivot via examining medians of
groups
Selecting a central pivot via randomly selecting an
element
Selecting a central pivot via examining a random
sample
Strategy
1:BFPRT algorithm uses median of medians as pivot
BFPRT
SelectMedian(A) Line up elements in groups of 5 elements; 2. Find the
median of each group; //cost \(\frac{6n}{5}\) time 3. Find the median of
medians (denoted as M)through recursively running Select over the group
medians; // \(T(\frac{n}{5})\) time 4.
Use M as pivot to partition A into S_ and S+; //\(O(n)\) time 5. if |S_| = k - 1 then 6.
return M; 7. else if |S_| > k - 1 then 8. return Select(S_; k); //at
most \(T(\frac{7n}{10})\) time 9. else
10. return Select(S+; k - |S_| - 1); //at most \(T(\frac{7n}{10})\) time 11. end if
Select(A; l; r; k) while TRUE do if l == r then return l; end if p =Pivot(A; l; r); //Use median of medians A[p] as pivot ; pos =Partition(A; l; r; p); //pos represents the final position of the pivot, A[l..pos - 1] deposit S_ and A[pos + 1..r] deposit S+; if (k - 1) == pos then return k - 1; else if (k - 1) < pos then r = pos - 1; else l = pos + 1; end if end while // Pivot(A, l, r) if (r - l) < 5 then return Partition5(A, l, r); //Get median for 5 or less elements; end if for i = l to r by 5 do right = i + 4; if right > r then right = r; end if m =Partition5(A, i, right); //Get median of a group; Swap A[m] and A[l + [(i-1)/5]]; end for return Select(A, l, l + [(r-l)/5],(r-l)/10 + 1); // Partition(A, l, r, p) pivot = A[p]; Swap A[p] and A[r]; //Move pivot to the right end; i = l; for j = l to r - 1 do if A[j] < pivot then Swap A[i] and A[j]; i + +; end if end for Swap A[r] and A[i]; return i;
图解:
part1part2part3
Strategy
2: QuickSelect algorithm randomly select an element as pivot
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
QuickSelect(A, k) Choose an element Ai from A uniformly at random; S+ = {}; S_ = {}; for all element Aj in A do if Aj > Ai then S+ = S+ U {Aj}; else S_ = S_ U {Aj}; end if end for if |S_| = k - 1 then return Ai; else if |S_| > k - 1 then return QuickSelect(S_; k); else return QuickSelect(S+; k - |S_| - 1); end if
Basic idea: when selecting an element uniformly at
random, it is highly likely to get a good pivot since a fairly large
fraction of the elements are nearly-central.
atRandom
The expected running time of QuickSelect: T(n) = O(n);
Strategy
3: Floyd-Rivest algorithm selects a pivot based on random samples
Floyd-Rivest
1 2 3 4 5 6
Floyd-Rivest-Select(A; k) Select a small random sample S (with replacement) from A. Select two pivots, denoted as u and v, from S through recursively calling Floyd-Rivest-Select. The interval [u, v], although small, is expected to cover the k-th smallest element of A. Divide A into three dis-joint subsets: L contains the elements less than u, M contains elements in [u; v], and H contains the elements greater than v. Partition A into these three sets through comparing each element Ai with u and v: if k <= n2, Ai is compared with v first and then to u only if Ai <= v. The order is reversed if k > n2. The k-th smallest element of A is selected through recursively running over an appropriate subset.
ClosestPair(pl; :::; pr) //To find the closest points within (pl; :::; pr). Here we assume that pl,...,pr have already been sorted according to x-coordinate; if r - l == 1 then return d(pl; pr); end if Use the x-coordinate of p((l+r)/2) to divide pl,...,pr into two halves; d1 = ClosestPair(LeftHalf); //T(n2) d2 = ClosestPair(RightHalf); //T(n2) d = min(d1; d2); Sort points within the 2d wide strip by y-coordinate; //O(n log n) Scan points in y-order and calculate distance between each point with its next 11 neighbors. Update d if finding a distance less than d; //O(n)