Hoare's Partition solves the Array Partition problem.
Here is an example of how partition might perform on a small array, with the assumption that the first element is the desired pivot.
Hoare’s Partition begins by selecting a pivot element, typically A[low].
It uses two pointers, i and j, to traverse the array.
Pointer i starts at low + 1, and pointer j starts at high.
The pointer i increments until it finds an element greater than the pivot (A[i] > pivot),
and pointer j decrements until it finds an element less than the pivot (A[j] < pivot).
When both out-of-place elements are identified, the algorithm swaps A[i] and A[j],
and then increments i and decrements j.
This process repeats until i ≥ j. Finally, the pivot element A[low]
is swapped with A[j], placing the pivot correctly at index j.
The partition index j is then returned.
Here is a step-by-step description.
A[low].i = low + 1j = highi ≥ j:
i forward until A[i] > pivot.j backward until A[j] < pivot.i < j, swap A[i] and A[j], then increment i and decrement j.A[low] with A[j].j.
Hoare’s algorithm kind of exemplifies the decrease-and-conquer paradigm since
as the pointers i and j move inward, elements are progressively
placed into their correct positions at the array's left and right portions,
shrinking the unsorted middle section with each iteration.
Thus, the size of the unsolved portion decreases with each iteration.
But generally speaking, it is difficult to categorize on its own.
Because it is used in Quick Sort, which is a divide-and-conquer
algorithm and Quick Select, which is a decrease-and-conquer algorithm,
I put it in the decrease-and-conquer category.
Here is one implementation of Hoare's Partition algorithm. There are many slight variations of the algorithm, so do not be surprised if you see versions that do not match this one exactly.
int partition(int[] A, int lo, int hi) {
int p = A[lo];
int i = lo + 1;
int j = hi;
while (true) {
while (i < hi && A[i] <= p) i++;
while (j > lo && A[j] >= p) j--;
if (j <= i) {
swap(A, lo, j);
return j;
} else {
swap(A, i, j);
i++;
j--;
}
}
}
void swap(int[] A, int i, int j) {
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
int partition(int A[], int lo, int hi) {
int p = A[lo];
int i = lo + 1;
int j = hi;
while (true) {
while (i < hi && A[i] <= p) i++;
while (j > lo && A[j] >= p) j--;
if (j <= i) {
swap(A, lo, j);
return j;
} else {
swap(A, i, j);
i++;
j--;
}
}
}
void swap(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
def partition(A, lo, hi):
p = A[lo]
i = lo + 1
j = hi
while True:
while i < hi and A[i] <= p:
i += 1
while j > lo and A[j] >= p:
j -= 1
if j <= i:
swap(A, lo, j)
return j
else:
swap(A, i, j)
i += 1
j -= 1
def swap(A, i, j):
A[i], A[j] = A[j], A[i]
Time Complexity: The algorithm consistently operates in linear time, O(n), because it involves two pointers traversing the array from opposite ends, moving toward each other until they cross. Each time a pointer moves, a constant number of operations is executed.
Compared to other partitioning methods like Lomuto’s scheme, Hoare's algorithm typically involves fewer swaps and fewer overall operations. Its efficiency arises from the bidirectional scanning of the array and performing swaps only when necessary.
Space Complexity: Hoare’s Partition algorithm operates in-place, requiring only constant additional space, O(1). The algorithm does not need auxiliary arrays or additional significant memory beyond a few pointers and temporary variables.
3 be a bad pivot value for the array [3,34,93,68,4,49,24,32,23,88,49]?[7, 4, 9, 6, 2, 8, 3] with low = 0 and high = 6,
apply Hoare's Partition with the pivot as the first element.
What does the array look like after partitioning, and what is the returned pivot index?
[2, 4, 3, 6, 7, 8, 9]
and the pivot (7) ends up at index 4.
[34, 23, 54, 21, 11, 45, 67, 89, 10], perform Hoare’s Partition step-by-step. Count and document each swap and comparison made.