360 likes | 445 Views
Chapter 7. Internal Sorting. Sorting. Each record contains a field called the key. Linear order: comparison. Measures of cost: Comparisons Swaps. Insertion Sort (1). Insertion Sort (2). template <class Elem> void inssort(Elem A[], int n) { for (int i=1; i<n; i++)
E N D
Chapter 7 Internal Sorting
Sorting Each record contains a field called the key. • Linear order: comparison. Measures of cost: • Comparisons • Swaps
Insertion Sort (2) template <class Elem> void inssort(Elem A[], int n) { for (int i=1; i<n; i++) for (int j=i; (j>0) && (A[j] < A[j-1]); j--) swap(A, j, j-1); } Best Case: Worst Case: Average Case:
Bubble Sort (2) template <class Elem, class Comp> void bubsort(Elem A[], int n) { for (int i=0; i<n-1; i++) for (int j=n-1; j>i; j--) if (A[j] < A[j-1]) swap(A, j, j-1); } Best Case: Worst Case: Average Case:
Selection Sort (2) template <class Elem> void selsort(Elem A[], int n) { for (int i=0; i<n-1; i++) { int lowindex = i; // Remember its index for (int j=n-1; j>i; j--) // Find least if (A[j] < A[lowindex]) lowindex = j; // Put it in place swap(A, i, lowindex); } } Best Case: Worst Case: Average Case:
Exchange Sorting All of the sorts so far rely on exchanges of adjacent records. What is the average number of exchanges required? • There are n! permutations • Consider permuation X and its reverse, X’ • Together, every pair requires n(n-1)/2 exchanges.
Shellsort // Modified version of Insertion Sort template <class Elem> void inssort2(Elem A[], int n, int incr) { for (int i=incr; i<n; i+=incr) for (int j=i; (j>=incr) && (A[j] < A[j-incr]); j-=incr) swap(A, j, j-incr); } template <class Elem> void shellsort(Elem A[], int n) { // Shellsort for (int i=n/2; i>2; i/=2) // For each incr for (int j=0; j<i; j++) // Sort sublists inssort2<Elem>(&A[j], n-j, i); inssort2<Elem>(A, n, 1); }
Quicksort template <class Elem> void qsort(Elem A[], int i, int j) { if (j <= i) return; // List too small int pivotindex = findpivot(A, i, j); swap(A, pivotindex, j); // Put pivot at end // k will be first position on right side int k = partition<Elem>(A, i-1, j, A[j]); swap(A, k, j); // Put pivot in place qsort<Elem>(A, i, k-1); qsort<Elem>(A, k+1, j); } template <class Elem> int findpivot(Elem A[], int i, int j) { return (i+j)/2; }
Quicksort Partition template <class Elem, class Comp> int partition(Elem A[], int l, int r, Elem& pivot) { do { // Move the bounds in until they meet while (Comp::lt(A[++l], pivot)); while ((r != 0) && Comp::gt(A[--r], pivot)); swap(A, l, r); // Swap out-of-place values } while (l < r); // Stop when they cross swap(A, l, r); // Reverse last swap return l; // Return first pos on right } The cost for partition is Q(n).
Cost of Quicksort Best case: Always partition in half. Worst case: Bad partition. Average case: T(n) = n + 1 + 1/(n-1) (T(k) + T(n-k)) Optimizations for Quicksort: • Better Pivot • Better algorithm for small sublists • Eliminate recursion n-1 k=1
Mergesort List mergesort(List inlist) { if (inlist.length() <= 1)return inlist; List l1 = half of the items from inlist; List l2 = other half of items from inlist; return merge(mergesort(l1), mergesort(l2)); }
Mergesort Implementation template <class Elem, class Comp> void mergesort(Elem A[], Elem temp[], int left, int right) { int mid = (left+right)/2; if (left == right) return; mergesort<Elem,Comp>(A, temp, left, mid); mergesort<Elem,Comp>(A, temp, mid+1, right); for (int i=left; i<=right; i++) // Copy temp[i] = A[i]; int i1 = left; int i2 = mid + 1; for (int curr=left; curr<=right; curr++) { if (i1 == mid+1) // Left exhausted A[curr] = temp[i2++]; else if (i2 > right) // Right exhausted A[curr] = temp[i1++]; else if (Comp::lt(temp[i1], temp[i2])) A[curr] = temp[i1++]; else A[curr] = temp[i2++]; }}
Optimized Mergesort template <class Elem, class Comp> void mergesort(Elem A[], Elem temp[], int left, int right) { if ((right-left) <= THRESHOLD) { inssort<Elem,Comp>(&A[left],right-left+1); return; } int i, j, k, mid = (left+right)/2; if (left == right) return; mergesort<Elem,Comp>(A, temp, left, mid); mergesort<Elem,Comp>(A, temp, mid+1, right); for (i=mid; i>=left; i--) temp[i] = A[i]; for (j=1; j<=right-mid; j++) temp[right-j+1] = A[j+mid]; for (i=left,j=right,k=left; k<=right; k++) if (temp[i] < temp[j]) A[k] = temp[i++]; else A[k] = temp[j--]; }
Mergesort Cost Mergesort cost: Mergsort is also good for sorting linked lists. Mergesort requires twice the space.
Heapsort template <class Elem, class Comp> void heapsort(Elem A[], int n) { // Heapsort Elem mval; maxheap<Elem,Comp> H(A, n, n); for (int i=0; i<n; i++) // Now sort H.removemax(mval); // Put max at end } Use a max-heap, so that elements end up sorted within the array. Cost of heapsort: Cost of finding K largest elements:
Binsort (1) A simple, efficient sort: for (i=0; i<n; i++) B[A[i]] = A[i]; Ways to generalize: • Make each bin the head of a list. • Allow more keys than records.
Binsort (2) template <class Elem> void binsort(Elem A[], int n) { List<Elem> B[MaxKeyValue]; Elem item; for (i=0; i<n; i++) B[A[i]].append(A[i]); for (i=0; i<MaxKeyValue; i++) for (B[i].setStart(); B[i].getValue(item); B[i].next()) output(item); } Cost:
Radix Sort (2) template <class Elem, class Comp> void radix(Elem A[], Elem B[], int n, int k, int r, int cnt[]) { // cnt[i] stores # of records in bin[i] int j; for (int i=0, rtok=1; i<k; i++, rtok*=r) { for (j=0; j<r; j++) cnt[j] = 0; // Count # of records for each bin for(j=0; j<n; j++) cnt[(A[j]/rtok)%r]++; // cnt[j] will be last slot of bin j. for (j=1; j<r; j++) cnt[j] = cnt[j-1] + cnt[j]; for (j=n-1; j>=0; j--)\ B[--cnt[(A[j]/rtok)%r]] = A[j]; for (j=0; j<n; j++) A[j] = B[j]; }}
Radix Sort Cost Cost: Q(nk + rk) How do n, k, and r relate? If key range is small, then this can be Q(n). If there are n distinct keys, then the length of a key must be at least log n. • Thus, Radix Sort is Q(n log n) in general case
Sorting Lower Bound We would like to know a lower bound for all possible sorting algorithms. Sorting is O(n log n) (average, worst cases) because we know of algorithms with this upper bound. Sorting I/O takes (n) time. We will now prove (n log n) lower bound for sorting.
Lower Bound Proof • There are n! permutations. • A sorting algorithm can be viewed as determining which permutation has been input. • Each leaf node of the decision tree corresponds to one permutation. • A tree with n nodes has W(log n) levels, so the tree with n! leaves has W(log n!) = W(n log n) levels. Which node in the decision tree corresponds to the worst case?