( Latest Revision: 10/02/2005 )

CS 3100 Handout on Managing the stack when doing Quick Sort


Doing a recursive quick sort that manages the runtime stack: Procedure Qsort (lo, hi) ; BEGIN /* This loop is used to eliminate the second recursive call. */ /* This algorithm keeps the runtime stack limited to size O(logN). */ WHILE (hi > lo) DO BEGIN Partition (lo, hi, splitPoint) ; /* if the right half is larger */ IF (hi-splitPoint) > (splitPoint-lo) THEN BEGIN Qsort (lo, splitPoint - 1) ; /* do the small (left) problem */ lo := splitPoint + 1 END ELSE BEGIN Qsort(splitPoint + 1, hi) ; /* do the small (right) problem */ hi := splitPoint - 1 END END END ;
Doing a non-recursive quick sort that manages the "save-stack": Push ({1, n}) ; REPEAT Pop ({lo,hi}) ; WHILE lo < hi BEGIN Partition (lo, hi, splitPoint) ; /* if the right half is larger */ IF (hi-splitPoint) > (splitPoint-lo) THEN BEGIN Push({splitPoint + 1, hi}) ; /* put the big problem on the stack */ hi := splitPoint - 1 /* go to work on the small problem */ END ELSE BEGIN Push({lo, splitPoint - 1}) ; /* put the big problem on the stack */ lo := splitPoint + 1 /* go to work on the small problem */ END END ; /* while */ UNTIL stack is empty
You can also improve quicksort by making the 'base case' a list of size 10 or so. After this 'quicksort' terminates, the list will probably not be sorted, but will consist of a sequence of contiguous 'runs' of 10 or fewer array elements. For each run X which is to the left of a run Y, all the elements in run X are less (or equal) to all the elements in Y. The 'trick' is to perform insertion sort on the array next. The insertion sort will sort the array very quickly because no element needs to move outside its 'run.' This way of putting all the 'runs' into order is much more efficient than doing it by allowing the quicksort procedure to work its way down to the lowest levels.