Understanding the QuickSort Algorithm
Provides an implementation and explanation of the quicksort algorithm.
The file that goes along with this article contains documented code examples for the QuickSort, one written in C and the other in QuickBASIC.
[size="5"]How it Works
The QuickSort is a recursive function that works using a "divide and conquer" method. It chooses one element, called the partition element, then shifts the elements of the array so that everything less than the partition element comes before it in the array, and everything greater than the partition element comes after it. The partition element is then at its permanent place in the array, and QuickSort calls itself twice: once to sort the upper half of the array, and once to sort the bottom half.
A QuickSort function should take two parameters, which we'll call high and low, that represent the upper and lower bounds of the portion of the array to be sorted. It then performs a few checks. First, if high is less than low, QuickSort does nothing. Then, if high and low represent array elements that are right next to each other sequentially, they are compared and swapped if necessary. If neither of these conditions is true, the main body of the function goes to work.
A partition element is chosen. The choice is irrelevant; you can make it whatever you want. In the included code examples, I have chosen it to be the center element, or the closest integer to (high + low) / 2. The partition element is temporarily swapped with the last element of the array segment. Now we set up two 'pointers', which I'll call top and bottom. These are used to keep track of where we are in the array. The bottom pointer is initialized to low, and the top pointer is initialized to (high - 1), since the array element at high is the partition element, and we just want to leave that alone for now.
The pointers are moved in the following manner. First, bottom is incremented until one of two things happens: an array element is encountered which is greater than the partition element, or bottom > top. Second, top is decremented until either an array element is encountered which is less than the partition element, or bottom > top. Once both of the pointers have been moved appropriately, if bottom is still less than top, the elements they point to are swapped. But if bottom is greater than or equal to top, the pointers have met, and the iteration ends. At this point, the partition element is swapped with the location where the bottom pointer ended up. The partition element is now fixed in its final position within the array, since all elements above it are less than it, and all elements below it are greater.
The array is not sorted yet, though; only the partition element has taken its final place. So now, QuickSort calls itself twice. The first call sorts the first half of the array, which is from positions low to (bottom - 1). The second call sorts the last half of the array, which is from positions (bottom + 1) to high. In this manner, the sizes of the partitions passed to QuickSort get less and less, until eventually, every element in the array has been sorted.
[size="5"]Performance
Well, they don't call it a QuickSort for nothing. The QuickSort is an excellent way to get things ordered in a hurry, but there are some cases where other options may be better. This algorithm is best used with large numbers of elements. If all you have is an array of twenty elements, you'll probably be just as happy with something simple like an insertion sort, and that's a lot easier to implement. The other case in which you may want to use another method is when you know that your data are going to be very close to sorted before applying the algorithm. In this case, the insertion sort is also a good way to go.
One thing I should mention for DOS users in particular... recursive functions are a fantastic way to run out of stack space. So don't be surprised if you try to QuickSort 20,000 integers and you come up against a memory problem! This is another time when it would be best to find another sort routine, one that is non-recursive. A shell sort might be a good option here.
This is my first attempt at an article for GameDev.net, so let me know how I'm doing! Send questions, comments, or hate mail to [email="jdfarrell@students.wisc.edu"]jdfarrell@students.wisc.edu[/email].
Related Tutorials
Balancing Game Development and Creative Direction in Indie Production
A practical look at how indie developers can balance creative direction with hands-on game development. This article co…
My Unreal Engine Development Process: From Core Idea to Playable Build
A practical overview of my Unreal Engine development process, covering how I move from a core game idea to a playable b…
Introducing LaneGraph: The Ultimate Road Network Solution for Unity
Discover the power of LaneGraph, a lightweight and flexible lane-based navigation system for Unity. LaneGraph makes it…
Retargeting Mixamo Characters with Root Motion In Unreal Engine 5.4.
I have always found Retargeting Mixamo Characters To have Root Motion is a serious lengthy Tast, Recently I stumbled up…
How To Make A SIMPLE Main Menu In Unity
In this tutorial for unity, i go over how to make a simple main menu for unity, it's an unlisted video because i do not…
Guide to Gameplay Balance
A perspective on competitive gameplay balance, from a background of "shooter" sandbox design.
Discussion
More from Joe Farrell
Comparing Shadow Mapping Techniques with Shadow Explorer
New Incentives and a Whole New Platform From The Intel AppUp developer program
The final installment in this series on Intel's AppUp program details additional incentives and opportunities for devel…
The Game Maker
This book excerpt contains the first chapter of the book that introduces beginning game developers to the Game Maker pr…
Discussion