in commons-numbers-arrays/src/main/java/org/apache/commons/numbers/arrays/QuickSelect.java [2436:2523]
static void dualPivotQuickSelect(int[] a, int left, int right, UpdatingInterval k, int flags) {
// If partitioning splits the interval then recursion is used for the left-most side(s)
// and the right-most side remains within this function. If partitioning does
// not split the interval then it remains within this function.
int l = left;
int r = right;
int f = flags;
int ka = k.left();
int kb = k.right();
final int[] upper = {0, 0, 0};
while (true) {
// Select when ka and kb are close to the same end,
// or the entire range is small
// |l|-----|ka|--------|kb|------|r|
final int n = r - l;
if (Math.min(kb - l, r - ka) < DP_SORTSELECT_SIZE ||
n < (f & SORTSELECT_MASK)) {
sortSelect(a, l, r, ka, kb);
return;
}
if (kb - ka < DP_SORTSELECT_SIZE) {
// Switch to single-pivot mode with Floyd-Rivest sub-sampling
quickSelectAdaptive(a, l, r, ka, kb, upper, MODE_FR_SAMPLING);
return;
}
if (f < 0) {
// Excess recursion, switch to heap select
heapSelect(a, l, r, ka, kb);
return;
}
// Dual-pivot partitioning
final int p0 = partition(a, l, r, upper);
final int p1 = upper[0];
// Recursion to max depth
// Note: Here we possibly branch left, middle and right with multiple keys.
// It is possible that the partition has split the keys
// and the recursion proceeds with a reduced set in each region.
// p0 p1 p2 p3
// |l|--|ka|--k----k--|P|------k--|kb|----|P|----|r|
// kb | ka
f += RECURSION_INCREMENT;
// Recurse left side if required
if (ka < p0) {
if (kb <= p1) {
// Entirely on left side
r = p0 - 1;
if (r < kb) {
kb = k.updateRight(r);
}
continue;
}
dualPivotQuickSelect(a, l, p0 - 1, k.splitLeft(p0, p1), f);
// Here we must process middle and/or right
ka = k.left();
} else if (kb <= p1) {
// No middle/right side
return;
} else if (ka <= p1) {
// Advance lower bound
ka = k.updateLeft(p1 + 1);
}
// Recurse middle if required
final int p2 = upper[1];
final int p3 = upper[2];
if (ka < p2) {
l = p1 + 1;
if (kb <= p3) {
// Entirely in middle
r = p2 - 1;
if (r < kb) {
kb = k.updateRight(r);
}
continue;
}
dualPivotQuickSelect(a, l, p2 - 1, k.splitLeft(p2, p3), f);
ka = k.left();
} else if (kb <= p3) {
// No right side
return;
} else if (ka <= p3) {
ka = k.updateLeft(p3 + 1);
}
// Continue right
l = p3 + 1;
}
}