第二章 算法入门(2)
2.3 算法设计 (合并排序)
插入排序使用的是增量(incremental)方法。
另一种设计策略,叫做“分治法”(divide-and-conquer)。分制算法的优点之一是很容易确定运行时间。
分治策略:将原问题划分成为n个规模较小而结构与原问题相似的子问题;递归的解决这些子问题,然后再合并其结果,就得到原问题的解。
分制模式在每一层递归上都有三个步骤:分解(divide),解决(conquer),合并(combine)。
合并排序(merge sort)的关键步骤在于合并两个已排序子序列。MERGE过程的时间代价是theta(n)。
伪代码实现MERGE过程:(避免检查是否每一个堆都是空的,在每一堆的底部放上一张“哨兵牌”(sentinel card),利用∞来作为哨兵值)。
MERGE(A, p, q, r) 1 n1 ← q - p + 1 2 n2 ← r - q 3 create arrays L[1 ‥ n1 + 1] and R[1 ‥ n2 + 1] 4 for i ← 1 to n1 5 do L[i] ← A[p + i - 1] 6 for j ← 1 to n2 7 do R[j] ← A[q + j] 8 L[n1 + 1] ← ∞ 9 R[n2 + 1] ← ∞ 10 i ← 1 11 j ← 1 12 for k ← p to r 13 do if L[i] ≤ R[j] 14 then A[k] ← L[i] 15 i ← i + 1 16 else A[k] ← R[j] 17 j ← j + 1
这个很好理解。
现在可将MERGE过程作为合并程序中一个子程序来使用。
伪代码实现MERGE-SORT(A,p,r):
MERGE-SORT(A, p, r) 1 if p < r 2 then q ← ⌊(p + r)/2⌋ 3 MERGE-SORT(A, p, q) 4 MERGE-SORT(A, q + 1, r) 5 MERGE(A, p, q, r)
看图示很明确:
练习题:2.3-7
Describe a Θ(n lg n)-time algorithm that, given a set S of n integers and another integer x, determines whether or not there exist two elements in S whose sum is exactly x.
请给出一个运行时间为 Θ(n lg n)的算法,使之能在给定一个由n个整数构成的集合S和另一个整数x时,判断出S中是否存在两个其和等于x的元素。
1 Input: An array A and a value x. 2 Output: A boolean value indicating if there is two elements in A whose sum is x. 3 A <- SORT(A) 4 n <- length[A] 5 for i to n do 6 if A[i] > 0 and BINARY-SEARCH(A;A[i] - x; 1; n) then 7 return true 8 end if 9 end for 10 return false
思考题2-4 逆序对
Let A[1 ‥ n] be an array of n distinct numbers. If i < j and A[i] > A[j], then the pair (i, j) is called an inversion of A.
-
List the five inversions of the array 〈2, 3, 8, 6, 1〉.
-
What array with elements from the set {1, 2, . . . , n} has the most inversions? How many does it have?
-
What is the relationship between the running time of insertion sort and the number of inversions in the input array? Justify your answer.
-
Give an algorithm that determines the number of inversions in any permutation on n elements in Θ(n lg n) worst-case time. (Hint: Modify merge sort.)
d)给出一个算法,它能用Θ(n lg n)的最坏情况运行时间,确定n个元素的任何排列中逆序对的数目(提示:修改合并程序)。
根据提示,利用合并程序。很显然,如果L暴露的比R暴露的大, 那么就是逆序对,我们可以统计其次数,则对应是逆序对数目。
COUNT-INVERSIONS.A; p; r/ inversions D 0 if p < r q D b.p C r/=2c inversions D in ersions C COUNT-INVERSIONS.A; p; q/ inversions D in ersions C COUNT-INVERSIONS.A; q C 1; r/ inversions D in ersions C MERGE-INVERSIONS.A; p; q; r/ return inversions
1 Selected Solutions for Chapter 2: Getting Started 2 MERGE-INVERSIONS.A; p; q; r/ 3 n1 = q - p + 1 4 n2 = r - q 5 let L[1 : : n1 + 1] and R[1 .. n2 + 1] be new arrays 6 for i = 1 to n1 7 L[i ] = A[p + i - 1] 8 for j = 1 to n2 9 R[j] = A[q + j] 10 L[n1 + 1] = ∞ 11 R[n2 + 1] = ∞ 12 i = 1 13 j = 1 14 inversions = 0 15 counted = FALSE 16 for k = p to r 17 if counted == FALSE and ROEj < LOEi 18 inversions = inversions + n1 - i + 1 19 counted = TRUE 20 if L[i] <= R[j] 21 A[k] = L[i] 22 i = i + 1 23 else A[k] = R[j] 24 j = j + 1 25 counted = FALSE 26 return inversions