The Partial QuickSort algorithm was first introduced by Conrado Martínez in his paper "Partial QuickSort".
Partial QuickSort works as follows. Like quicksort but in every recursive call we receive a subarray a[i..j] and a k that k >= i. We want to rearrange the subarray so that a[i..k] contains the k - i + 1 smallest elements of a[i, j] in ascending order; if k > j that means we must fully sort a[i..j].
Pseudo code:
function partial_quicksort(a, i, j, k)
if i < j
p ← partition(a, i, j)
partial_quicksort(a, i, p-1, k)
if p < k-1
partial_quicksort(a, p+1, j, k)
The expected running time of this algorithm is only O(n + m log m) where n is the size of the subarray a[i..j] and m is the number of smallest elements we need
Java Code:
1 import java.util.Comparator;
2 import java.util.Random;
3
4 /**
5 * Created by william on 08/04/2018.
6 */
7 public class QuickSort<T> {
8
9 private static final int MAX_STACK_SIZE = 64;
10 private static final int MAX_ARRAY_SIZE;
11 static {
12 long maxArraySize = 1L << (MAX_STACK_SIZE / 2 - 1);
13 MAX_ARRAY_SIZE = (int) Math.min(
14 maxArraySize, (long) Integer.MAX_VALUE);
15 }
16
17 private static final int INSERTION_SORT_THRESHOLD = 16;
18
19 private static final int MEDIAN_OF_THREE_THRESHOLD = 32;
20
21 public static <T> void partialSort(
22 T[] a, int fromIndex, int toIndex, int middleIndex,
23 Comparator<? super T> c) {
24 rangeCheck(a.length, fromIndex, toIndex);
25
26 int[] stack = new int[MAX_STACK_SIZE];
27 int top = 0;
28
29 stack[top++] = fromIndex;
30 stack[top++] = toIndex;
31
32 while (top > 0) {
33 toIndex = stack[--top];
34 fromIndex = stack[--top];
35
36 if (toIndex - fromIndex <= INSERTION_SORT_THRESHOLD) {
37 for (int i = fromIndex + 1; i < toIndex; i++) {
38 T x = a[i];
39 int j = i;
40 while (--j >= fromIndex && c.compare(x, a[j]) < 0) {
41 a[j + 1] = a[j];
42 }
43 a[j + 1] = x;
44 }
45 continue;
46 }
47
48 int pivotIndex = partition(a, fromIndex, toIndex, c);
49
50 if (pivotIndex - fromIndex >= toIndex - pivotIndex - 1) {
51 stack[top++] = fromIndex;
52 stack[top++] = pivotIndex;
53
54 if (pivotIndex < middleIndex - 1) {
55 stack[top++] = pivotIndex + 1;
56 stack[top++] = toIndex;
57 }
58 } else {
59 if (pivotIndex < middleIndex - 1) {
60 stack[top++] = pivotIndex + 1;
61 stack[top++] = toIndex;
62 }
63 if (pivotIndex > fromIndex) {
64 stack[top++] = fromIndex;
65 stack[top++] = pivotIndex;
66 }
67 }
68 }
69 }
70
71 private static void rangeCheck(
72 int arrayLength, int fromIndex, int toIndex) {
73
74 if (arrayLength > MAX_ARRAY_SIZE) {
75 throw new IllegalArgumentException("size of array (" +
76 arrayLength + ") is too large, maximum array " +
77 "size allowed: " + MAX_ARRAY_SIZE);
78 }
79
80 if (fromIndex < 0) {
81 throw new ArrayIndexOutOfBoundsException(fromIndex);
82 }
83
84 if (toIndex > arrayLength) {
85 throw new ArrayIndexOutOfBoundsException(toIndex);
86 }
87
88 if (fromIndex > toIndex) {
89 throw new IllegalArgumentException(
90 "fromIndex(" + fromIndex + ") > " +
91 "toIndex(" + toIndex + ")");
92 }
93 }
94
95 private static final long RANDOM_SEED = System.currentTimeMillis();
96
97 private static <T> int partition(T[] a, int fromIndex, int toIndex,
98 Comparator<? super T> c) {
99 int n = toIndex - fromIndex;
100 int pivotIndex = fromIndex + (n >> 1);
101 if (n > MEDIAN_OF_THREE_THRESHOLD) {
102 Random random = new Random(RANDOM_SEED);
103 pivotIndex = medianOfThree(a,
104 fromIndex + random.nextInt(n),
105 fromIndex + random.nextInt(n),
106 fromIndex + random.nextInt(n),
107 c);
108 }
109 swap(a, fromIndex, pivotIndex);
110
111 T pivot = a[fromIndex];
112 int i = fromIndex;
113 for (int j = fromIndex + 1; j < toIndex; j++) {
114 if (c.compare(a[j], pivot) < 0) {
115 swap(a, ++i, j);
116 }
117 }
118 swap(a, fromIndex, i);
119 return i;
120 }
121
122 private static <T> int medianOfThree(T[] a, int i, int j, int k,
123 Comparator<? super T> c) {
124 return c.compare(a[i], a[j]) < 0 ?
125 (c.compare(a[j], a[k]) < 0 ? j :
126 c.compare(a[i], a[k]) < 0 ? k : i) :
127 (c.compare(a[k], a[j]) < 0 ? j :
128 c.compare(a[i], a[k]) < 0 ? i : k);
129 }
130
131 private static <T> void swap(T[] a, int i, int j) {
132 T temp = a[i];
133 a[i] = a[j];
134 a[j] = temp;
135 }
136
137 public static <T> void sort(T[] a, Comparator<? super T> c) {
138 sort(a, 0, a.length, c);
139 }
140
141 public static <T> void sort(T[] a, int fromIndex, int toIndex,
142 Comparator<? super T> c) {
143 partialSort(a, fromIndex, toIndex, toIndex, c);
144 }
145
146 public static <T> void partialSort(T[] a, int k,
147 Comparator<? super T> c) {
148 partialSort(a, 0, a.length, k, c);
149 }
150 }