(
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.