mirror of
https://github.com/dlang/phobos.git
synced 2025-04-30 15:10:46 +03:00
Add medianOf
This commit is contained in:
parent
81c09ed1c1
commit
dcd00a7609
1 changed files with 159 additions and 0 deletions
|
@ -3120,6 +3120,165 @@ unittest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// medianOf
|
||||||
|
/**
|
||||||
|
Computes the median of 2 to 5 arbitrary indexes in random-access range `r`
|
||||||
|
using hand-written specialized algorithms. The indexes must be distinct (if not,
|
||||||
|
behavior is implementation-defined). The function also partitions the elements
|
||||||
|
involved around the median, e.g. $(D median(r, a, b, c)) not only fills `r[b]`
|
||||||
|
with the median of `r[a]`, `r[b]`, and `r[c]`, but also puts the minimum in
|
||||||
|
`r[a]` and the maximum in `r[c]`.
|
||||||
|
|
||||||
|
Params:
|
||||||
|
less = The comparison predicate used, modeled as a $(LUCKY strict weak
|
||||||
|
ordering) (irreflexive, antisymmetric, transitive, and implying a transitive
|
||||||
|
equivalence).
|
||||||
|
flag = Used only for even values of `T.length`. If `No.leanRight`, the median
|
||||||
|
"leans left", meaning $(D median(r, a, b, c, d)) puts the lower median of the
|
||||||
|
four in `r[b]`, the minimum in `r[a]`, and the two others in `r[c]` and `r[d]`.
|
||||||
|
Conversely, $(D median!("a < b", Yes.leanRight)(r, a, b, c, d)) puts the upper
|
||||||
|
median of the four in `r[c]`, the maximum in `r[d]`, and the two others in
|
||||||
|
`r[a]` and `r[b]`.
|
||||||
|
r = The range containing the indexes.
|
||||||
|
i = Two to five indexes inside `r`.
|
||||||
|
*/
|
||||||
|
void medianOf(
|
||||||
|
alias less = "a < b",
|
||||||
|
Flag!"leanRight" flag = No.leanRight,
|
||||||
|
Range,
|
||||||
|
Index...)
|
||||||
|
(Range r, Index i)
|
||||||
|
if (isRandomAccessRange!Range && Index.length >= 2 && Index.length <= 5 &&
|
||||||
|
allSatisfy!(isIntegral, Index))
|
||||||
|
{
|
||||||
|
assert(r.length >= Index.length);
|
||||||
|
import std.functional : binaryFun;
|
||||||
|
alias lt = binaryFun!less;
|
||||||
|
enum k = Index.length;
|
||||||
|
import std.algorithm : swapAt;
|
||||||
|
|
||||||
|
alias a = i[0];
|
||||||
|
static if (k >= 2)
|
||||||
|
{
|
||||||
|
alias b = i[1];
|
||||||
|
assert(a != b);
|
||||||
|
}
|
||||||
|
static if (k >= 3)
|
||||||
|
{
|
||||||
|
alias c = i[2];
|
||||||
|
assert(a != c && b != c);
|
||||||
|
}
|
||||||
|
static if (k >= 4)
|
||||||
|
{
|
||||||
|
alias d = i[3];
|
||||||
|
assert(a != d && b != d && c != d);
|
||||||
|
}
|
||||||
|
static if (k >= 5)
|
||||||
|
{
|
||||||
|
alias e = i[4];
|
||||||
|
assert(a != e && b != e && c != e && d != e);
|
||||||
|
}
|
||||||
|
|
||||||
|
static if (k == 2)
|
||||||
|
{
|
||||||
|
if (lt(r[b], r[a])) r.swapAt(a, b);
|
||||||
|
}
|
||||||
|
else static if (k == 3)
|
||||||
|
{
|
||||||
|
if (lt(r[c], r[a])) // c < a
|
||||||
|
{
|
||||||
|
if (lt(r[a], r[b])) // c < a < b
|
||||||
|
{
|
||||||
|
r.swapAt(a, b);
|
||||||
|
r.swapAt(a, c);
|
||||||
|
}
|
||||||
|
else // c < a, b <= a
|
||||||
|
{
|
||||||
|
r.swapAt(a, c);
|
||||||
|
if (lt(r[b], r[a])) r.swapAt(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // a <= c
|
||||||
|
{
|
||||||
|
if (lt(r[b], r[a])) // b < a <= c
|
||||||
|
{
|
||||||
|
r.swapAt(a, b);
|
||||||
|
}
|
||||||
|
else // a <= c, a <= b
|
||||||
|
{
|
||||||
|
if (lt(r[c], r[b])) r.swapAt(b, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(!lt(r[b], r[a]));
|
||||||
|
assert(!lt(r[c], r[b]));
|
||||||
|
}
|
||||||
|
else static if (k == 4)
|
||||||
|
{
|
||||||
|
static if (flag == No.leanRight)
|
||||||
|
{
|
||||||
|
// Eliminate the rightmost from the competition
|
||||||
|
if (lt(r[d], r[c])) r.swapAt(c, d); // c<=d
|
||||||
|
if (lt(r[d], r[b])) r.swapAt(b, d); // b<=d
|
||||||
|
medianOf!lt(r, a, b, c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Eliminate the leftmost from the competition
|
||||||
|
if (lt(r[b], r[a])) r.swapAt(a, b); // a<=b
|
||||||
|
if (lt(r[c], r[a])) r.swapAt(a, c); // a<=c
|
||||||
|
medianOf!lt(r, b, c, d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else static if (k == 5)
|
||||||
|
{
|
||||||
|
// Credit: Teppo Niinimäki
|
||||||
|
version(unittest) scope(success)
|
||||||
|
{
|
||||||
|
assert(!lt(r[c], r[a]));
|
||||||
|
assert(!lt(r[c], r[b]));
|
||||||
|
assert(!lt(r[d], r[c]));
|
||||||
|
assert(!lt(r[e], r[c]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lt(r[c], r[a])) r.swapAt(a, c);
|
||||||
|
if (lt(r[d], r[b])) r.swapAt(b, d);
|
||||||
|
if (lt(r[d], r[c]))
|
||||||
|
{
|
||||||
|
r.swapAt(c, d);
|
||||||
|
r.swapAt(a, b);
|
||||||
|
}
|
||||||
|
if (lt(r[e], r[b])) r.swapAt(b, e);
|
||||||
|
if (lt(r[e], r[c]))
|
||||||
|
{
|
||||||
|
r.swapAt(c, e);
|
||||||
|
if (lt(r[c], r[a])) r.swapAt(a, c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (lt(r[c], r[b])) r.swapAt(b, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
import std.random : uniform;
|
||||||
|
import std.algorithm.iteration : map;
|
||||||
|
auto a = iota(0, 18).map!(_ => uniform(-10, 10)).array;
|
||||||
|
medianOf(a, 0, 1);
|
||||||
|
assert(a[0] <= a[1]);
|
||||||
|
medianOf(a, 2, 3, 4);
|
||||||
|
assert(a[2] <= a[3] && a[3] <= a[4]);
|
||||||
|
medianOf(a, 5, 6, 7, 8);
|
||||||
|
assert(a[5] <= a[6] && a[6] <= a[7] && a[6] <= a[8]);
|
||||||
|
medianOf!("a < b", Yes.leanRight)(a, 9, 10, 11, 12);
|
||||||
|
assert(a[9] <= a[11] && a[10] <= a[11] && a[11] <= a[12]);
|
||||||
|
medianOf(a, 13, 14, 15, 16, 17);
|
||||||
|
assert(a[13] <= a[15] && a[14] <= a[15] && a[15] <= a[16] &&
|
||||||
|
a[15] <= a[17]);
|
||||||
|
}
|
||||||
|
|
||||||
// nextPermutation
|
// nextPermutation
|
||||||
/**
|
/**
|
||||||
* Permutes $(D range) in-place to the next lexicographically greater
|
* Permutes $(D range) in-place to the next lexicographically greater
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue