Hello, curious learners! Today, we will embark on a journey through the Quick Sort world. Picture yourself organizing various items — like toys or books — by size or color. That's what Quick Sort does with spectacular speed. Are you ready to explore further? Fantastic! Let's get started.
Quick Sort is a clever algorithm invented by a British computer scientist named Tony Hoare in 1959. It uses a strategy called 'divide-and-conquer' to put elements in order. Quick Sort takes an array, selects a particular "pivot" element, and then places everything smaller than the pivot on one side and everything larger on the other.
Quick Sort has a three-step process:
- Pick a random "pivot" element from the array.
- Move all elements smaller than the pivot to one side and bigger ones to the other. This operation effectively divides the array into two parts, ensuring that all the elements will remain within their part until the end of the sorting process.
- Repeat steps 1 and 2 for each part until there are no more unsorted elements.
For example, if we have nine marbles numbered [3, 9, 4, 7, 5, 1, 6, 2, 8]
and our chosen marble, or pivot, is 7
, then after one round of sorting, we'll get [3, 4, 5, 1, 6, 2, 7, 9, 8]
. It seems this is a minor change, but now the pivot element is in its correct position, and we can consider the first half of the array [3, 4, 5, 1, 6]
and [9, 8]
separately as they won't ever intersect again.
Let's translate these steps into a concrete C++ program. We'll tackle it part by part. Our first step is to partition an array around a pivot. In C++, we need to write a function, let's call it partition()
, to handle this:
C++1int partition(int arr[], int start, int end) { 2 int pivot = arr[end]; // choosing the last element as pivot 3 int i = start - 1; // marking the index of the smaller element 4 5 for (int j = start; j < end; j++) { 6 // checking if the current element is smaller than the pivot 7 if (arr[j] <= pivot) { 8 i++; 9 // swap arr[i] and arr[j] 10 std::swap(arr[i], arr[j]); 11 } 12 } 13 return i + 1; // placeholder, will update in next section 14}
In this segment of the code, we selected the last element as the pivot and placed smaller elements on the left.
- The function starts by initializing
i
to one index before thestart
. Thisi
basically keeps track of the latest position where an element has been swapped because it was less than or equal to the pivot. Ifarr[j]
is less than or equal to the pivot,i
is incremented and thenarr[j]
is swapped witharr[i]
. Essentially, smaller elements are pushed toward the front of the array (or the given part of the array).
The start
and end
parameters control which part of the given array is under the partition operation. Using these parameters, we can apply the partition to some part of the array, which will be helpful later.
After partitioning, we still need to place the pivot properly in the already partitioned list. Let's finalize the partition()
function:
C++1 // Swap arr[i+1] and arr[end] (or pivot) 2 std::swap(arr[i + 1], arr[end]); 3 4 return i + 1; // return the partition point 5}
Now our partition()
function is complete! It partitions the array around the pivot and ensures it is in its correct position.
Next up is the quickSort()
function. It will use our partition()
function to sort the left and right portions of the array recursively. Let's code that step by step. First, it should call the partitioning process:
C++1void quickSort(int arr[], int start, int end) { 2 if (start < end) { 3 int pivotIndex = partition(arr, start, end); 4 // Ready to split! 5 } 6}
This function has yet to do much, but it's a strong start. We've managed to partition our list around a pivot point.
We must teach our quickSort()
function to keep sorting smaller and larger partitions. We do this by simply calling itself recursively for these partitions:
C++1void quickSort(int arr[], int start, int end) { 2 if (start < end) { 3 int pivotIndex = partition(arr, start, end); 4 quickSort(arr, start, pivotIndex - 1); // sort left part 5 quickSort(arr, pivotIndex + 1, end); // sort right part 6 } 7}
And that's it! Our Quick Sort implementation is complete. It initially partitions the array and then continues sorting each partition until everything is sorted.
The efficiency or "time complexity" of Quick Sort varies. When sorting items, usually the more unique items, the quicker it is. In the "best" and "average" situations, Quick Sort works like a charm with a time complexity of . However, in the "worst" situation, where many items are the same (like a pile of identical blocks), it may take more time, resulting in a time complexity of .
Great job! We've untangled the concept of Quick Sort, broken it down piece by piece, and implemented it in C++. Now comes the fun part: we will reinforce what you've learned with practical exercises. Ready to dive in?