Skip to content

Commit 64375b3

Browse files
Merge pull request #3 from Sphesihlebjamile/sort/quick-sort
Quick Sort Algorithm
2 parents 8308a41 + fbeae25 commit 64375b3

4 files changed

Lines changed: 137 additions & 3 deletions

File tree

src/com/sketch/Main.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package com.sketch;
22

3-
import com.sketch.sort.selectionsort.SelectionSort;
3+
import com.sketch.sort.quicksort.QuickSort;
44

55
import java.util.Arrays;
66
import java.util.Random;
77

88
public class Main {
99
public static void main(String[] args){
10-
int[] unsortedArray = new int[20];
10+
int[] unsortedArray = new int[100];
1111
Random random = new Random();
1212
for(int i = 0; i < unsortedArray.length; i++){
1313
unsortedArray[i] = random.nextInt(20);
@@ -16,7 +16,7 @@ public static void main(String[] args){
1616
int[] unsortedArrayResult = new int[unsortedArray.length];
1717
System.arraycopy(unsortedArray, 0, unsortedArrayResult, 0, unsortedArray.length);
1818

19-
unsortedArrayResult = SelectionSort.sort(unsortedArrayResult);
19+
QuickSort.sort(unsortedArrayResult, 0, unsortedArrayResult.length - 1);
2020

2121
System.out.println("Actual Value Index: " + Arrays.toString(unsortedArray));
2222
System.out.println("Actual Value Index: " + Arrays.toString(unsortedArrayResult));
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.sketch.sort.quicksort;
2+
3+
import java.util.Random;
4+
5+
public class QuickSort {
6+
public static void sort(int[] unsortedArray, int lowIndex, int highIndex){
7+
if(lowIndex >= highIndex){
8+
return;
9+
}
10+
int pivotIndex = new Random().nextInt(highIndex - lowIndex) + lowIndex;
11+
int pivot = unsortedArray[pivotIndex];
12+
swap(unsortedArray, pivotIndex, highIndex);
13+
int leftPointer = partition(unsortedArray, lowIndex, highIndex, pivot);
14+
15+
sort(unsortedArray, lowIndex, leftPointer - 1);
16+
sort(unsortedArray, leftPointer + 1, highIndex);
17+
}
18+
19+
private static int partition(int[] unsortedArray, int lowIndex, int highIndex, int pivot){
20+
int leftPointer = lowIndex;
21+
int rightPointer = highIndex;
22+
23+
while(leftPointer < rightPointer){
24+
while (unsortedArray[leftPointer] <= pivot && leftPointer < rightPointer){
25+
leftPointer++;
26+
}
27+
while(unsortedArray[rightPointer] >= pivot && leftPointer < rightPointer){
28+
rightPointer--;
29+
}
30+
swap(unsortedArray, leftPointer, rightPointer);
31+
}
32+
swap(unsortedArray, leftPointer, highIndex);
33+
34+
return leftPointer;
35+
}
36+
37+
private static void swap(int[] array, int a, int b){
38+
int temp = array[a];
39+
array[a] = array[b];
40+
array[b] = temp;
41+
}
42+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Quick Sort Algorithm
2+
**QuickSort** is a sorting algorithm based on the Divide and Conquer that picks an element as a pivot and partitions the given array around the picked pivot by placing the pivot in its correct position in the sorted array.
3+
4+
There are mainly three steps in the algorithm:
5+
6+
1. **Choose a Pivot:** Select an element from the array as the pivot. The choice of pivot can vary (e.g., first element, last element, random element, or median).
7+
2. **Partition the Array:** Re arrange the array around the pivot. After partitioning, all elements smaller than the pivot will be on its left, and all elements greater than the pivot will be on its right.
8+
3. **Recursively Call:** Recursively apply the same process to the two partitioned sub-arrays.
9+
4. **Base Case:** The recursion stops when there is only one element left in the sub-array, as a single element is already sorted.
10+
11+
![img.png](img.png)
12+
- Implementation: [QuickSort.java](./QuickSort.java)
13+
14+
## Partition Algorithm
15+
The key process in quickSort is a partition() algorithm/function. There are three common algorithms to partition. All these algorithms have O(n) time complexity.
16+
1. **Naive Partition**: Here we create copy of the array. First put all smaller elements and then all greater. Finally we copy the temporary array back to original array. This requires O(n) extra space.
17+
2. **Lomuto Partition**: We have used this partition in this article. This is a simple algorithm, we keep track of index of smaller elements and keep swapping.
18+
3. **Hoare's Partition**: This is the fastest of all. Here we traverse array from both sides and keep swapping greater element on left with smaller on right while the array is not partitioned.
19+
20+
The **Lomuto Partition** is the most simplest one of the 3, but in our [implementation](./QuickSort.java) we used **Hoare's Partition** because it is the fastest of them all.
21+
It is documented below.
22+
23+
## Hoare's Algorithm
24+
Given an array **arr[]**, that task is to *partition* the array by assuming first element as **pivot element**.
25+
The partition of an array must satisfy the following two conditions:
26+
- Elements smaller than pivot element must appear at index less than or equal to partition index.
27+
- Elements larger than or equal to pivot element must appear at index greater than partition index.
28+
29+
Partition index is equal to count of elements, strictly smaller than pivot, minus one.
30+
31+
```text
32+
Input: arr[] = [5, 3, 8, 4, 2, 7, 1, 10]
33+
Output: [1, 3, 2, 4, 8, 7, 5, 10]
34+
Explanation: The partition index is 3 and pivot element is 5, all elements smaller than pivot element [1, 3, 2, 4] were arranged before partition index and elements larger than or equal to pivot [8, 7, 5, 10] were arranged after partition index.
35+
36+
Input: arr[] = [12, 10, 9, 16, 19, 9]
37+
Output: [9, 10, 9, 16, 19, 12]
38+
Explanation: The partition index is 2 and pivot element is 12, all elements smaller than pivot element [9, 10, 9] were arranged before or at partition index and elements larger than or equal to pivot [16, 19, 12] were arranged after partition index.
39+
```
40+
41+
This partition algorithm performs in **O(n)** time and **O(1)** space.
42+
43+
Step-by-step execution of algorithm:
44+
- Consider the first element as the pivot and initialise two pointers, i at the start and j at the end of the array.
45+
- Move i to the right until an element greater than or equal to the pivot is found, and move j to the left until an element less than or equal to the pivot is found.
46+
- If i points to an element greater than or equal to the pivot and j points to an element less than or equal to the pivot, swap them.
47+
- Repeat the process, moving i and j toward each other until they meet or cross.
48+
- When the pointers cross, the partitioning is complete, with elements less than or equal to the pivot on the left and those greater than or equal to the pivot on the right.
49+
50+
Interesting facts:
51+
- Hoare's Partition Algorithm is generally faster than Lomuto's because it performs fewer swaps and makes only one traversal of the array, leading to better time complexity in practice.
52+
- It works in-place and does not require extra space, unlike the naive partitioning method which uses a temporary array.
53+
- It can be used to implement a stable version of Quick Sort with the right adjustments, though it is not inherently stable.
54+
- We can easily modify the algorithm to consider the first element (or any other element) as pivot by swapping first and last elements and then using the same code.
55+
56+
## Choice of Pivot
57+
There are many different methodologies for selecting a pivot.
58+
- Always picking the first (or last) element as a pivot results in a problem where the approach ends up in the worst case scenario if the array is already sorted.
59+
- Picking a random element as a pivot is the preferred approach because it does not have a pattern for which the worst case happens.
60+
- Picking the median element as a pivot:
61+
- This is an ideal apprach in terms of time complexity as we can find median in linear time and the partition function will always divide the input array into two halves.
62+
- But it takes more time on average as median finding has high constants.
63+
64+
## Complexity Analysis
65+
- Time Complexity:
66+
- Best Case: **_(Ω(n log n))_**, Occurs when the pivot element divides the array into two equal halves.
67+
- Average Case: **_(θ(n log n))_**, On average, the pivot divides the array into two parts, but not necessarily equal.
68+
- Worst Case: **_(O(n²))_**, Occurs when the smallest or largest element is always chosen as the pivot (e.g., sorted arrays).
69+
- Auxiliary Space:
70+
- Worst Case: **_O(n)_** due to unbalanced partitioning leading to a skewed recursion tree requiring a call stack of size O(n).
71+
- Best Case: **_O(log n)_** as a result of balanced partitioning leading to a balanced recursion tree with a call stack of size O(log n).
72+
73+
## Advantages & Disadvantages
74+
### Advantages
75+
- It is a divide-and-conquer algorithm that makes it easier to solve problems.
76+
- It is efficient on large data sets.
77+
- It has a low overhead, as it only requires a small amount of memory to function.
78+
- It is Cache Friendly as we work on the same array to sort and do not copy data to any auxiliary array.
79+
- Fastest general purpose algorithm for large data when stability is not required.
80+
81+
### Disadvantages
82+
- It has a worst-case time complexity of O(n2), which occurs when the pivot is chosen poorly.
83+
- It is not a good choice for small data sets.
84+
- It is not a stable sort, meaning that if two elements have the same key, their relative order will not be preserved in the sorted output in case of quick sort, because here we are swapping elements according to the pivot's position (without considering their original positions).
85+
86+
## Application of Quick Sort
87+
- Sorting large datasets efficiently in memory.
88+
- Used in library sort functions (like C++ std::sort and Java Arrays.sort for primitives).
89+
- Arranging records in databases for faster searching.
90+
- Preprocessing step in algorithms requiring sorted input (e.g., binary search, two-pointer techniques)
91+
- Sorting arrays of objects based on multiple keys (custom comparators).
92+
- Graphics and computational geometry (e.g., convex hull algorithms).
116 KB
Loading

0 commit comments

Comments
 (0)