190 likes | 345 Views
COSC 1030 Lecture 11. Sorting. Topics. Sorting Themes Low bound of sorting Priority queue methods Selection sort Heap sort Divide-and-conquer methods Merge sort Quick sort Insertion based methods Address-calculation methods. Sorting Themes. Why sort is an important theme of CS
E N D
COSC 1030 Lecture 11 Sorting
Topics • Sorting Themes • Low bound of sorting • Priority queue methods • Selection sort • Heap sort • Divide-and-conquer methods • Merge sort • Quick sort • Insertion based methods • Address-calculation methods
Sorting Themes • Why sort is an important theme of CS • Performance analysis • Low boundary of problems • Model to implementation • Comparison-based sorting • Insertion • Priority Queue • Divide-and-conquer • Address-calculation sorting
Low Bound of Sorting • Low bound – of a problem P • A complexity class O(P), for any solution S to P, the complexity is of O(S) in the worst case, then O(S) O(P) • There is a solution S such that O(S) = O(P) • To sorting, the low bound is O(n log n) • How do we find the low bound?
Decision Tree • In-node represents comparison • Leaf represents an order • Extended binary tree • For n elements, there are n! orders • Every path determines an order • Minimal external path length lg (n!) • lg(n!) > ½ n lg n
Priority Queue Sorting • Insert n elements into a priority queue • Remove elements from the priority queue one by one • Performance? • Dependent on priority queue implementation • List impl. – remove is of O(n) SelectionSort • Heap impl. – remove is of O(lg n) HeapSort • O(n lg n) if heap is used • Do we need additional space?
void selectionSort(KeyType[] A) { KeyType key; int n = A.length; int i = n –1; // initially Q is empty while(i > 0) { // PQ has more element int j = i; // j point to last key of PQ for(int k = 0; k < I; k++) { // find max in PQ if(A[k].compareTo(A[j]) > 0) j = k; } temp = A[i]; A[i] = A[j]; A[j] = temp; // swap i--; // move boundary down } }
void heapSort(KeyType[] A) { KeyType temp; int n = A.length; for(int j = n / 2; j>1; j--) { // heapify all sub trees siftUp(A, j, n); // except root tree } // only non-leaf sub tree need to heapify for(int i = n; i >1; i--) { // reheapify starting at root siftUp(A, 1, i); // to the last leaf temp = A[1]; A[1] = A[i]; A[i] = temp; // swap } }
void siftUp(KeyType[] A, int i, int n) { // O(lg (n –i)) // i the index of root, n the last leaf index KeyType rootKey = A[i]; int j = 2*i; // point to left child of i boolean notFinished = (j <= n); // if j is in the range, not finished while(notFinished) { // if right child of i exists and it’s bigger than left, j point to right if(j<n && A[j+1].compareTo(A[j]) > 0) j ++; if(A[j].compareTo(rootKey) <= 0) { notFinished = false; // no more keys sift up } else { A[i] = A[j]; // sift A[j] up one level i = j; // i point to larger child j = 2*i; // j point to the new left child of i notFinshed = (j <= n); } // end of while A[i] = rootKey; }
Divide-and-conquer void sort(KeyType[] A, int m, int n) { if(n-m > 1) { // if more than 1 element in the range // divide A[m:n] into subarrays: // A[m:i] and A[i+1:n] sort(A, m, i); sort(A, i, n); // combine two sorted array // to yield the sorted original array } }
Merge Sort void mergeSort(KeyType[] A, int m, int n) { if(n - m > 1) { // if more than 1 element in the range // divide A[m:n] into subarrays: // A[m:i] and A[i+1:n] int i = (m + n)/2; // I point in the middle mergeSort(A, m, i); mergeSort(A, I+1, n); merge(A, m, i, n); } }
Merge void merge(KeyType[] A, int m, int i, int n) { // O(n – m +1) KeyType[] temp = new KeyType[n – m + 1]; int k =0; int j = i + 1; int l = m; while(l <= i && j <= n) { if(A[l] <= A[j]) { // copy smaller one into temp temp[k++] = A[l++]; } else { temp[k++] = A[j++]; } } while(l <= i) temp[k++] = A[l++]; // copy remain part into temp while(j <= n) temp[k++] = A[j++]; // only one will be executed for(j = 0; j < k; j++) A[m+j] = temp[j]; // move back }
Quick Sort Void quickSort(KeyType[] A, int m, int n) { if(m < n) { int p = partition(A, m, n); quickSort(A, m, p); quickSort(A, p+1, n); } }
int partition(KeyType[] A, int i, int j) { // O( j – i + 1) KeyType pivot, temp; int k, middle, p; middle = (m +n) /2; pivot = A[middle]; A[middle] = A[i]; A[i] = pivot; p = i; // place pivot in the A[i], p is the pivot position for(k = i+1; k <= j; k++) { if(A[k].compareTo(pivot) < 0) { // swap the smaller one to left sub array temp = A[++p]; A[p] = A[k]; A[k] = temp; } // loop invariant (A[I+1:p] < pivot && A[p+1:k] >= pivot) } temp = A[i]; A[i] = A[p]; A[p] = temp; return p; }
Quick Sort Performance • Average: O(n lg n) • Worst case: • if every time partition makes one sub array empty, the other size –1 • O(n ^ 2) • Why Quick Sort get the name? • Two times faster than HeapSort in average • Only one loop in partition • Coefficient less than other sort methods
Insertion Sort • Assume A’s left part already sorted up to k. • Insert a[k+1] into A[0:k] by: • Extract A[k+1] and save it in temp • Compare temp to A[j], j = 0..k, to find the right position j • Shift A[j:k] one position right • Insert temp into A[j] • O( )?
Address Calculation Sort • Proxmap sort – O(n) • Indexing – maps key domain into [0, n) • key (key – min(KEY))/(max(KEY) – min(KEY)) *n • Counting – number of keys in each slot • Positioning – shift position of each slot • Position(k) Count(k-1) • Inserting – each key into its sub array • using insertSort
Address Calculation Sort • Radix sort – O(n) • Sort a deck of cards • Each card is represented by <n, s> • where n [2, 3, …, 10, J, Q, K, A] • and s [Diamond, Club, Heart, Spear] • Separate cards by their shape • Put them back in order of shape • Separate them by number while maintain original order in each deck • Put them back in order of number