Skip to content

Commit dc9d377

Browse files
author
LUKMANul
committed
Add deterministic QuickSelect (Median of Medians)
1 parent 9484c7e commit dc9d377

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package com.thealgorithms.divideandconquer;
2+
3+
import java.util.Arrays;
4+
5+
/**
6+
* QuickSelect algorithm using the Median of Medians method.
7+
*
8+
* <p>This algorithm finds the kth smallest element in an unsorted array in
9+
* O(n) worst-case time complexity.
10+
*
11+
* <p>Steps:
12+
* <ol>
13+
* <li>Divide the array into groups of five elements each.</li>
14+
* <li>Find the median of each group.</li>
15+
* <li>Recursively find the median of these medians, which becomes the pivot.</li>
16+
* <li>Partition the array around this pivot.</li>
17+
* <li>Recurse into the part that contains the kth smallest element.</li>
18+
* </ol>
19+
*
20+
* <p>Reference:
21+
* <a href="https://en.wikipedia.org/wiki/Median_of_medians">
22+
* Median of Medians Algorithm</a>
23+
*/
24+
public final class QuickSelectMedianOfMedians {
25+
26+
private QuickSelectMedianOfMedians() {
27+
// Utility class; prevent instantiation
28+
}
29+
30+
/**
31+
* Returns the kth smallest element in the given array using the
32+
* deterministic Median of Medians approach.
33+
*
34+
* @param arr the input array
35+
* @param k index (0-based) of the kth smallest element to find
36+
* @return the kth smallest element
37+
* @throws IllegalArgumentException if input is invalid
38+
*/
39+
public static int quickSelect(int[] arr, int k) {
40+
if (arr == null || arr.length == 0 || k < 0 || k >= arr.length) {
41+
throw new IllegalArgumentException("Invalid input");
42+
}
43+
return select(arr, 0, arr.length - 1, k);
44+
}
45+
46+
private static int select(int[] arr, int left, int right, int k) {
47+
if (left == right) {
48+
return arr[left];
49+
}
50+
51+
int pivotIndex = getPivotIndex(arr, left, right);
52+
int pivotValue = arr[pivotIndex];
53+
int partitionIndex = partition(arr, left, right, pivotValue);
54+
55+
if (k == partitionIndex) {
56+
return arr[k];
57+
} else if (k < partitionIndex) {
58+
return select(arr, left, partitionIndex - 1, k);
59+
} else {
60+
return select(arr, partitionIndex + 1, right, k);
61+
}
62+
}
63+
64+
private static int getPivotIndex(int[] arr, int left, int right) {
65+
int n = right - left + 1;
66+
if (n < 5) {
67+
Arrays.sort(arr, left, right + 1);
68+
return left + n / 2;
69+
}
70+
71+
int numMedians = (int) Math.ceil(n / 5.0);
72+
int[] medians = new int[numMedians];
73+
74+
for (int i = 0; i < numMedians; i++) {
75+
int subLeft = left + i * 5;
76+
int subRight = Math.min(subLeft + 4, right);
77+
Arrays.sort(arr, subLeft, subRight + 1);
78+
medians[i] = arr[subLeft + (subRight - subLeft) / 2];
79+
}
80+
81+
int medianOfMedians = quickSelect(medians, numMedians / 2);
82+
for (int i = left; i <= right; i++) {
83+
if (arr[i] == medianOfMedians) {
84+
return i;
85+
}
86+
}
87+
return left; // fallback
88+
}
89+
90+
private static int partition(int[] arr, int left, int right, int pivotValue) {
91+
int i = left;
92+
for (int j = left; j <= right; j++) {
93+
if (arr[j] < pivotValue) {
94+
swap(arr, i, j);
95+
i++;
96+
}
97+
}
98+
99+
int pivotIndex = i;
100+
for (int j = i; j <= right; j++) {
101+
if (arr[j] == pivotValue) {
102+
swap(arr, j, pivotIndex);
103+
break;
104+
}
105+
}
106+
return pivotIndex;
107+
}
108+
109+
private static void swap(int[] arr, int i, int j) {
110+
int tmp = arr[i];
111+
arr[i] = arr[j];
112+
arr[j] = tmp;
113+
}
114+
}

0 commit comments

Comments
 (0)