VIEWS: 11 PAGES: 11 POSTED ON: 5/14/2011 Public Domain
Quick Sorting (Chapter 11) Quick Sort So far, we have learned quite a few algorithms for sorting: Bubble sort, selection sort, insertion sort and merge sort. Here, we are going to learn yet another algorithm for sorting objects. 1 Recall that in merge sort, we use an approach called divide- and-conquer. This approach is also used in quick sort. Suppose we have a sequence S. 1. Divide: If S has at least two elements (nothing needs to be done if S has zero or one element), select a specific element x from S, which is called the pivot. As is common practice, choose the pivot x to be the last element in S. Remove all the elements from S and put them into three sequences: 1) L, storing the elements in S less than x 2) E, storing the elements in S equal to x 3) G, storing the elements in S greater than x. Of course, if the elements of S are all distinct, then E holds just one element - the pivot itself. 2. Recur: Recursively sort sequence L and G. 3. Conquer: Put back the elements into S in order by first inserting the elements of L, then those of E, and finally those of G. Example: We have a sequence (85, 24, 63, 45, 17, 31, 96, 50). It is difficult to sort in one step. So we pick the number 50 (pivot) and divide elements into three sequences: (24, 45, 17, 31), (50), and (85, 63, 96). Now the problem becomes that we need to sort these three sequences. However, they are smaller and hopefully easier to sort. 2 Now we take the first sequence (24, 45, 17, 31) and see that it is still too complicated to sort in one step. So we pick the number 31 as a pivot and split the sequence further into three sequences (24, 17), (31), and (45). Now two sequences (31) and (45) are easy enough to sort (they are trivially sorted.) The sequence (24, 17), however, is still complicated. Again, we pick the number 17 as a pivot and split the sequence into three sequences (), (17), and (24). Now all these smaller sequences are sorted. We now need to put them together. The result is (17, 24). Next, we put sequences (17, 24), (31), and (45) together. The result is (17, 24, 31, 45). Similarly, the sequence (85, 63, 96) will be sorted. The result is (63, 85, 96). So we put the sequences (17, 24, 31, 45), (50) and (63, 85, 96) together to have a sorted sequence: (17, 24, 31, 45, 50, 63, 85, 96). 3 The figure here shows how the sequence is divided into smaller sequences and pivots. 85 24 63 45 17 31 96 50 24 45 17 31 85 63 96 24 17 45 85 63 24 85 The figure here shows how the sequences merged. 17 24 31 45 50 63 85 96 17 24 31 45 63 85 96 pivot 50 pivot 31 17 24 45 63 85 pivot 96 24 pivot 17 85 pivot 63 4 In-Place Quick Sort in-place: Use only a constant amount of memory space in additional to the sequence itself. Instead of transfering elements in and out of a memory block, we simply rearrange them. Recall that in the step of divide-and-conquer, we split the sequence into three groups: a pivot, a sequence containing elements less then the pivot, and a sequence containing elements greater than the pivot. Let us see how this is done by rearranging the elements within the sequence. What do we want: The two smaller sequences are separated by the pivot. For example: 31 24 17 45 50 85 96 63 How can we do it: Using two indices, starting from both ends. We search for a pair of elements such that one is smaller than the pivot and the other is larger than the pivot. Then, swap them. We repeat this process until the two indices meet. 85 24 63 45 17 31 96 50 l r 5 Algorithm inPlaceQuickSort(S, a, b) Input: Sequence S of elements; integers a and b Output: Sequence S with elements originally from ranks from a to b, inclusive, sorted in nondecreasing order from ranks a to b if a is greater than or equal to b return assign the element at rank b to variable p (pivot) assign a to variable l assign b - 1 to variable r while l is less than or equal to r while l is less than or equal to r and the element at rank l is less than or equal to p increase l by 1 while r is greater than or equal to l and the element at rank r is greater than or equal to p decrease r by 1 if l is less than r swap the elements at ranks l and r swap the elements at ranks l and b inPlaceQuickSort(S, a, l - 1) inPlaceQuickSort(S, l + 1, b) 6 Example: 85 24 63 45 17 31 96 50 l r 85 24 63 45 17 31 96 50 l r 31 24 63 45 17 85 96 50 l r 31 24 63 45 17 85 96 50 l r 31 24 17 45 63 85 96 50 l r 31 24 17 45 63 85 96 50 r l 31 24 17 45 50 85 96 63 r l 7 Java implementation public static void quickSort( Sequence S, Comparator c ) { if( S.size() < 2 ) return; quickSortStep( S, c, 0, S.size() - 1 ); } private static void quickSortStep( Sequence S, Comparator c, int leftBound, int rightBound ) { if( leftBound >= rightBound ) return; Object pivot = S.atRank( rightBound ).element(); int leftIndex = leftBound; int rightIndex = rightBound - 1; while(( leftIndex <= rightIndex ) { while(( leftIndex <= rightIndex ) && c.isLessThanorEqualTo( S.atRank( leftIndex ).element(), pivot )) leftIndex++; while((rightIndex >= leftIndex ) && c.isGreaterThanorEqualTo( S.atRank( rightIndex ).element(), pivot )) rightIndex--; if( leftIndex < rightIndex ) S.swapElements( S.atRank( leftIndex ), S.atRank( rightIndex )); } S.swapElements( S.atRank( leftIndex ), S.atRank( rightBound )); quickSortStep( S, c, leftBound, leftIndex - 1 ); quickSortStep( S, c, leftBound + 1, rightBound ); } 8 The running time of quick sort is proportional to the square of n, the size of the sequence: O(n2). Average running time: O(nlogn). In practice, the quick sort works better than the merge sort. Lab 9: import java.lang.*; public class QuickSorter { public static void quickSort (Integer[] S, Comparator c) { if (S.length < 2) return; // the array is already sorted in this case quickSortStep(S, c, 0, S.length-1); // recursive sort method } private static void quickSortStep (Object[] S, Comparator c, int leftBound, int rightBound ) { if (leftBound >= rightBound) return; // the indices have crossed Object temp; // temp object used for swapping Object pivot = S[rightBound]; int leftIndex = leftBound; // will scan rightward int rightIndex = rightBound-1; // will scan leftward while (leftIndex <= rightIndex) { // scan right until larger than the pivot while ( (leftIndex <= rightIndex) && (c.compare(S[leftIndex], pivot)<=0) ) leftIndex++; 9 // scan leftward to find an element smaller than the pivot while ( (rightIndex >= leftIndex) && (c.compare(S[rightIndex], pivot)>=0)) rightIndex--; if (leftIndex < rightIndex) { // both elements were found temp = S[rightIndex]; S[rightIndex] = S[leftIndex]; // swap these elements S[leftIndex] = temp; } } // the loop continues until the indices cross temp = S[rightBound]; // swap pivot with the element at leftIndex S[rightBound] = S[leftIndex]; S[leftIndex] = temp; // the pivot is now at leftIndex, so recurse quickSortStep(S, c, leftBound, leftIndex-1); quickSortStep(S, c, leftIndex+1, rightBound); } public static void main (String[] args) { int k = 0; Integer[] nums = new Integer[10]; System.out.println("Quick sorting:" + "\n"); System.out.println("Input sequence:" + "\n"); //Create an array to hold numbers for(int i = 0; i < nums.length; i++) {k = (int) (Math.random()*100); //Generate random numbers nums[i] = new Integer(k); System.out.print(k + " "); } System.out.println(); 10 System.out.println(); System.out.println(); Comparator c = new Comparator(); quickSort(nums, c); //Sort them System.out.println("Result:" + "\n"); for (int j = 0; j < nums.length; j++) //Print them out System.out.print(nums[j].intValue() + " "); System.out.println(); } } 11