Skip to content

Commit 08a9e4e

Browse files
Enhance QuickSort documentation and structure
Updated QuickSort implementation with detailed comments and improved clarity.
1 parent 2c4bf3c commit 08a9e4e

File tree

1 file changed

+128
-19
lines changed

1 file changed

+128
-19
lines changed
Lines changed: 128 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,186 @@
11
package com.thealgorithms.sorts;
22

33
/**
4+
* QuickSort Algorithm Implementation
5+
*
6+
* QuickSort is a highly efficient sorting algorithm that uses the divide-and-conquer approach
7+
* to sort elements. It was developed by C. A. R. Hoare and is commonly used in practice because
8+
* of its efficiency and in-place sorting capability.
9+
*
10+
* When to use QuickSort:
11+
* - When you need in-place sorting (O(log n) extra space on average)
12+
* - When average-case performance is important (O(n log n))
13+
* - When you need to sort large datasets efficiently
14+
* - When stability is not required
15+
*
16+
* When NOT to use QuickSort:
17+
* - When stability is required (use MergeSort instead)
18+
* - When worst-case O(n^2) performance is unacceptable (use HeapSort or MergeSort)
19+
* - When working with nearly sorted data (consider insertion sort or adaptive sorts)
20+
*
21+
* Complexity Analysis:
22+
* - Best Case: O(n log n) - when pivot divides array into two nearly equal parts
23+
* - Average Case: O(n log n) - expected behavior with random pivot selection
24+
* - Worst Case: O(n^2) - when pivot is always smallest/largest element (rare with random selection)
25+
* - Space Complexity: O(log n) - for recursion stack in average case, O(n) in worst case
26+
*
27+
* Characteristics:
28+
* - In-place sorting algorithm (minimal extra space required)
29+
* - Not stable (relative order of equal elements may change)
30+
* - Uses randomized pivot selection to avoid worst-case scenarios
31+
* - Cache-friendly due to good memory access patterns
32+
*
433
* @author Varun Upadhyay (https://github.com/varunu28)
534
* @author Podshivalov Nikita (https://github.com/nikitap492)
635
* @see SortAlgorithm
736
*/
837
class QuickSort implements SortAlgorithm {
938

1039
/**
11-
* This method implements the Generic Quick Sort
40+
* Main entry point for Quick Sort algorithm
41+
* This method implements the generic Quick Sort for arrays of comparable objects.
42+
* The algorithm works by selecting a pivot element and partitioning the array
43+
* into elements smaller and larger than the pivot, then recursively sorting each partition.
1244
*
13-
* @param array The array to be sorted Sorts the array in increasing order
45+
* @param array The array to be sorted. Sorts the array in increasing order.
46+
* The array is modified in-place.
47+
* @return The sorted array (same reference as input, modified in-place)
48+
* @param <T> Generic type that must extend Comparable to allow element comparison
1449
*/
1550
@Override
1651
public <T extends Comparable<T>> T[] sort(T[] array) {
52+
// Start the recursive sorting process from index 0 to array.length - 1
1753
doSort(array, 0, array.length - 1);
1854
return array;
1955
}
2056

2157
/**
22-
* The sorting process
58+
* Recursive helper method that performs the actual QuickSort sorting process.
59+
* This method divides the array into smaller subarrays and recursively sorts them.
60+
* The division is done using the partition method.
2361
*
24-
* @param left The first index of an array
25-
* @param right The last index of an array
26-
* @param array The array to be sorted
62+
* How it works:
63+
* 1. If left >= right, the subarray has 0 or 1 element, so it's already sorted
64+
* 2. Use randomPartition to find a pivot position that divides the array
65+
* 3. Recursively sort the left subarray (elements < pivot)
66+
* 4. Recursively sort the right subarray (elements >= pivot)
67+
*
68+
* @param array The array being sorted
69+
* @param left The leftmost index of the current subarray
70+
* @param right The rightmost index of the current subarray
71+
* @param <T> Generic type that must extend Comparable
2772
*/
2873
private static <T extends Comparable<T>> void doSort(T[] array, final int left, final int right) {
74+
// Base case: if left >= right, the subarray has 0 or 1 element (already sorted)
2975
if (left < right) {
76+
// Partition the array and get the final position of the pivot
3077
final int pivot = randomPartition(array, left, right);
78+
79+
// Recursively sort the left partition (elements smaller than pivot)
80+
// Sort from left to pivot - 1 since element at pivot is now in final position
3181
doSort(array, left, pivot - 1);
82+
83+
// Recursively sort the right partition (elements greater than or equal to pivot)
84+
// Sort from pivot to right since element at pivot is in final position
3285
doSort(array, pivot, right);
3386
}
3487
}
3588

3689
/**
37-
* Randomize the array to avoid the basically ordered sequences
90+
* Selects a random pivot position and partitions the array around it.
91+
* Using a random pivot helps avoid the O(n^2) worst-case scenario that occurs
92+
* when the pivot is always the smallest or largest element (common with sorted data).
93+
*
94+
* The randomization strategy:
95+
* - Generates a random index between left and right (inclusive)
96+
* - Swaps the element at random index with the element at right position
97+
* - Then performs standard partition with the element at right as pivot
98+
* This ensures we avoid worst-case scenarios on already sorted or reverse sorted arrays
3899
*
39-
* @param array The array to be sorted
40-
* @param left The first index of an array
41-
* @param right The last index of an array
42-
* @return the partition index of the array
100+
* @param array The array being partitioned
101+
* @param left The leftmost index of the current subarray
102+
* @param right The rightmost index of the current subarray
103+
* @return The final partition index where the pivot element is now positioned
104+
* @param <T> Generic type that must extend Comparable
43105
*/
44106
private static <T extends Comparable<T>> int randomPartition(T[] array, final int left, final int right) {
107+
// Generate a random index between left and right (inclusive)
108+
// The formula: left + random_value ensures the index falls within [left, right]
45109
final int randomIndex = left + (int) (Math.random() * (right - left + 1));
110+
111+
// Swap the element at randomIndex with the element at right position
112+
// This moves our randomly selected pivot to the right for standard partition
46113
SortUtils.swap(array, randomIndex, right);
114+
115+
// Perform standard partition with the element at right as the pivot
47116
return partition(array, left, right);
48117
}
49118

50119
/**
51-
* This method finds the partition index for an array
120+
* Partitions the array around a pivot element.
121+
* This is the core logic of QuickSort that divides the array into two regions:
122+
* - Elements smaller than or equal to pivot (on the left)
123+
* - Elements greater than pivot (on the right)
124+
*
125+
* Partitioning Strategy (Two-pointer approach):
126+
* 1. Choose the middle element as pivot to improve performance on sorted arrays
127+
* 2. Initialize left pointer at the start and right pointer at the end
128+
* 3. Move left pointer right until finding an element >= pivot
129+
* 4. Move right pointer left until finding an element < pivot
130+
* 5. If pointers haven't crossed, swap the elements (move them to correct sides)
131+
* 6. Continue until pointers meet or cross
132+
* 7. Return the position where the pivot is finally placed
133+
*
134+
* Time Complexity of this method: O(n) where n is the size of the subarray
135+
*
136+
* Example:
137+
* Array: [3, 7, 2, 9, 1, 5] with pivot = 5 (middle element at index 2)
138+
* After partition: [3, 2, 1, 5, 9, 7] where 5 is at its final sorted position
52139
*
53-
* @param array The array to be sorted
54-
* @param left The first index of an array
55-
* @param right The last index of an array Finds the partition index of an
56-
* array
140+
* @param array The array being partitioned
141+
* @param left The starting index of the current partition
142+
* @param right The ending index of the current partition
143+
* @return The index where the pivot element ends up after partitioning
144+
* @param <T> Generic type that must extend Comparable
57145
*/
58146
private static <T extends Comparable<T>> int partition(T[] array, int left, int right) {
147+
// Select the middle element as the pivot
148+
// Using middle element improves performance on partially sorted data
149+
// The >>> operator is unsigned right shift, equivalent to (left + right) / 2 but avoids overflow
59150
final int mid = (left + right) >>> 1;
60151
final T pivot = array[mid];
61-
152+
153+
// Two-pointer partitioning approach
154+
// Loop continues while left and right pointers haven't crossed each other
62155
while (left <= right) {
156+
// Move left pointer right until we find an element >= pivot
157+
// All elements to the left of final left position will be < pivot
63158
while (SortUtils.less(array[left], pivot)) {
64159
++left;
65160
}
161+
162+
// Move right pointer left until we find an element < pivot
163+
// All elements to the right of final right position will be >= pivot
66164
while (SortUtils.less(pivot, array[right])) {
67165
--right;
68166
}
167+
168+
// If pointers haven't crossed, swap the elements
169+
// This places the smaller element on the left side and larger on the right side
69170
if (left <= right) {
171+
// Perform the swap to move elements to their correct sides relative to pivot
70172
SortUtils.swap(array, left, right);
71-
++left;
72-
--right;
173+
174+
// Move pointers to continue partitioning
175+
++left; // Move left pointer right
176+
--right; // Move right pointer left
73177
}
74178
}
179+
180+
// Return the final position of the left pointer
181+
// This is where we'll place the pivot in the next recursive step
182+
// Elements [original_left...left-1] are < pivot
183+
// Elements [left...original_right] are >= pivot
75184
return left;
76185
}
77186
}

0 commit comments

Comments
 (0)