Click here to Skip to main content
15,886,199 members
Articles / General Programming / Algorithms

Optimizing QuickSort

Rate me:
Please Sign up or sign in to vote.
2.75/5 (4 votes)
6 Jan 2011CPOL2 min read 38.1K   216   8   6
Some things we can do to make QuickSort more efficient

Introduction

In productivity, there are two variables which are always a concern: time and space. In terms of computing, these are speed and memory. QuickSort, as the overall fastest sorting algorithm, has had people combing over it for nearly 50 years, so there isn't really much left to do as far as directly increasing its speed. However, there remain several ways that we can optimize it so that it can make much better use of its memory.

Background

Just have a good interest in sorting algorithms, and an understanding of QuickSort.

Changes

C++
static void OptimizedQuickSort(ref int[] Arr, int Left, int Right)
{
    int Pivot;
    Pivot = Q_Sort(ref Arr, Left, Right);
    if(Left < Pivot - 1)
    {
        OptimizedQuickSort(ref Arr, Left, Pivot - 1);
    }
    if(Right > Pivot + 1)
    {
        OptimizedQuickSort(ref Arr, Pivot + 1, Right);
    }
}  

static int Q_Sort(ref int[] Arr, int Left, int Right)
{
    int Pivot;
    Pivot = Arr[Left];
    while(Left < Right)
    {
        while((Arr[Right] >= Pivot) && (Left < Right))
        {
            Right--;
        }
        if(Left != Right)
        {
            Arr[Left] = Arr[Right];
            Left++;
        }
        while((Arr[Left] <= Pivot) && (Left < Right))
        {
            Left++;
        }
        if(Left != Right)
        {
            Arr[Right] = Arr[Left];
            Right--;
        }
    }   
    Arr[Left] = Pivot;
    return Left;
}  

The biggest change I made was to separate QuickSort into two functions, so that, at first glance, it looks sort of like MergeSort. The idea for doing this is that instead of each new recursion copying the same code and using up more memory, it reuses the same code.
NOTE: This code only works properly when running a single thread. If you want to use QuickSort on multiple threads, use the standard version.

As a result of the algorithm being split up, we don't need a Temporary Left and Right variable in Q_Sort, because they are kept back in the original function that calls them, so the only variable we need in Q_Sort is the Pivot.

Next, if you look in the OptimizeQuickSort, you will see that I replaced the:

C#
if(Left < Pivot)   &&    if(Right > Pivot)  

with:

C#
if(Left < Pivot - 1)   &&    if(Right > Pivot + 1)   

My reasoning behind this is that, if there is one variable between Left and Pivot, then that variable must be Greater Than Left. What's more, it must be the only variable that is Less than Pivot that is greater than Left, so there is no reason to sort it. The same thing works for Pivot and Right.

End

Well, that's really all I've got. Just a few things that I think improve upon QuickSort, at least as far as managing memory. I would like to add that I have seen many other ways to make QuickSort more efficient, but nearly all of those advantages only worked on those languages, taking advantage of its features, whereas I wanted to work on the overall design.

If anyone can see any way to further improve upon what I've done here, or if you think this is a waste of time, let me know.

John

History

  • 6th January, 2011: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralOther optimisations Pin
jsc4210-Jan-11 4:37
professionaljsc4210-Jan-11 4:37 
Other optimisations include eliminating redundant recursive calls, minimising stack size and housekeeping overheads by doing the smallest partition first and using iteration rather than recursion for the 2nd partition. Also, whilst QS is good for reasonably large sets, it is not efficient for small sets (e.g. less than ~10 items) - for them, a simple bubble sort is often quicker; so you should check for small / trivial subsets before doing recursion.

The code below is a sample that I wrote years ago in QBASIC, just as an algorithm Proof-Of-Concept, which includes some of the above optimisations. (I am too lazy to convert to any popular 'modern' language!). It includes stack optimisations and simple code for trivial cases (but only for 2 or less items).

DIM Arr(12)
DATA 3,1,4,1,2,5,9,2,6,-1,27,42,0
FOR i = 0 TO 12: READ Arr(i): NEXT

QuickSort Arr()
FOR i = 0 TO 12: PRINT Arr(i); : NEXT: PRINT

' Sort already sorted (worst case scenario)
QuickSort Arr()
FOR i = 0 TO 12: PRINT Arr(i); : NEXT: PRINT

SUB QuickSort (Arr())
	QuickSortPartition Arr(), 0, UBOUND(Arr), 1
END SUB

SUB QuickSortPartition (Arr(), Lo, Hi, Depth)
	PRINT SPC(Depth * 3); "[ QSP("; Lo; ", "; Hi; ", "; Depth; ")"
	' Recursive / iterative routine to sort a partition of an array
	' This routine is optimised to minimise the no of concurrent depths of recursion and no of swaps
	DO WHILE Lo < Hi
		Pivot = Arr(Lo): i = Lo + 1: j = Hi: PivotN = Lo
		PRINT SPC(Depth * 3 + 3); "Do While "; Lo; " < "; Hi; " Pivot = "; Pivot

		IF Hi > i THEN  ' More than 2 elements
			WHILE i < j
				' Search right to left for value greater than pivot
				Temp = Arr(j)
				DO WHILE j > PivotN
					IF Temp > Pivot THEN
						j = j - 1: Temp = Arr(j)
					ELSE
						Arr(j) = Pivot: Arr(PivotN) = Temp: PivotN = j: EXIT DO
					END IF
				LOOP


				' Search left to right for value less than pivot
				Temp = Arr(i)
				DO WHILE i < PivotN
					IF Temp < Pivot THEN
						i = i + 1: Temp = Arr(i)
					ELSE
						Arr(i) = Pivot: Arr(PivotN) = Temp: PivotN = i: EXIT DO
					END IF
				LOOP
			WEND

			' Sort smallest subrange first
			IF PivotN - Lo > Hi - PivotN THEN
				IF Hi > PivotN + 1 THEN
					QuickSortPartition Arr(), PivotN + 1, (Hi), Depth + 1      ' Non-empty top partition
				END IF
				Hi = PivotN - 1
			ELSE
				IF Lo < PivotN - 1 THEN
					QuickSortPartition Arr(), (Lo), PivotN - 1, Depth + 1      ' Non-empty bottom partition
				END IF
				Lo = PivotN + 1
			END IF
		ELSE    ' Trivial cases
			IF Hi = i THEN
				Temp = Arr(Hi)
				IF Pivot > Temp THEN
					Arr(Lo) = Temp: Arr(Hi) = Pivot     ' 2 elements
				END IF
			END IF
			EXIT DO
		END IF
	LOOP
	PRINT SPC(Depth * 3); "] QSP("; Lo; ", "; Hi; ", "; Depth; ")"
END SUB

GeneralMy vote of 4 Pin
JustDownload29-Jan-11 9:27
JustDownload29-Jan-11 9:27 
General3 percent improvement in benchmark testing Pin
bob169729-Jan-11 3:53
bob169729-Jan-11 3:53 
GeneralMy vote of 3 Pin
Emilio Garavaglia7-Jan-11 6:10
Emilio Garavaglia7-Jan-11 6:10 
GeneralQuicksort Pin
T21026-Jan-11 22:15
T21026-Jan-11 22:15 
GeneralComments PinPopular
peterchen6-Jan-11 22:08
peterchen6-Jan-11 22:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.