510 likes | 744 Views
Contents of Chapter 3. Chapter 3 Divide-and Conquer 3.1 General method 3.2 Binary search 3.3 Finding the maximum and minimum 3.4 Merge sort 3.5 Quicksort 3.6 Selection 3.7 Strassen ’ s matrix multiplication 3.8 Convex hull 3.9 References and readings 3.10 Additional exercises.
E N D
Contents of Chapter 3 • Chapter 3 Divide-and Conquer • 3.1 General method • 3.2 Binary search • 3.3 Finding the maximum and minimum • 3.4 Merge sort • 3.5 Quicksort • 3.6 Selection • 3.7 Strassen’s matrix multiplication • 3.8 Convex hull • 3.9 References and readings • 3.10 Additional exercises
3.1 General Method • Control abstraction for divide-and-conquer (Program 3.1) • Subproblem Pi is the same type as original problem Type DAndC(P) { if Small(P) return S(P); else { divide P into smaller instances P1, P2, …, PK, k≥1; Apply DAndC to each of these subproblems; return Combine(DAndC(P1), DAndC(P2), …, DAndC(Pk)); } }
n small otherwise 3.1 General Method • Computing time of DAndC (Formula 3.1) • g(n): time to compute the answer for small inputs • f(n): time for dividing P and combining the solutions to subproblems
n = 1 3.1 General Method • Solving recurrence relations • General form (Formula 3.2) • Example 3.1: a=2, b=2, T(1)=2, f(n)=n • T(n) = 2T(n/2) + n = 4T(n/4) + 2n (= 2[2T(n/4)+n/2] + n) = 8T(n/8) + 3n (= 4[2T(n/8)+n/4] + 2n) = … = nT(1)+ n log2 n = n log2 n + 2n
3.2 Binary Search • An instance of binary search problem • P = (n, ai,ai+1,…,al, x) • n: number of elements • ai,ai+1,…,al: list of elements in nondecreasing order • x: element to be searched for • Divide-and-conquer • Small(P) • True if n=1 • S(P) takes the value i if x=ai, otherwise 0 • So, g(1)=(1) • Divide (if Small(P) is not true) • Pick an index q (in the range [i,l]) and compare x with aq • Three possibilities • x=aq: P is solved • x<aq: P reduces to (q-i, ai,ai+1,…,aq-1, x) • x>aq: P reduces to (l-q, aq+1,aq+2,…,al, x) • Division takes only (1) • If q is chosen to be q=floor((n+1)/2), the algorithm is binary search • No need for combining (because the answer to new subproblem is also the answer to the original problem)
3.2 Binary Search • Recursive binary search (Program 3.2) int BinSrch(Type a[], int i, int l, Type x) // Given an array a[i:l] of elements in nondecreasing // order, 1<=i<=l, determine whether x is present, and // if so, return j such that x == a[j]; else return 0. { if (l==i) { // If Small(P) if (x==a[i]) return i; else return 0; } else { // Reduce P into a smaller subproblem. int mid = (i+l)/2; if (x == a[mid]) return mid; else if (x < a[mid]) return BinSrch(a,i,mid-1,x); else return BinSrch(a,mid+1,l,x); } }
3.2 Binary Search • Nonrecursive binary search (Program 3.3) int BinSearch(Type a[], int n, Type x) // Given an array a[1:n] of elements in nondecreasing // order, n>=0, determine whether x is present, and // if so, return j such that x == a[j]; else return 0. { int low = 1, high = n; while (low <= high){ int mid = (low + high)/2; if (x < a[mid]) high = mid - 1; else if (x > a[mid]) low = mid + 1; else return(mid); } return(0); }
3.2 Binary Search • Example 3.6 • 14 entries in a[] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] -15 -6 0 7 9 23 54 82 101 112 125 131 142 151 • Three examples of binary search (Table 3.2) • Theorem 3.1: Function BinSearch(a,n,x) works correctly
3.2 Binary Search • Space complexity • n+4: a[1:n], low, high, mid, x • (n) • Time complexity • Basic operation: element comparison • Other operations (arithmetic) are of the same order • Binary decision tree (Figure 3.1)
3.2 Binary Search • Successful search a: [1] [2] [3] [4] [5] [6] [7] [8] [9][10] [11] [12] [13] [14] Elements: -15 -6 0 7 9 23 54 82 101 112 125 131 142 151 Comparisons: 3 4 2 4 3 4 1 4 3 4 2 4 3 4 On the average: 45/14 3.21 comparisons • Unsuccessful search: (3+14*4)/15 3.93 • Theorem 3.2: • If n is in the range [2k-1, 2k), then BinSearch makes at most k element comparisons for a successful search and either k-1 or k comparisons for an unsuccessful search. (In other words, the time for a successful search is O(log n) and for an unsuccessful search is (log n)). • Computing time of BinSearch • Successful searches • Best (1), Average (log n), Worst (log n) • Unsuccessful searches • Best, average, worst: (log n)
3.2 Binary Search • Can expect another algorithm to be significantly better than binary search in the worst case? • No! (refer to Chapter 10) • Binary search using one comparison per cycle (Program 3.4) BinSearch1(Type a[], int n, Type x) // Same specifications as BinSearch except n > 0 { int low=1, high=n+1; // high is one more than possible. while (low < (high-1)) { int mid = (low + high)/2; if (x < a[mid]) high = mid; // Only one comparison // in the loop else low = mid; // x >= a[mid] } if (x == a[low]) return(low); // x is present. else return(0); // x is not present. }
3.2 Binary Search • BinSearch1 is better than BinSearch in average case (Table 3.3) • BinSearch1 is worse than BinSearch in the best case • best case of BinSearch: (1) • best case of BinSearch1: (log n)
3.3 Finding the Maximum and Minimum • A straightforward algorithm (Program 3.5) • Analysis • basic operation: element comparisons • 2(n-1) in best,average,and worst cases void StraightMaxMin(Type a[], int n, Type& max, Type& min) // Set max to the maximum and min to the minimum of a[1:n]. { max = min = a[1]; for (int i=2; i<=n; i++) { if (a[i] > max) max = a[i]; if (a[i] < min) min = a[i]; } }
3.3 Finding the Maximum and Minimum • An improvement if(a[i]>max) max = a[i]; else if(a[i]<min) min = a[i]; • best case: n-1 element comparisons (when in increasing order) • worst case: 2(n-1) element comparisons (when in decreasing order) • Divide-and-conquer algorithm (Program 3.6) void MaxMin(int i, int j, Type& max, Type& min) // a[1:n] is a global array. Parameters i and j are // integers, 1 <= i <= j <= n. The effect is to set // max and min to the largest and smallest values in // a[i:j], respectively. { if (i == j) max = min = a[i]; // Small(P) else if (i == j-1) { // Another case of Small(P) if (a[i] < a[j]) { max = a[j]; min = a[i]; } else { max = a[i]; min = a[j]; } }
else { // If P is not small // divide P into subproblems. // Find where to split the set. int mid=(i+j)/2; Type max1, min1; // Solve the subproblems. MaxMin(i, mid, max, min); MaxMin(mid+1, j, max1, min1); // Combine the solutions. if (max < max1) max = max1; if (min > min1) min = min1; } } 3.3 Finding the Maximum and Minimum
9 1,9,60,-8 8 5 6,9,60,17 1,5,22,-8 3 4 6 7 1,3,22,-5 8,9,47,31 4,5,15,-8 6,7,60,17 1 2 1,2,22,13 3,3,-5,-5 3.3 Finding the Maximum and Minimum • Example a: [1] [2] [3] [4] [5] [6] [7] [8] [9] Elements: 22 13 -5 -8 15 60 17 31 47 • Trees of recursive calls (Figure 3.2)
n > 2 n = 2 n = 1 • 1 0 3.3 Finding the Maximum and Minimum • Time complexity • Recurrence relations • When n=2k
3.3 Finding the Maximum and Minimum • Time complexity • 3n/2-2: best, average,and worst cases • 25% savings compared with 2n-2 for StraightMaxMin • no algorithm can do better, so MaxMin is optimal (See Chapter 10) • Does this mean that MaxMin is better in practice? • Not necessarily due to recursion (log2 n+1 levels of recursion and stacking seven values for each recursive call)
void MergeSort(int low, int high) // a[low : high] is a global array to be sorted. // Small(P) is true if there is only one element to // sort. In this case the list is already sorted. { if (low < high) { // If there are more than one element // Divide P into subproblems. // Find where to split the set. int mid = (low + high)/2; // Solve the subproblems. MergeSort(low, mid); MergeSort(mid + 1, high); // Combine the solutions. Merge(low, mid, high); } } 3.4 Merge Sort • General idea • Given n elements a[1],…, a[n],split into two sets a[1],…,a[n/2] and a[n/2+1],…,a[n]. • Each set is individually sorted, and the resulting sorted sequences are merged to a single sorted sequence of n elements. • Merge sort algorithm (Programs 3.7)
3.4 Merge Sort • Merge sort algorithm (Programs 3.8) void Merge(int low, int mid, int high) // a[low:high] is a global array containing two sorted // subsets in a[low:mid] and in a[mid+1:high]. The goal // is to merge these two sets into a single set residing // in a[low:high]. b[] is an auxiliary global array. { int h = low, i = low, j = mid+1, k; while ((h <= mid) && (j <= high)) { if (a[h] <= a[j]) { b[i] = a[h]; h++; } else { b[i] = a[j]; j++; } i++; } if (h > mid) for (k=j; k<=high; k++) { b[i] = a[k]; i++; } else for (k=h; k<=mid; k++) { b[i] = a[k]; i++; } for (k=low; k<=high; k++) a[k] = b[k]; }
3.4 Merge Sort • Example 3.7 a[1:10]=(310, 285, 179, 652, 351, 423, 861, 254, 450, 520) • Hand simulation (310 285 179 652 351 | 423 861 254 450 520) split (310 285 179 | 652 351 | 423 861 254 450 520) split (310 285 | 179 | 652 351 | 423 861 254 450 520) split (310 | 285 | 179 | 652 351 | 423 861 254 450 520) split (285 310 | 179 | 652 351 | 423 861 254 450 520) merge (179 285 310 | 652 351 | 423 861 254 450 520) merge (179 285 310 | 652 | 351 | 423 861 254 450 520) split (179 285 310 | 351 652 | 423 861 254 450 520) merge (179 285 310 351 652 | 423 861 254 450 520) merge (179 285 310 351 652 | 423 861 254 | 450 520) split ……
3.4 Merge Sort • Example 3.7 (Continued) • Tree of calls of MergeSort(1,10) (Figure 3.3)
3.4 Merge Sort • Tree of calls of Merge (Figure 3.4)
a n = 1, a a constant n > 1, c a constant – 3.4 Merge Sort • Time complexity of merge sort • When n=2k • T(n)= O(n log n)
3.4 Merge Sort • Two inefficiencies of MergeSort • Not in place (It uses another array b[].) • Copy between a[] and b[] needed • Space and time for stack due to recursion • For small set sizes, most of time consumed by recursion instead of sorting • Improvements • Using link[1:n] • Containing integers in the range [0,n], interpreted as pointers (indices) to elements of a[] • Example link: [1] [2] [3] [4] [5] [6] [7] [8] 6 4 7 1 3 0 8 0 • Q=2 denoting Q=(2,4,1,6) and sorted sublist (i.e., a[2]a[4] a[1]a[6]) • R=5 denoting R=(5,3,7,8) and sorted sublist (i.e., a[5]a[3] a[7]a[8])
3.4 Merge Sort • Improvements (Continued) • Changing the condition Small(P) • True if n16 • And use insertion sort for the small problem (since insertion sort works exceedingly fast on arrays of less than, say 16 elements) • Improved algorithm (Programs 3.10) int MergeSort1(int low, int high) // The global array a[low : high] is sorted in // nondecreasing order using the auxiliary array // link[low:high]. The values in link will // represent a list of the indices low through // high giving a[] in sorted order. A pointer // to the beginning of the list is returned. { if ((high-low+1)<16) return InsertionSort1(a, link, low, high); else { int mid = (low + high)/2; int q = MergeSort1(low, mid); int r = MergeSort1(mid+1, high); return(Merge1(q,r)); } }
3.4 Merge Sort • Improved algorithm (Programs 3.11) int Merge1(int q, int r) // q and r are pointers to lists contained in the global // array link[0:n]. link[0] is introduced only for // convenience and need not be initialized. The lists // pointed at by q and r are merged and a pointer to the // beginning of the merged list is returned. { int i=q, j=r, k=0; // The new list starts at link[0]. while (i && j) { // While both lists // are nonempty do if (a[i] <= a[j]) { // Find the smaller key. link[k] = i; k = i; i = link[i]; // Add a new key // to the list. } else { link[k] = j; k = j; j = link[j]; } } if (!i) link[k] = j; else link[k] = i; return(link[0]); }
3.4 Merge Sort • Example 3.8 (Table 3.4) • Write InsertionSort1(a,link,low,high) for yourself !
3.5 Quick Sort • Division • Partitioning a[1:n] into two subarrays a[1:m] and a[m+1:n] such that a[i]a[j] for all 1im and m+1jn • No need for merging • Each of two subarrays can be sorted independently
3.5 Quick Sort • Partitioning (due to C.A.R Hoare) (Program 3.12) int Partition(Type a[], int m, int p) // Within a[m], a[m+1],..., a[p-1] the elements // are rearranged in such a manner that if // initially t==a[m], then after completion // a[q]==t for some q between m and p-1, a[k]<=t // for m<=k<q, and a[k]>=t for q<k<p. q is returned. { Type v=a[m]; int i=m, j=p; do { do i++; while (a[i] < v); do j--; while (a[j] > v); if (i < j) Interchange(a, i, j); } while (i < j); a[m] = a[j]; a[j] = v; return(j); } inline void Interchange(Type a[], int i, int j) // Exchange a[i] with a[j]. { Type p = a[i]; a[i] = a[j]; a[j] = p; }
3.5 Quick Sort • Example 3.9 • Hand simulation (i.e., partitioned into [60 45 50 55] 65 [85 80 75 70]) • Do yourself for another example ! [15 22 13 27 12 10 20 25] • Why + at a[n+1]? • Explain using the example 1 2 3 4 5 6 7 8 9 10 [65 12 15 11 16 20 23 17 21 + ]
3.5 Quick Sort • Quick sort (Program 3.13) void QuickSort(int p, int q) // Sorts the elements a[p],..., a[q] which reside in // the global array a[1:n] into ascending order; a[n+1] // is considered to be defined and must be >= all the // elements in a[1:n]. { if (p < q) { // If there are more than one element // divide P into two subproblems. int j = Partition(a, p, q+1); // j is the position of the // partitioning element. // Solve the subproblems. QuickSort(p, j-1); QuickSort(j+1,q); // There is no need for combining solutions. } }
3.5 Quick Sort • Time complexity • Basic operation: element comparison • Assumption • n elements are distinct • Partitioning element v=a[m] has an equal probability of being the i-th smallest element, 1ip-m • Worst case: O(n2) • Exercise 7 (on p.163) • On what input data does QuickSort exhibit its worst-case behavior? • Answer (a) for the case in which the partitioning element is selected according to the median of three rule. • Average case: O(n log n)
3.5 Quick Sort • Iterative version of quick sort (Program 3.14) • Smaller of two subarrays always sorted first by the iterative version • Maximum stack depth • QuickSort (recursive version): n-1 • QucikSort1 (iterative version): O(log n) void QuickSort2(int p, int q) // Sorts the elements in a[p:q]. { Stack<int> stack(SIZE); // SIZE is 2*log(n). do { while (p < q) { int j = Partition(a, p, q+1); if ((j-p) < (q-j)) { stack.Add(j+1); stack.Add(q); q = j-1; } else { stack.Add(p); stack.Add(j-1); p = j+1; } }; // Sort the smaller subfile. if (stack.StackEmpty()) return; stack.Delete(q); stack.Delete(p); } while (1); }
3.5 Quick Sort • Performance measurement • Experiments • Comparison between QuickSort and MergeSort on Sun 10/30 • Data made by random integer generator in the range [0,1000] • Average-case on 50 random inputs (Table 3.5)
3.5 Quick Sort • Performance measurement • Worst-case on 50 random inputs (Table 3.6) • QuickSort always faster than MergeSort in Tables 3.5 and 3.6 • QuickSort usually perform better in practice (though both algorithm have O(n log n))
3.5 Quick Sort • Randomized sorting algorithms (Program 3.15) • With the aim of selecting a better partitioning element void RQuickSort(int p, int q) // Sorts the elements a[p],..., a[q] which reside in // the global array a[1:n] into ascending order. a[n+1] // is considered to be defined and must be >= all the // elements in a[1:n]. { if (p < q) { if ((q-p)>5) Interchange(a, random()%(q-p+1)+p, p); int j = Partition(p, q+1); // j is the position of // the partitioning element. RQuickSort(p,j-1); RQuickSort(j+1,q); } }
3.6 Selection • Problem • Select k-th smallest element from a[1:n] • Algorithm using partitioning (Program 3.17) • Complexity • Worst case: O(n2) • Average case: O(n) (Theorem 3.3) void Select1(Type a[], int n, int k) // Selects the kth-smallest element in a[1:n] and // places it in the kth position of a[]. The // remaining elements are rearranged such that // a[m] <= a[k] for 1 <= m < k, and // a[m] >= a[k] for k < m <= n. { int low=1, up=n+1; a[n+1] = INFTY; // a[n+1] is set to infinity. do { // Each time the loop is entered, // 1<=low<=k<=up<=n+1. int j = Partition(a, low, up); // j is such that a[j] is the // jth-smallest value in a[]. if (k == j) return; else if (k < j) up = j; // j is the new upper limit. else low = j+1; // j+1 is the new lower limit. } while (TRUE); }
• • • • • • • • • • • • 3.8 Convex Hull • Definitions • Convex hull: the smallest convex polygon containing all the points of S • Extreme point: vertex of convex hull • Example (Figure 3.6)
3.8 Convex Hull • A simple algorithm • Algorithm for(each point p in S) Look at each triplet of points and see whether p lies in the triangle formed by these three points; if p lies in any such triangle, it is not extreme, otherwise it is; • Time • (n3) to check a point, since there are (n3) possible triangles • Total time is (n4), since there are n points
q p2 p1 3.8 Convex Hull • Some geometric primitives • q is to the left (right) of <p1,p2> if the angle p1p2q is a left (right) turn • Signed area of p1(x1,y1), p2(x2,y2), and p3(x3,y3) • One-half of det(A) where A= • Positive if p3 is at the left of <p1,p2>, negative otherwise
3.8 Convex Hull • The QuickHull algorithm • Similar to QuickSort • Algorithm QuickHull • Identify two points p1 and p2 with the smallest and largest x-coordinate values (both p1 and p2 are extreme points) • Divide the point set X into X1 and X2 such that X1 (X2) has all the points to the left (right) of <p1,p2> • Compute the upper hull for X1 and lower hull for X2 using the recursive algorithm Hull • Merge two hulls into one
3.8 Convex Hull • The QuickHull algorithm (Continued) • Algorithm Hull • Divide • Pick the point p with the largest area formed by p1, p, and p2 (call such point p3) // partitioning element (Figure 3.7) • Partition the points so that one set contains the points to the left of <p1,p3> and the other set contains the ones to the left of <p3,p2> • Eliminate the remaining points // they are interior points • Apply Hull recursively to each of two subsets • Merge • Place one convex hull next to other in the right order
• • • • • • • • • • • • • • 3.8 Convex Hull • The QuickHull algorithm (Continued) • Identifying the partitioning element (Figure 3.7)
3.8 Convex Hull • The QuickHull algorithm (Continued) • Time • Algorithm Hull • m=number of point in point set • Partitioning: O(m) • Merging: O(1) • Recurrence relation • T(m) = T(m1) + T(m2) + O(m) // similar to QuickSort • Worst case: O(m2) • Average case: O(m log m) • Algorithm QuickHull • Worst case: O(n2) • Average case: O(n log n)
3.8 Convex Hull • Graham’s scan algorithm • Algorithm • Identify the point p with the lowest y-coordinate value • Sort the points of S according to the angle subtended by the points and p with the positive x-axis // Figure 3.8 • Considering three successive points p1, p2, and p3 at a time • If left turn, move to the next point • Otherwise, delete p2 and move one point back in the list by setting p1 to its predecessor • Repeat until the point p is reached • Example (Figure 3.8) 4 • 6 3 • • 5 • 7 • 2 1 • • 9 • 8 • • 10 • P
3.8 Convex Hull • Graham’s scan algorithm (Continued) • C++ programs (Program 3.21) # define NIL 0 # include<iostream.h> struct point { float x, y; struct point *prev, *next; }; typedef struct point Type; class PointSet { private: Type* ptslist; float Area(float, float, float, float, float, float); void PrintList(Type *); void Scan(Type *); void Sort(Type *); public: PointSet() {ptslist = NIL;} void Insert(float a, float b); void ConvexHull(); };
void PointSet::Scan(Type* list) { Type *p=list, *p1=list, *p2, *p3; float temp; do { p2 = p1->next; if (p2->next) p3 = p2->next; else p3 = p; temp = Area(p1->x, p1->y, p2->x, p2->y, p3->x, p3->y); if (temp>=0.0) p1 = p1->next; // If p1,p2,p3 form a left turn // move one point ahead; // if not delete p2 and move back. else { p1->next=p3; p3->prev=p1; delete p2; p1 = p1->prev; } } while (!((p3 == p) && (temp>=0.0))); } void PointSet::ConvexHull() { // Find the point p in ptslist of lowest // x-coordinate. Sort the points according // to the angle made with p and x-axis. Sort(ptslist); Scan(ptslist); PrintList(ptslist); }
3.8 Convex Hull • Graham’s scan algorithm (Continued) • Time • Scan: O(n) • Testing left or right turn for each triplet: O(1) • Sorting: O(n log n) • So, total time: O(n log n)
3.8 Convex Hull • DCHull algorithm • O(n log n) divide-and-conquer algorithm • Left for your self-study !