Recursive and divided treatment
Many useful algorithms are structurally recursive : In order to solve a given problem, the algorithm invokes itself one or more times recursively to solve some closely related sub-problems. These algorithms typically follow the idea of divide-and- conquer : To decompose the original problem into several smaller but similar sub-problems, to solve these sub-problems recursively, and then merge the solutions of these sub-problems to establish the solution of the original problem.
The divide-and-conquer pattern has three steps at each level of recursion:
- decomposition of the original problem is a number of sub-problems, these sub-problems are the original problem of small-scale instances.
- solve These sub-problems and solve the sub-problems recursively. However, if the size of the sub-problem is small enough, it is solved directly.
- The solution of the Jia Cheng original problem of merging these sub-problems.
Merge Sort
The merge sort algorithm completely follows the divide-and-conquer mode. Intuitively, it operates as follows:
(1) Decomposition: The sequence of n elements sorted by decomposition is divided into two sub-sequences with N/2 elements;
(2) Solve: Use merge sort recursively to sort two sub-sequences;
(3) Merge: Merges two sorted sub-sequences to produce sorted answers.
When the sequence length to be sorted is 1 o'clock, the recursion "starts to pick up", in which case no root does any work, because each sequence of length 1 is ordered.
The key operation of the merge sort algorithm is the merging of two sorted sequences in the Combine step. We can complete the merge by invoking a secondary process merge (a, p, Q, R), where a is an array, p, Q, and R are array subscripts, satisfying P≤q < R. The procedure assumes that the Subarray a[p: Q] and A[Q+1..R] have been sequenced. It merges these two sub-arrays to form a single, ordered Subarray and replaces the current Subarray a[p. R].
Merge (A, p, Q, R)1N1 = Q-p +12N2 = R-Q3Let l[1.. n1+1] and r[1.. n2+1] BeNewArrays4 for(i =1; I <= N1; i++)5L[i] = a[p+i-1]6 for(j =1; J <= N2; J + +)7R[J] = a[q+J]8l[n1+1] =INF9r[n2+1] =INFTeni =1 Onej =1 A for(k = p; k <= R; k++) - if(L[i] <=R[j]) -A[K] =L[i] thei = i +1 - ElseA[K] =R[j] -j = j +1
The process merge detailed work process is as follows:
- The 1th Row calculates the Subarray a[p: Q] The length of N1, the 2nd row calculates the length of the sub-array a[q+1..r] n2;
- In line 3rd, we create an array of lengths of N1+1 and N2+1, respectively L and R ("left" and "right"), and the additional positions in each array will save the Sentinel;
- The For loop of the 4–5 line a[p the sub-array: Q] Copy to l[1..n1], 第6-7 row for loop to copy sub-array A[Q+1..R] to r[1..n2];
- 第8-9 will be placed Sentinel at the end of the array L and R;
- The 第10-17 line performs r-p+1 basic steps by maintaining the following loop invariant:
At the beginning of each iteration of the 第12-17 line for loop, the sub-array a[p: K-1] k-p smallest elements in l[1..n1+1] and r[1..n2+1] in order from small to large. Further, L[i] and r[j] are the smallest elements in the array in which they are not copied back to array a.
Now we can use merge as a subroutine in the merge sort algorithm. The following procedure Merge-sort (A, p, R) to sort the sub-array a[p: The elements in R]. If P≥r, the Subarray has a maximum of one element, so it is already sorted. Otherwise, the decomposition step simply computes a subscript q, which will a[p. R] is divided into two sub-arrays of a[p. Q] and A[Q+1..R].
merge-Sort (A, p, R)1 if (P < R)2 23 merge-Sort (A, p, q)4 merge-sort (A, q+1, R)5 Merge (A, p, Q, R)
Analysis of time complexity
Below we analyze the recursive type of the worst-case run time t (n) that sets the number of merge sort N. Merging to sort an element requires constant time. When there are n>1 elements, we decompose the run time as follows:
Decomposition: The decomposition step computes only the middle position of the subarray, which requires constant time, so D (n) = O (1).
Solution: We recursively solve two sub-problems of both scale N/2, which will contribute 2T (N/2) run time.
Merge: We have noticed that the process merge requires O (n) time on a sub-array with n elements, so C (n) = O (n).
When N>1, T (n) = 2T (N/2) + O (n). The recursive solution is as follows:
Exercise 2.3
1. Description of the merge sort in the array a=<3, a, 9,, 49>, on the operation.
"Solution" as shown:
2. The rewrite process merges so that it does not use Sentinels, but once all elements of the array L or R are copied back to a, they stop immediately and then copy the remainder of the other array back to a.
The "answer" reference pseudo-code is shown below
Merge (A, p, Q, R)1N1 = Q-p +12N2 = R-Q3Let l[1.. N1] and r[1.. N2] BeNewArrays4 for(i =1; I <= N1; i++)5L[i] = a[p+i-1]6 for(j =1; J <= N2; J + +)7R[J] = a[q+J]8i =19j =1TenK =P One while(I <= N1 && J <=n2) A if(L[i] <=R[j]) -a[k++] = l[i++] - Elsea[k++] = r[j++] the while(I <= N1) a[k++] = l[i++] - while(J <= N2) a[k++] = r[j++]
3. Use the array induction method to prove that: when N is just the power of 2, the following recursive solution is t (n) = nlgn.
T (n) =2t (N/2) +n, if n=2k,k>1, and t (2) = 2.
"Proof" slightly.
4. We can represent the insertion sort as the following recursive procedure. In order to sort A[1..N], we recursively sort a[1..n-1], and then insert a[n] into the sorted array a[1..n-1]. Write a recursive for the worst case run time of this recursive version of the insertion sort.
"Solution" t (n) = t (n-1) + O (n) = O (n2)
5. Look back at the problem (see exercise 2.1-3) and note that if sequence A is ordered, you can compare the midpoint of the sequence to V. As a result of the comparison, half of the original sequence can be used without further consideration. The binary lookup algorithm repeats the process, halving the size of the remainder of the sequence each time. Find the pseudo-code that writes out iterations or recursion for two points. Proof: The worst-case run time for binary lookup is O (LGN).
The "answer" binary lookup recursive reference pseudocode is as follows:
binary-Search (A, p, R, v)1 if(P > R)returnNIL2Q = (p + r)/23 if(A[q] = = v)returnQ4 Else if(A[q] >v)5 returnBinary-search (A, p, q1)6 Else returnBinary-search (A, q+1, R)
The iterative reference pseudo-code looks like this:
binary-search (A, p, R, v) 1 while (P < R) 2 Q = (p + r)/2 3 if (a[q] = = v) return Q 4 else if (A [Q] > V) r = q-1 5 else p = q + 1 6 return NIL
Time complexity: t (n) = t (N/2) + O (1) = O (LGN).
6. Note that the procedure in the Insert sort insertion-sort the 第5-7 line of the while loop color a linear lookup to (reverse) scan a sorted sub-array a[1..j-1]. Can we use a binary lookup (see exercise 2.3-5) to improve the worst-case total run time for the insertion sort to O (NLGN)?
"Solution" cannot. Because although it can reduce the time to find, but the time to move to the right can not be reduced, still O (n).
#7. Describes an algorithm that runs at O (NLGN), given the set S of n integers and another integer x, which determines if there are two elements in s that are exactly x.
The answers are sorted first, and then the two pointers are traversed from the head and tail of the array to find them.
Appendix: Merging sort code Examples
/** * If this code works, then it's written by XIAOXXMU * Otherwise, I don't know who wrote it.*/#include<stdio.h>#include<stdlib.h>voidMergeintArr[],intPintQintR) { intLen1 = Q-p +1, Len2 = R-Q, I, J, K; int*l = (int*) malloc (LEN1 *sizeof(int)); int*r = (int*) malloc (LEN2 *sizeof(int)); for(i =0; i < len1; i++) L[i]= arr[p+i]; for(j =0; J < Len2; J + +) R[j]= arr[q+j+1]; I=0, j =0, k =p; while(I < len1 && J <len2) { if(L[i] < r[j]) arr[k++] = l[i++]; Elsearr[k++] = r[j++]; } while(I < len1) arr[k++] = l[i++]; while(J < len2) arr[k++] = r[j++]; }voidMerge_sort (intArr[],intPintR) { if(P <r) {intQ = (p + r)/2; Merge_sort (arr, p, q); Merge_sort (arr, q+1, R); Merge (arr, p, Q, R); }}intMainintargcChar*argv[]) { intArr[] = {3, A, the, -, -, $,9, the, -}; intLength = (sizeofARR)/(sizeofarr[0]); Merge_sort (arr,0, Length-1); for(inti =0; i < length; i++) { if(i = =0) printf ("%d", Arr[i]); Elseprintf"%d", Arr[i]); } printf ("\ n"); return 0; }
"Introduction to Algorithms" Merge sort