std.algorithm.sorting
Это подмодуль std.algorithm. Он содержит обобщённые алгоритмы сортировки.
| Название функции | Описание |
|---|---|
completeSort | Если a = [10, 20, 30] и b = [40, 6, 15], то completeSort(a, b) оставляет a = [6, 10, 15] и b = [20, 30, 40]. Диапазон a должен быть отсортирован до вызова, и в результате комбинация std.range.chain(a, b) будет отсортирована. |
isPartitioned | isPartitioned!"a < 0"([-1, -2, 1, 0, 2]) возвращает true, потому что предикат true для части диапазона и false после. |
isSorted | isSorted([1, 1, 2, 3]) возвращает true. |
isStrictlyMonotonic | isStrictlyMonotonic([1, 1, 2, 3]) возвращает false. |
ordered | ordered(1, 1, 2, 3) возвращает true. |
strictlyOrdered | strictlyOrdered(1, 1, 2, 3) возвращает false. |
makeIndex | Создаёт отдельный индекс для диапазона. |
merge | Лениво объединяет два или более отсортированных диапазонов. |
multiSort | Сортирует по нескольким ключам. |
nextEvenPermutation | Вычисляет следующее лексикографически большее чётное перестановку диапазона на месте. |
nextPermutation | Вычисляет следующую лексикографически большее перестановку диапазона на месте. |
nthPermutation | Вычисляет n-ю перестановку диапазона на месте. |
partialSort | Если a = [5, 4, 3, 2, 1], то partialSort(a, 3) оставляет a[0 .. 3] = [1, 2, 3]. Остальные элементы a оставляются в неопределённом порядке. |
partition | Разделяет диапазон в соответствии с унарным предикатом. |
partition3 | Разделяет диапазон по бинарному предикату на три части (меньше, равно, больше заданного опорного элемента). Опорный элемент не задаётся как индекс, а вместо этого как элемент, независимый от содержимого диапазона. |
pivotPartition | Разделяет диапазон по бинарному предикату на две части: меньше или равно и больше или равно заданному опорному элементу, переданному как индекс в диапазоне. |
schwartzSort | Сортирует с помощью преобразования Шварца. |
sort | Сортирует. |
topN | Выделяет лучшие элементы в диапазоне. |
topNCopy | Копирует лучшие элементы диапазона. |
topNIndex | Создаёт индекс лучших элементов диапазона. |
- Лицензия:
- Лицензия Boost 1.0.
- Авторы:
- Андрей Александреску
- Исходный код
- std/algorithm/sorting.d
- alias SortOutput = std.typecons.Flag!"sortOutput".Flag;
-
Указывает, требуется ли вывод определённого алгоритма в отсортированном формате.
Если установлено в
SortOutput.no, вывод не должен быть отсортированным.
В противном случае, если установлено вSortOutput.yes, вывод должен быть отсортированным. - void completeSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Lhs, Rhs)(SortedRange!(Lhs, less) lhs, Rhs rhs)
Constraints: if (hasLength!Rhs && hasSlicing!Rhs && hasSwappableElements!Lhs && hasSwappableElements!Rhs); -
Сортирует диапазон произвольного доступа
chain(lhs, rhs)согласно предикатуless. Левая часть диапазонаlhsпредполагается уже отсортированной;rhsпредполагается неотсортированной. Точная выбранная стратегия зависит от относительных размеровlhsиrhs. Выполняет Ο(lhs.length + rhs.length * log(rhs.length)) (лучший случай) до Ο((lhs.length + rhs.length) * log(lhs.length + rhs.length)) (худший случай) вычисленийswap.- Parameters:
less Предикат для сортировки. ss Стратегия обмена. SortedRange!(Lhs, less) lhsОтсортированная левая часть диапазона произвольного доступа, подлежащая сортировке. Rhs rhsНеотсортированная правая часть диапазона произвольного доступа, подлежащая сортировке.
- Examples:
-
import std.range : assumeSorted; int[] a = [ 1, 2, 3 ]; int[] b = [ 4, 0, 6, 5 ]; completeSort(assumeSorted(a), b); writeln(a); // [0, 1, 2] writeln(b); // [3, 4, 5, 6]
- bool isSorted(alias less = "a < b", Range)(Range r)
Constraints: if (isForwardRange!Range);
bool isStrictlyMonotonic(alias less = "a < b", Range)(Range r)
Constraints: if (isForwardRange!Range); -
Проверяет, является ли прямолинейный диапазон отсортированным согласно операции сравнения
less. Выполняет Ο(r.length) вычисленийless.В отличие от
isSorted,isStrictlyMonotonicне допускает одинаковых значений, т.е. значений, для которых иless(a, b), иless(b, a)ложны.
В обоих функциях предикат должен быть строгим упорядочением, как и вisSorted. Например, использование"a <= b"вместо"a < b"неверно и приведёт к ошибкам.- Parameters:
less Предикат, по которому должен быть отсортирован диапазон. Range rПрямолинейный диапазон для проверки на отсортированность.
- Returns:
-
trueесли диапазон отсортирован, иначе false.isSortedдопускает дубликаты,isStrictlyMonotonic— нет.
- Examples:
-
assert([1, 1, 2].isSorted); // strictly monotonic doesn't allow duplicates assert(![1, 1, 2].isStrictlyMonotonic); int[] arr = [4, 3, 2, 1]; assert(!isSorted(arr)); assert(!isStrictlyMonotonic(arr)); assert(isSorted!"a > b"(arr)); assert(isStrictlyMonotonic!"a > b"(arr)); sort(arr); assert(isSorted(arr)); assert(isStrictlyMonotonic(arr));
- bool ordered(alias less = "a < b", T...)(T values)
Constraints: if (T.length == 2 && is(typeof(binaryFun!less(values[1], values[0])) : bool) || T.length > 2 && is(typeof(ordered!less(values[0..1 + $ / 2]))) && is(typeof(ordered!less(values[$ / 2..$]))));
bool strictlyOrdered(alias less = "a < b", T...)(T values)
Constraints: if (is(typeof(ordered!less(values)))); -
Как и
isSorted, возвращаетtrueесли заданныеvaluesупорядочены согласно операции сравненияless. В отличие отisSorted, принимает значения напрямую вместо структурирования в диапазоне.orderedдопускает повторяющиеся значения, например,ordered(1, 1, 2)этоtrue. Для проверки, что значения упорядочены строго монотонно, используйтеstrictlyOrdered;strictlyOrdered(1, 1, 2)этоfalse.
В обоих функциях предикат должен быть строгим упорядочением. Например, использование"a <= b"вместо"a < b"неверно и приведёт к ошибкам.- Parameters:
T valuesТестируемое значение less Предикат сравнения
- Returns:
-
trueесли значения упорядочены;orderedдопускает дубликаты,strictlyOrdered— нет.
- Examples:
-
assert(ordered(42, 42, 43)); assert(!strictlyOrdered(43, 42, 45)); assert(ordered(42, 42, 43)); assert(!strictlyOrdered(42, 42, 43)); assert(!ordered(43, 42, 45)); // Ordered lexicographically assert(ordered("Jane", "Jim", "Joe")); assert(strictlyOrdered("Jane", "Jim", "Joe")); // Incidentally also ordered by length decreasing assert(ordered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe")); // ... but not strictly so: "Jim" and "Joe" have the same length assert(!strictlyOrdered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe"));
- Range partition(alias predicate, SwapStrategy ss, Range)(Range r)
Constraints: if (ss == SwapStrategy.stable && isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && hasSwappableElements!Range);
Range partition(alias predicate, SwapStrategy ss = SwapStrategy.unstable, Range)(Range r)
Constraints: if (ss != SwapStrategy.stable && isInputRange!Range && hasSwappableElements!Range); -
Разделяет диапазон на две части, используя данный
predicate. В частности, переупорядочивает диапазонr = [left, right)с использованиемswapтаким образом, чтобы все элементыi, для которыхpredicate(i)имеет значениеtrue, стояли перед всеми элементамиj, для которыхpredicate(j)возвращаетfalse.Выполняет Ο(
r.length) (если неустойчивый или полуустойчивый) или Ο(r.length * log(r.length)) (если устойчивый) вычисленийlessиswap. Неустойчивая версия вычисляет минимальное возможное количество вычисленийswap(примерно половину тех, что выполняются полуустойчивой версией).- Parameters:
predicate Предикат для разделения. ss Стратегия обмена. Range rДиапазон произвольного доступа для разделения.
- Returns:
- Правая часть
rпосле разделения. Еслиss == SwapStrategy.stable,partitionсохраняет относительный порядок всех элементовa,bвrдля которыхpredicate(a) == predicate(b). Еслиss == SwapStrategy.semistable,partitionсохраняет относительный порядок всех элементовa,bв левой частиrдля которыхpredicate(a) == predicate(b).
- Examples:
-
import std.algorithm.mutation : SwapStrategy; import std.algorithm.searching : count, find; import std.conv : text; import std.range.primitives : empty; auto Arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; auto arr = Arr.dup; static bool even(int a) { return (a & 1) == 0; } // Partition arr such that even numbers come first auto r = partition!(even)(arr); // Now arr is separated in evens and odds. // Numbers may have become shuffled due to instability writeln(r); // arr[5 .. $] writeln(count!(even)(arr[0 .. 5])); // 5 assert(find!(even)(r).empty); // Can also specify the predicate as a string. // Use 'a' as the predicate argument name arr[] = Arr[]; r = partition!(q{(a & 1) == 0})(arr); writeln(r); // arr[5 .. $] // Now for a stable partition: arr[] = Arr[]; r = partition!(q{(a & 1) == 0}, SwapStrategy.stable)(arr); // Now arr is [2 4 6 8 10 1 3 5 7 9], and r points to 1 assert(arr == [2, 4, 6, 8, 10, 1, 3, 5, 7, 9] && r == arr[5 .. $]); // In case the predicate needs to hold its own state, use a delegate: arr[] = Arr[]; int x = 3; // Put stuff greater than 3 on the left bool fun(int a) { return a > x; } r = partition!(fun, SwapStrategy.semistable)(arr); // Now arr is [4 5 6 7 8 9 10 2 3 1] and r points to 2 assert(arr == [4, 5, 6, 7, 8, 9, 10, 2, 3, 1] && r == arr[7 .. $]);
- size_t pivotPartition(alias less = "a < b", Range)(Range r, size_t pivot)
Constraints: if (isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && hasAssignableElements!Range); -
Разделяет
rвокругpivotиспользуя функцию сравненияless, алгоритм, аналогичный схеме разбиения Хоара. В частности, переставляет элементыrи возвращает индексk < r.lengthтакой, что:-
r[pivot]переставляется сr[k] - Все элементы
eв поддиапазонеr[0 .. k]удовлетворяют!less(r[k], e)(т.е.r[k]больше или равно каждому элементу слева в соответствии с предикатомless). - Все элементы
eв поддиапазонеr[k .. $]удовлетворяют!less(e, r[k])(т.е.r[k]меньше или равно каждому элементу справа в соответствии с предикатомless).
Еслиrсодержит эквивалентные элементы, несколько перестановокrудовлетворяют этим ограничениям. В таких случаях,pivotPartitionпытается распределить эквивалентные элементы достаточно равномерно слева и справа отk, так чтоkостаётся рядом сr.length / 2.- Parameters:
less Предикат, используемый для сравнения, моделируемый как строгое слабое упорядочение (иррефлексивное, антисимметричное, транзитивное и подразумевающее транзитивную эквивалентность) Range rРазделяемый диапазон size_t pivotИндекс опорного элемента для разбиения, должен быть меньше r.lengthили0еслиr.lengthэто0
- Returns:
- Новая позиция опорного элемента
- See Also:
- Engineering of a Quicksort Partitioning Algorithm, D. Abhyankar, Journal of Global Research in Computer Science, February 2011. ACCU 2016 Keynote, Andrei Alexandrescu.
- Examples:
-
int[] a = [5, 3, 2, 6, 4, 1, 3, 7]; size_t pivot = pivotPartition(a, a.length / 2); import std.algorithm.searching : all; assert(a[0 .. pivot].all!(x => x <= a[pivot])); assert(a[pivot .. $].all!(x => x >= a[pivot]));
-
- bool isPartitioned(alias pred, Range)(Range r)
Constraints: if (isForwardRange!Range); -
- Parameters:
pred Предикат, по которому должен быть разделён диапазон. Range rДиапазон для проверки.
- Returns:
-
trueеслиrразделён согласно предикатуpred.
- Examples:
-
int[] r = [ 1, 3, 5, 7, 8, 2, 4, ]; assert(isPartitioned!"a & 1"(r));
- auto partition3(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, E)(Range r, E pivot)
Constraints: if (ss == SwapStrategy.unstable && isRandomAccessRange!Range && hasSwappableElements!Range && hasLength!Range && hasSlicing!Range && is(typeof(binaryFun!less(r.front, pivot)) == bool) && is(typeof(binaryFun!less(pivot, r.front)) == bool) && is(typeof(binaryFun!less(r.front, r.front)) == bool));
-
Переупорядочивает элементы в
rв трех смежных диапазонах и возвращает их. Первый и самый левый диапазон содержит только элементы вrменьшеpivot. Второй и средний диапазон содержит только элементы вrравныеpivot. Наконец, третий и самый правый диапазон содержит только элементы вrбольшеpivot. Тест "меньше" определяется бинарной функциейless.- Параметры:
less Предикат для использования при переупорядочивании. ss Стратегия перестановки для использования. Диапазон rДиапазон с произвольным доступом для переупорядочивания. E pivotЭлемент-опорная точка.
- Возвращаемое значение:
- Кортеж
std.typecons.Tupleиз трех получившихся диапазонов. Эти диапазоны являются срезами исходного диапазона.
- Ошибки:
- Устойчивая
partition3еще не реализована.
- Примеры:
-
auto a = [ 8, 3, 4, 1, 4, 7, 4 ]; auto pieces = partition3(a, 4); writeln(pieces[0]); // [1, 3] writeln(pieces[1]); // [4, 4, 4] writeln(pieces[2]); // [8, 7]
- SortedRange!(RangeIndex, (a, b) => binaryFun!less(*a, *b)) makeIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex)(Range r, RangeIndex index)
Constraints: if (isForwardRange!Range && isRandomAccessRange!RangeIndex && is(ElementType!RangeIndex : ElementType!Range*) && hasAssignableElements!RangeIndex);
void makeIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex)(Range r, RangeIndex index)
Constraints: if (isRandomAccessRange!Range && !isInfinite!Range && isRandomAccessRange!RangeIndex && !isInfinite!RangeIndex && isIntegral!(ElementType!RangeIndex) && hasAssignableElements!RangeIndex); -
Вычисляет индекс для
rна основе сравненияless. Индекс — это отсортированный массив указателей или индексов в исходном диапазоне. Этот метод аналогичен сортировке, но более гибкий, поскольку (1) позволяет «сортировать» неизменяемые коллекции, (2) позволяет проводить бинарный поиск, даже если исходная коллекция не обеспечивает произвольного доступа, (3) позволяет использовать несколько индексов, каждый на разных предикатах, и (4) может быть быстрее при работе с большими объектами. Однако использование индекса также может быть медленнее в определенных обстоятельствах из-за дополнительной косвенности и всегда больше, чем решение на основе сортировки, поскольку оно требует памяти для индекса в дополнение к исходной коллекции. Сложность такая же, как уsort.Первый перегруженный вариант
makeIndexзаписывает в диапазон, содержащий указатели, а второй — в диапазон, содержащий смещения. Первый перегруженный вариант требует, чтобыRangeбыл диапазоном с последовательным доступом, а второй — диапазоном с произвольным доступом.
makeIndexперезаписывает свой второй аргумент результатом, но никогда не перевыделяет его.- Параметры:
less Используемое сравнение. ss Стратегия перестановки. Диапазон rДиапазон для индексирования. RangeIndex indexПолученный индекс.
- Возвращаемое значение:
- Версия на основе указателей возвращает обёртку
SortedRangeнад индексом типаSortedRange!(RangeIndex, (a, b) => binaryFun!less(*a, *b)), отражающую порядок индекса. Версия на основе индексов возвращаетvoid, поскольку отношение порядка включает не толькоindex, но иr.
- Исключения:
- Если длина второго аргумента меньше длины индексируемого диапазона, выбрасывается исключение.
- Примеры:
-
immutable(int[]) arr = [ 2, 3, 1, 5, 0 ]; // index using pointers auto index1 = new immutable(int)*[arr.length]; makeIndex!("a < b")(arr, index1); assert(isSorted!("*a < *b")(index1)); // index using offsets auto index2 = new size_t[arr.length]; makeIndex!("a < b")(arr, index2); assert(isSorted! ((size_t a, size_t b){ return arr[a] < arr[b];}) (index2));
- Merge!(less, Rs) merge(alias less = "a < b", Rs...)(Rs rs)
Constraints: if (Rs.length >= 2 && allSatisfy!(isInputRange, Rs) && !is(CommonType!(staticMap!(ElementType, Rs)) == void)); -
Объединяет несколько отсортированных диапазонов
rsс предикатом меньшеpredв один отсортированный выходной диапазон, содержащий отсортированное объединение элементов ввода. Дубликаты не удаляются, что означает, что общее количество элементов на выходе равно сумме всех элементов во входящих диапазонах; членlengthпредлагается, если все входы также имеютlength. Типы элементов всех входов должны иметь общий типCommonType.- Параметры:
less Предикат, по которому отсортированы заданные диапазоны. Rs rsДиапазоны для вычисления объединения.
- Возвращаемое значение:
- Диапазон, содержащий объединение заданных диапазонов.
- Подробности
- Все входящие диапазоны предполагаются отсортированными. Это может означать, что входы являются экземплярами
std.range.SortedRange. Используйте результатstd.algorithm.sorting.sortилиstd.range.assumeSorted, чтобы объединить известные отсортированные диапазоны (показано в примере ниже). Обратите внимание, что в настоящее время нет способа гарантировать, что два или более экземпляровstd.range.SortedRangeотсортированы с использованием определённой функции сравненияpred. Поэтому здесь не проверяется, чтобы все входящиеrsбыли экземплярамиstd.range.SortedRange.
ref, вывод становится диапазоном с изменяемымиfront(иbackпри необходимости), которые отражаются в исходных входах. Если какой-либо из входовrsбесконечен, бесконечным будет и результат (emptyвсегдаfalse).- См. также:
-
std.algorithm.setops.multiwayMergeдля аналогичной функции объединения динамического количества диапазонов.
- Примеры:
-
import std.algorithm.comparison : equal; import std.range : retro; int[] a = [1, 3, 5]; int[] b = [2, 3, 4]; assert(a.merge(b).equal([1, 2, 3, 3, 4, 5])); assert(a.merge(b).retro.equal([5, 4, 3, 3, 2, 1]));
- Примеры:
- тестирование двунаправленного доступа и общего типа
import std.algorithm.comparison : equal; import std.range : retro; import std.traits : CommonType; alias S = short; alias I = int; alias D = double; S[] a = [1, 2, 3]; I[] b = [50, 60]; D[] c = [10, 20, 30, 40]; auto m = merge(a, b, c); static assert(is(typeof(m.front) == CommonType!(S, I, D))); assert(equal(m, [1, 2, 3, 10, 20, 30, 40, 50, 60])); assert(equal(m.retro, [60, 50, 40, 30, 20, 10, 3, 2, 1])); m.popFront(); assert(equal(m, [2, 3, 10, 20, 30, 40, 50, 60])); m.popBack(); assert(equal(m, [2, 3, 10, 20, 30, 40, 50])); m.popFront(); assert(equal(m, [3, 10, 20, 30, 40, 50])); m.popBack(); assert(equal(m, [3, 10, 20, 30, 40])); m.popFront(); assert(equal(m, [10, 20, 30, 40])); m.popBack(); assert(equal(m, [10, 20, 30])); m.popFront(); assert(equal(m, [20, 30])); m.popBack(); assert(equal(m, [20])); m.popFront(); assert(m.empty);
- template multiSort(less...)
-
Сортирует диапазон по нескольким ключам. Вызов
multiSort!("a.id < b.id", "a.date > b.date")(r)сортирует диапазонrпоidпо возрастанию и сортирует элементы, имеющие одинаковое значениеidпоdateпо убыванию. Такой вызов эквивалентенsort!"a.id != b.id ? a.id < b.id : a.date > b.date"(r), ноmultiSortбыстрее, потому что выполняет меньше сравнений (помимо большей удобства).- Возвращаемое значение:
- Исходный диапазон, обернутый как
SortedRangeс его предикатными функциями, преобразованными в эквивалентный единичный предикат.
- Примеры:
-
import std.algorithm.mutation : SwapStrategy; static struct Point { int x, y; } auto pts1 = [ Point(0, 0), Point(5, 5), Point(0, 1), Point(0, 2) ]; auto pts2 = [ Point(0, 0), Point(0, 1), Point(0, 2), Point(5, 5) ]; multiSort!("a.x < b.x", "a.y < b.y", SwapStrategy.unstable)(pts1); writeln(pts1); // pts2
- SortedRange!(Range, less) sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r)
Constraints: if ((ss == SwapStrategy.unstable && (hasSwappableElements!Range || hasAssignableElements!Range) || ss != SwapStrategy.unstable && hasAssignableElements!Range) && isRandomAccessRange!Range && hasSlicing!Range && hasLength!Range); -
Сортирует диапазон с произвольным доступом в соответствии с предикатом
less. Выполняет Ο(r.length * log(r.length)) вычисленийless. Еслиlessвключает дорогостоящие вычисления для ключа сортировки, может быть целесообразно использоватьschwartzSortвместо этого.Устойчивая сортировка требует, чтобы
hasAssignableElements!Rangeбыло true.
sortвозвращаетstd.range.SortedRangeнад исходным диапазоном, позволяя функциям, которые могут использовать отсортированные данные, знать, что диапазон отсортирован, и соответственно корректировать поведение.std.range.SortedRange— это оболочка вокруг исходного диапазона, поэтому оба они отсортированы. Другие функции не могут знать, что исходный диапазон был отсортирован, но они *могут* знать, чтоstd.range.SortedRangeбыл отсортирован.- Предпосылки
- От предиката ожидается соблюдение определённых правил, чтобы
sortвело себя ожидаемым образом — в противном случае программа может завершиться неудачно на некоторых входных данных (но не на других), когда не скомпилирована в режиме выпуска, из-за поверхностнойassumeSortedпроверки. В частности,sortожидает, чтоless(a,b) && less(b,c)подразумеваетless(a,c)(транзитивность) и, наоборот,!less(a,b) && !less(b,c)подразумевает!less(a,c). Обратите внимание, что стандартный предикат ("a < b") не всегда удовлетворяет этим условиям для чисел с плавающей точкой, поскольку выражение всегда будетfalseкогда либоaилиbявляется NaN. Используйтеstd.math.cmpвместо этого.
- Параметры:
less Предикат для сортировки. ss Стратегия перестановки для использования. Диапазон rДиапазон для сортировки.
- Возвращаемое значение:
- Исходный диапазон, обернутый как
SortedRangeс предикатомbinaryFun!less.
- Алгоритмы
- Introsort используется для неустойчивой сортировки, а Timsort — для устойчивой. Каждый алгоритм имеет преимущества помимо стабильности. Introsort обычно быстрее, но Timsort может достичь большей скорости на данных с низкой энтропией или если вызовы предикатов дорогостоящие. Introsort не выполняет выделений, тогда как Timsort выполнит одно или несколько выделений на вызов. Оба алгоритма имеют Ο(
n log n) временную сложность в худшем случае.
- См. также:
-
std.range.assumeSorted
std.range.SortedRange
std.algorithm.mutation.SwapStrategy
std.functional.binaryFun
- Примеры:
-
int[] array = [ 1, 2, 3, 4 ]; // sort in descending order array.sort!("a > b"); writeln(array); // [4, 3, 2, 1] // sort in ascending order array.sort(); writeln(array); // [1, 2, 3, 4] // sort with reusable comparator and chain alias myComp = (x, y) => x > y; writeln(array.sort!(myComp).release); // [4, 3, 2, 1]
- Примеры:
-
// Showcase stable sorting import std.algorithm.mutation : SwapStrategy; string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ]; sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable)(words); writeln(words); // ["a", "aBc", "abc", "ABC", "b", "c"]
- Примеры:
-
// Sorting floating-point numbers in presence of NaN double[] numbers = [-0.0, 3.0, -2.0, double.nan, 0.0, -double.nan]; import std.algorithm.comparison : equal; import std.math : cmp, isIdentical; sort!((a, b) => cmp(a, b) < 0)(numbers); double[] sorted = [-double.nan, -2.0, -0.0, 0.0, 3.0, double.nan]; assert(numbers.equal!isIdentical(sorted));
- SortedRange!(R, (a, b) => binaryFun!less(unaryFun!transform(a), unaryFun!transform(b))) schwartzSort(alias transform, alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, R)(R r)
Constraints: if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R && !is(typeof(binaryFun!less) == SwapStrategy));
auto schwartzSort(alias transform, SwapStrategy ss, R)(R r)
Constraints: if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R); -
Альтернативный метод сортировки, который следует использовать, когда сравнение ключей включает дорогостоящие вычисления. Вместо использования
less(a, b)для сравнения элементов,schwartzSortиспользуетless(transform(a), transform(b)). Значения функцииtransformпредварительно вычисляются в временном массиве, тем самым экономя вычислительные ресурсы. И наоборот, если стоимость вычисленияtransformневелика по сравнению со стоимостью выделения и заполнения предварительно вычисленного массива,sortможет быть быстрее и, следовательно, предпочтительнее.Этот подход к сортировке аналогичен преобразованию Шварца, также известному как шаблон «декорировать-сортировать-распотрошить» в Python и Lisp. Сложность такая же, как у соответствующего
sort, ноschwartzSortвычисляетtransformтолькоr.lengthраз (менее чем в половину по сравнению с обычной сортировкой). Использование лучше всего проиллюстрировать на примере.- Пример
uint hashFun(string) { ... expensive computation ... } string[] array = ...; // Sort strings by hash, slow sort!((a, b) => hashFun(a) < hashFun(b))(array); // Sort strings by hash, fast (only computes arr.length hashes): schwartzSort!(hashFun, "a < b")(array);ФункцияschwartzSortможет потребовать меньше временных данных и быть быстрее, чем фрагмент Perl или шаблон «декорировать-сортировать-распотрошить», присутствующий в Python и Lisp. Это происходит потому, что сортировка выполняется на месте и создается только минимально дополнительный объем данных (один массив преобразованных элементов). Чтобы проверить, был ли массив отсортирован, и воспользоваться ускорением сортировки Шварца, функцияschwartzIsSortedне предоставляется, поскольку этого можно достичь, вызвавisSorted!less(map!transform(r)).- Параметры:
transform Применяемая трансформация. Либо унарная функция ( unaryFun!transform(element)), либо бинарная функция (binaryFun!transform(element, index)).less Предикат для сортировки преобразованных элементов. ss Используемая стратегия перестановки. R rДиапазон для сортировки.
- Возвращаемое значение:
- Исходный диапазон, обернутый как
SortedRangeс предикатом(a, b) => binaryFun!less(transform(a), transform(b)).
- Примеры:
-
import std.algorithm.iteration : map; import std.numeric : entropy; auto lowEnt = [ 1.0, 0, 0 ], midEnt = [ 0.1, 0.1, 0.8 ], highEnt = [ 0.31, 0.29, 0.4 ]; auto arr = new double[][3]; arr[0] = midEnt; arr[1] = lowEnt; arr[2] = highEnt; schwartzSort!(entropy, "a > b")(arr); writeln(arr[0]); // highEnt writeln(arr[1]); // midEnt writeln(arr[2]); // lowEnt assert(isSorted!("a > b")(map!(entropy)(arr)));
- void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r, size_t n)
Constraints: if (isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range); -
Переупорядочивает диапазон случайного доступа
rтаким образом, чтобы диапазонr[0 .. mid]был таким же, как если бы весьrбыл отсортирован, а диапазонr[mid .. r.length]не упорядочен определенным образом. Выполняет Ο(r.length * log(mid)) вычисленийpred. Реализация просто вызываетtopN!(less, ss)(r, n)и затемsort!(less, ss)(r[0 .. n]).- Параметры:
less Предикат для сортировки. ss Используемая стратегия перестановки. Range rДиапазон случайного доступа, который нужно переупорядочить. size_t nДлина начального сегмента rдля сортировки.
- Примеры:
-
int[] a = [ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ]; partialSort(a, 5); writeln(a[0 .. 5]); // [0, 1, 2, 3, 4]
- void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range1, Range2)(Range1 r1, Range2 r2)
Constraints: if (isRandomAccessRange!Range1 && hasLength!Range1 && isInputRange!Range2 && is(ElementType!Range1 == ElementType!Range2) && hasLvalueElements!Range1 && hasLvalueElements!Range2); -
Хранит наименьшие элементы из двух диапазонов в левом диапазоне в отсортированном порядке.
- Параметры:
less Предикат для сортировки. ss Используемая стратегия перестановки. Range1 r1Первый диапазон. Range2 r2Второй диапазон.
- Примеры:
-
int[] a = [5, 7, 2, 6, 7]; int[] b = [2, 1, 5, 6, 7, 3, 0]; partialSort(a, b); writeln(a); // [0, 1, 2, 2, 3]
- auto topN(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r, size_t nth)
Constraints: if (isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && hasAssignableElements!Range); -
Переупорядочивает диапазон
rс помощьюswapтак, чтоr[nth]ссылается на элемент, который там бы оказался, если бы диапазон был полностью отсортирован. Кроме того, он также разбиваетrтаким образом, что все элементыe1отr[0]доr[nth]удовлетворяют!less(r[nth], e1), а все элементыe2отr[nth]доr[r.length]удовлетворяют!less(e2, r[nth]). По сути, он находит n-й по величине (согласноless) элементы вr. Выполняет ожидаемое Ο(r.length) (если неустойчивая) или Ο(r.length * log(r.length)) (если устойчивая) вычисленийlessиswap.Если
n >= r.length, алгоритм не оказывает никакого влияния и возвращаетr[0 .. r.length].- Параметры:
less Предикат для сортировки. ss Используемая стратегия перестановки. Range rДиапазон случайного доступа для переупорядочения. size_t nthИндекс элемента, который должен быть в отсортированном положении после завершения функции.
- См. также:
-
topNIndex,
- Ошибки:
- Устойчивый topN еще не реализован.
- Примеры:
-
int[] v = [ 25, 7, 9, 2, 0, 5, 21 ]; topN!"a < b"(v, 100); writeln(v); // [25, 7, 9, 2, 0, 5, 21] auto n = 4; topN!((a, b) => a < b)(v, n); writeln(v[n]); // 9
- auto topN(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range1, Range2)(Range1 r1, Range2 r2)
Constraints: if (isRandomAccessRange!Range1 && hasLength!Range1 && isInputRange!Range2 && is(ElementType!Range1 == ElementType!Range2) && hasLvalueElements!Range1 && hasLvalueElements!Range2); -
Хранит наименьшие элементы из двух диапазонов в левом диапазоне.
- Параметры:
less Предикат для сортировки. ss Используемая стратегия перестановки. Range1 r1Первый диапазон. Range2 r2Второй диапазон.
- Примеры:
-
int[] a = [ 5, 7, 2, 6, 7 ]; int[] b = [ 2, 1, 5, 6, 7, 3, 0 ]; topN(a, b); sort(a); writeln(a); // [0, 1, 2, 2, 3]
- TRange topNCopy(alias less = "a < b", SRange, TRange)(SRange source, TRange target, SortOutput sorted = No.sortOutput)
Constraints: if (isInputRange!SRange && isRandomAccessRange!TRange && hasLength!TRange && hasSlicing!TRange); -
Копирует верхние
nэлементы входного диапазонаsourceв диапазон случайного доступаtarget, гдеn = target.length. Элементыsourceне трогаются. Еслиsortedравноtrue, целевой диапазон отсортирован. В противном случае, целевой диапазон сохраняет свойство кучи.- Параметры:
less Предикат для сортировки. SRange sourceИсходный диапазон. TRange targetЦелевой диапазон. SortOutput sortedФлаг сортировки копируемых элементов в target.
- Возвращаемое значение:
- Срез
target, содержащий скопированные элементы.
- Примеры:
-
import std.typecons : Yes; int[] a = [ 10, 16, 2, 3, 1, 5, 0 ]; int[] b = new int[3]; topNCopy(a, b, Yes.sortOutput); writeln(b); // [0, 1, 2]
- void topNIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex)(Range r, RangeIndex index, SortOutput sorted = No.sortOutput)
Constraints: if (isRandomAccessRange!Range && isRandomAccessRange!RangeIndex && hasAssignableElements!RangeIndex); -
Учитывая диапазон элементов, создает индекс его верхних n элементов (т.е., первых n элементов, если бы диапазон был отсортирован).
Аналогично
topN, за исключением того, что диапазон не изменяется.- Параметры:
less Бинарный предикат, определяющий порядок элементов диапазона. По умолчанию a < b.ss (Не реализовано.) Укажите стратегию перестановки. Range rДиапазон случайного доступа элементов, для которых нужно создать индекс. RangeIndex indexДиапазон случайного доступа с присваиваемыми элементами для построения индекса. Длина этого диапазона определяет, сколько верхних элементов индексировать в r. Этот индексный диапазон может содержать целочисленные элементы, в таком случае создаваемый индекс будет содержать индексы с нулевой базой вr; или он может содержать указатели на тип элементовr, в таком случае создаваемый индекс будет указателями на верхние элементы вr.SortOutput sortedОпределяет, следует ли сортировать индекс по элементам, на которые они ссылаются.
- См. также:
-
topN,topNCopy.
- Ошибки:
- Параметр стратегии перестановки еще не реализован; в настоящее время он игнорируется.
- Примеры:
-
import std.typecons : Yes; // Construct index to top 3 elements using numerical indices: int[] a = [ 10, 2, 7, 5, 8, 1 ]; int[] index = new int[3]; topNIndex(a, index, Yes.sortOutput); assert(index == [5, 1, 3]); // because a[5]==1, a[1]==2, a[3]==5 // Construct index to top 3 elements using pointer indices: int*[] ptrIndex = new int*[3]; topNIndex(a, ptrIndex, Yes.sortOutput); writeln(ptrIndex); // [&a[5], &a[1], &a[3]]
- bool nextPermutation(alias less = "a < b", BidirectionalRange)(BidirectionalRange range)
Constraints: if (isBidirectionalRange!BidirectionalRange && hasSwappableElements!BidirectionalRange); -
Переставляет
rangeна месте в следующую лексикографически большую перестановку.Предикат
lessопределяет лексикографический порядок, который будет использоваться для диапазона.
Если диапазон в настоящее время является лексикографически наибольшей перестановкой, он переставляется обратно в наименьшую перестановку, и возвращается false. В противном случае возвращается true. Таким образом, можно сгенерировать все перестановки диапазона, отсортировав его в соответствии сless, что даст лексикографически наименьшую перестановку, а затем вызывать nextPermutation до тех пор, пока он не вернёт false. Гарантируется, что это сгенерирует все различные перестановки диапазона ровно один раз. Если в диапазоне N элементов и все они уникальны, то будет сгенерировано N! перестановок. В противном случае, если есть некоторые повторяющиеся элементы, будет сгенерировано меньше перестановок.// Enumerate all permutations int[] a = [1,2,3,4,5]; do { // use the current permutation and // proceed to the next permutation of the array. } while (nextPermutation(a));- Параметры:
less Порядок, который будет использоваться для определения лексикографического порядка перестановок. BidirectionalRange rangeДиапазон для перестановки.
- Возвращает:
- false, если диапазон был лексикографически наибольшим, в этом случае диапазон возвращается к лексикографически наименьшей перестановке; в противном случае возвращает true.
- См. также:
-
std.algorithm.iteration.permutations.
- Примеры:
-
// Step through all permutations of a sorted array in lexicographic order int[] a = [1,2,3]; writeln(nextPermutation(a)); // true writeln(a); // [1, 3, 2] writeln(nextPermutation(a)); // true writeln(a); // [2, 1, 3] writeln(nextPermutation(a)); // true writeln(a); // [2, 3, 1] writeln(nextPermutation(a)); // true writeln(a); // [3, 1, 2] writeln(nextPermutation(a)); // true writeln(a); // [3, 2, 1] writeln(nextPermutation(a)); // false writeln(a); // [1, 2, 3]
- Примеры:
-
// Step through permutations of an array containing duplicate elements: int[] a = [1,1,2]; writeln(nextPermutation(a)); // true writeln(a); // [1, 2, 1] writeln(nextPermutation(a)); // true writeln(a); // [2, 1, 1] writeln(nextPermutation(a)); // false writeln(a); // [1, 1, 2]
- bool nextEvenPermutation(alias less = "a < b", BidirectionalRange)(BidirectionalRange range)
Constraints: if (isBidirectionalRange!BidirectionalRange && hasSwappableElements!BidirectionalRange); -
Переставляет
rangeна месте в следующую лексикографически большую чётную перестановку.Предикат
lessопределяет лексикографический порядок, который будет использоваться для диапазона.
Чётная перестановка — это перестановка, которая получается путём обмена чётного количества пар элементов в исходном диапазоне. Множество чётных перестановок отличается от множества всех перестановок только тогда, когда в диапазоне нет повторяющихся элементов. Если диапазон содержит N уникальных элементов, то существует ровно N!/2 чётных перестановок.
Если диапазон уже является лексикографически наибольшей чётной перестановкой, он переставляется обратно в наименьшую чётную перестановку, и возвращается false. В противном случае возвращается true, и диапазон изменяется на месте, чтобы стать лексикографически следующей чётной перестановкой.
Таким образом, можно сгенерировать чётные перестановки диапазона с уникальными элементами, начиная с лексикографически наименьшей перестановки и многократно вызывая nextEvenPermutation, пока она не вернёт false.// Enumerate even permutations int[] a = [1,2,3,4,5]; do { // use the current permutation and // proceed to the next even permutation of the array. } while (nextEvenPermutation(a));Также можно сгенерировать нечётные перестановки диапазона, заметив, что перестановки подчиняются правилу, что чётная + чётная = чётная, а нечётная + чётная = нечётная. Таким образом, поменяв последние два элемента лексикографически наименьшего диапазона, он превращается в первую нечётную перестановку. Затем, вызвав nextEvenPermutation для этой первой нечётной перестановки, будет сгенерирована следующая чётная перестановка относительно этой нечётной перестановки, которая фактически является следующей нечётной перестановкой исходного диапазона. Таким образом, вызывая многократно nextEvenPermutation, пока она не вернёт false, перечисляются нечётные перестановки исходного диапазона.// Enumerate odd permutations int[] a = [1,2,3,4,5]; swap(a[$-2], a[$-1]); // a is now the first odd permutation of [1,2,3,4,5] do { // use the current permutation and // proceed to the next odd permutation of the original array // (which is an even permutation of the first odd permutation). } while (nextEvenPermutation(a));- Предупреждение
- Поскольку чётные перестановки отличаются от всех перестановок только в случае уникальности элементов диапазона, эта функция предполагает, что в диапазоне нет повторяющихся элементов при указанном порядке. Если это не так, некоторые перестановки могут не быть сгенерированы. Когда диапазон содержит не уникальные элементы, вы должны использовать nextPermutation вместо этого.
- Параметры:
less Порядок, который будет использоваться для определения лексикографического порядка перестановок. BidirectionalRange rangeДиапазон для перестановки.
- Возвращает:
- false, если диапазон был лексикографически наибольшим, в этом случае диапазон возвращается к лексикографически наименьшей перестановке; в противном случае возвращает true.
- Примеры:
-
// Step through even permutations of a sorted array in lexicographic order int[] a = [1,2,3]; writeln(nextEvenPermutation(a)); // true writeln(a); // [2, 3, 1] writeln(nextEvenPermutation(a)); // true writeln(a); // [3, 1, 2] writeln(nextEvenPermutation(a)); // false writeln(a); // [1, 2, 3]
- Примеры:
- Чётные перестановки полезны для генерации координат некоторых геометрических фигур. Вот нетривиальный пример:
import std.math : sqrt; // Print the 60 vertices of a uniform truncated icosahedron (soccer ball) enum real Phi = (1.0 + sqrt(5.0)) / 2.0; // Golden ratio real[][] seeds = [ [0.0, 1.0, 3.0*Phi], [1.0, 2.0+Phi, 2.0*Phi], [Phi, 2.0, Phi^^3] ]; size_t n; foreach (seed; seeds) { // Loop over even permutations of each seed do { // Loop over all sign changes of each permutation size_t i; do { // Generate all possible sign changes for (i=0; i < seed.length; i++) { if (seed[i] != 0.0) { seed[i] = -seed[i]; if (seed[i] < 0.0) break; } } n++; } while (i < seed.length); } while (nextEvenPermutation(seed)); } writeln(n); // 60
- ref Range nthPermutation(Range)(auto ref Range range, const ulong perm)
Constraints: if (isRandomAccessRange!Range && hasLength!Range); -
Переставляет
rangeвpermперестановку. Алгоритм имеет постоянную временную сложность относительно количества созданных перестановок. Из-за количества уникальных значенийulongтолько первые 21 элементrangeмогут быть переставлены. Остальная часть диапазона, следовательно, не будет переставлена. Этот алгоритм использует код Лемера.Алгоритм работает следующим образом:
auto pem = [4,0,4,1,0,0,0]; // permutation 2982 in factorial auto src = [0,1,2,3,4,5,6]; // the range to permutate auto i = 0; // range index // range index iterates pem and src in sync // pem[i] + i is used as index into src // first src[pem[i] + i] is stored in t auto t = 4; // tmp value src = [0,1,2,3,n,5,6]; // then the values between i and pem[i] + i are moved one // to the right src = [n,0,1,2,3,5,6]; // at last t is inserted into position i src = [4,0,1,2,3,5,6]; // finally i is incremented ++i; // this process is repeated while i < pem.length t = 0; src = [4,n,1,2,3,5,6]; src = [4,0,1,2,3,5,6]; ++i; t = 6; src = [4,0,1,2,3,5,n]; src = [4,0,n,1,2,3,5]; src = [4,0,6,1,2,3,5];- Возвращает:
- Переставленный диапазон.
- Параметры:
Range rangeДиапазон для перестановки. Исходный порядок будет потерян. ulong permПерестановка, в которую необходимо переставить range.
- Примеры:
-
auto src = [0, 1, 2, 3, 4, 5, 6]; auto rslt = [4, 0, 6, 2, 1, 3, 5]; src = nthPermutation(src, 2982); writeln(src); // rslt
- bool nthPermutationImpl(Range)(auto ref Range range, ulong perm)
Constraints: if (isRandomAccessRange!Range && hasLength!Range); -
- Возвращает:
-
trueв случае успешной перестановки,falseв случае, если уpermбыло больше цифр в системе факториалов, чем элементов в диапазоне. Этот случай не должен возникать, так как это приведёт к обращениям к элементам за пределами диапазона.
- Примеры:
-
auto src = [0, 1, 2, 3, 4, 5, 6]; auto rslt = [4, 0, 6, 2, 1, 3, 5]; bool worked = nthPermutationImpl(src, 2982); assert(worked); writeln(src); // rslt
© 1999–2021 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_algorithm_sorting.html