std.sort
Reed's standard library. Imported with use std.sort; not on disk.
Functions
| cmp_asc | Ascending order. |
| cmp_desc | Descending order. |
| cmp_asc_u | Ascending unsigned order. |
| sort | Sorts values in place in ascending order. |
| sort_by | Sorts values in place using compare, by heapsort. |
| sift_down | Restores the max-heap property at root over values[0..count]. |
| sort_stable | Sorts values in place using compare, preserving the relative order of equal |
| merge_runs | Merges the sorted runs values[lo..mid] and values[mid..hi] into scratch[lo..hi]. |
| is_sorted | Whether values is sorted in ascending order. |
| is_sorted_by | Whether values is ordered according to compare. |
| binary_search | Finds target in an ascending-sorted array. |
| binary_search_by | Finds target in an array sorted according to compare. |
| lower_bound | The index of the first element not ordered before target. |
| upper_bound | The index of the first element ordered after target. |
| reverse | Reverses values in place. |
| dedup | Removes consecutive duplicates from a sorted array, in place. |
func cmp_asc(a: i32, b: i32) -> i32
Ascending order.
Written as two comparisons rather than a - b, which overflows for operands spanning more than the i32 range and would then order them backwards -- the single most common bug in hand-written integer comparators.
- Parameters
- a — the left value
- b — the right value
- Returns
- negative, zero, or positive as
a orders before, with, or after b
- See also
cmp_desc
Source
func cmp_asc(a: i32, b: i32) -> i32 {
if (a < b) { return -1; }
if (a > b) { return 1; }
return 0;
}
func cmp_desc(a: i32, b: i32) -> i32
- Parameters
- a — the left value
- b — the right value
- Returns
- negative, zero, or positive as
a orders after, with, or before b
- See also
cmp_asc
Source
func cmp_desc(a: i32, b: i32) -> i32 {
if (a < b) { return 1; }
if (a > b) { return -1; }
return 0;
}
func cmp_asc_u(a: i32, b: i32) -> i32
Ascending unsigned order.
Distinct from cmp_asc: -1 sorts last here (as 4294967295) and first there.
- Parameters
- a — the left value
- b — the right value
- Returns
- negative, zero, or positive by unsigned comparison
Source
func cmp_asc_u(a: i32, b: i32) -> i32 {
if (a.lt_u(b)) { return -1; }
if (a.gt_u(b)) { return 1; }
return 0;
}
func sort(values: &I32Values) -> void
Sorts values in place in ascending order.
Shorthand for sort_by(values, &cmp_asc).
- Parameters
- values — the array to sort
- See also
sort_by, sort_stable
Source
func sort(values: &I32Values) {
sort_by(values, &cmp_asc);
}
func sort_by(values: &I32Values, compare: &IntCmp) -> void
Sorts values in place using compare, by heapsort.
O(n log n) in the worst case with no allocation and no recursion. Not stable: equal elements may be reordered. Use sort_stable when that matters.
- Parameters
- values — the array to sort
- compare — the ordering to impose
- See also
sort_stable
Source
func sort_by(values: &I32Values, compare: &IntCmp) {
let n: i32 = #values;
if (n < 2) { return; }
var node: i32 = n / 2;
loop build() {
if (node == 0) { break build(); }
node = node - 1;
sift_down(values, node, n, compare);
continue build();
}
var end: i32 = n;
loop drain() {
if (end <= 1) { break drain(); }
end = end - 1;
let top: i32 = values[0];
values[0] = values[end];
values[end] = top;
sift_down(values, 0, end, compare);
continue drain();
}
}
func sift_down(values: &I32Values, root: i32, count: i32, compare: &IntCmp) -> void
Restores the max-heap property at root over values[0..count].
Not pub: an implementation detail of sort_by, and meaningless outside a heap.
Source
func sift_down(values: &I32Values, root: i32, count: i32, compare: &IntCmp) {
var parent: i32 = root;
loop descend() {
let left: i32 = parent * 2 + 1;
if (left >= count) { break descend(); }
var largest: i32 = left;
let right: i32 = left + 1;
if (right < count && compare(values[right], values[left]) > 0) { largest = right; }
if (compare(values[largest], values[parent]) <= 0) { break descend(); }
let t: i32 = values[parent];
values[parent] = values[largest];
values[largest] = t;
parent = largest;
continue descend();
}
}
func sort_stable(values: &I32Values, compare: &IntCmp) -> void
Sorts values in place using compare, preserving the relative order of equal elements.
A bottom-up merge sort: O(n log n) always, and stable, at the cost of one scratch array the size of the input. Iterative, so there is no recursion depth to exhaust.
- Parameters
- values — the array to sort
- compare — the ordering to impose
- See also
sort_by
Source
func sort_stable(values: &I32Values, compare: &IntCmp) {
let n: i32 = #values;
if (n < 2) { return; }
let scratch: &I32Values = new I32Values[n]{};
var width: i32 = 1;
loop passes() {
if (width >= n) { break passes(); }
var lo: i32 = 0;
loop runs() {
if (lo >= n) { break runs(); }
let mid: i32 = lo + width < n ? lo + width : n;
let hi: i32 = lo + width * 2 < n ? lo + width * 2 : n;
merge_runs(values, scratch, lo, mid, hi, compare);
lo = lo + width * 2;
continue runs();
}
values.copy(0, scratch, 0, n);
width = width * 2;
continue passes();
}
}
func merge_runs(values: &I32Values, scratch: &I32Values, lo: i32, mid: i32, hi: i32, compare: &IntCmp) -> void
Merges the sorted runs values[lo..mid] and values[mid..hi] into scratch[lo..hi].
Takes the left element when the two compare equal, which is exactly what makes the enclosing sort stable.
Source
func merge_runs(
values: &I32Values,
scratch: &I32Values,
lo: i32,
mid: i32,
hi: i32,
compare: &IntCmp,
) {
var left: i32 = lo;
var right: i32 = mid;
var out: i32 = lo;
loop merge() {
if (out >= hi) { break merge(); }
let take_left: i32 = left < mid && (right >= hi || compare(values[right], values[left]) >= 0);
if (take_left != 0) {
scratch[out] = values[left];
left = left + 1;
} else {
scratch[out] = values[right];
right = right + 1;
}
out = out + 1;
continue merge();
}
}
func is_sorted(values: &I32Values) -> i32
Whether values is sorted in ascending order.
- Parameters
- values — the array to inspect
- Returns
1 when sorted, 0 otherwise
- See also
is_sorted_by
Source
func is_sorted(values: &I32Values) -> i32 {
return is_sorted_by(values, &cmp_asc);
}
func is_sorted_by(values: &I32Values, compare: &IntCmp) -> i32
Whether values is ordered according to compare.
- Parameters
- values — the array to inspect
- compare — the ordering to check against
- Returns
1 when ordered, 0 otherwise
Source
func is_sorted_by(values: &I32Values, compare: &IntCmp) -> i32 {
for i in 1..#values {
if (compare(values[i - 1], values[i]) > 0) { return 0; }
}
return 1;
}
func binary_search(values: &I32Values, target: i32) -> (i32, i32)
Finds target in an ascending-sorted array.
Precondition: values is sorted ascending. This is not checked, because verifying it would cost the linear scan the search exists to avoid; on unsorted input the result is unspecified but the call still terminates and never traps.
On a miss, index is the position where target would be inserted to keep the array sorted, so one call serves both lookup and ordered insertion. When several elements equal target, which one is found is unspecified.
- Parameters
- values — the sorted array to search
- target — the value to find
- Returns
(index, found) -- the index or insertion point, and 1 when found
- See also
binary_search_by
Source
func binary_search(values: &I32Values, target: i32) -> (i32, i32) {
return binary_search_by(values, target, &cmp_asc);
}
func binary_search_by(values: &I32Values, target: i32, compare: &IntCmp) -> (i32, i32)
Finds target in an array sorted according to compare.
- Parameters
- values — the sorted array to search
- target — the value to find
- compare — the ordering the array is sorted by
- Returns
(index, found) -- the index or insertion point, and 1 when found
- See also
binary_search
Source
func binary_search_by(values: &I32Values, target: i32, compare: &IntCmp) -> (i32, i32) {
var lo: i32 = 0;
var hi: i32 = #values;
loop narrow() {
if (lo >= hi) { break narrow(); }
let mid: i32 = lo + (hi - lo) / 2;
let order: i32 = compare(values[mid], target);
if (order == 0) { return (mid, 1); }
if (order < 0) { lo = mid + 1; } else { hi = mid; }
continue narrow();
}
return (lo, 0);
}
func lower_bound(values: &I32Values, target: i32) -> i32
The index of the first element not ordered before target.
The insertion point that keeps a sorted array sorted while placing target before any equal elements. Together with upper_bound it delimits the run of equal elements.
- Parameters
- values — the sorted array to search
- target — the value to place
- Returns
- the index
- See also
upper_bound
Source
func lower_bound(values: &I32Values, target: i32) -> i32 {
var lo: i32 = 0;
var hi: i32 = #values;
loop narrow() {
if (lo >= hi) { break narrow(); }
let mid: i32 = lo + (hi - lo) / 2;
if (values[mid] < target) { lo = mid + 1; } else { hi = mid; }
continue narrow();
}
return lo;
}
func upper_bound(values: &I32Values, target: i32) -> i32
The index of the first element ordered after target.
- Parameters
- values — the sorted array to search
- target — the value to place
- Returns
- the index
- See also
lower_bound
Source
func upper_bound(values: &I32Values, target: i32) -> i32 {
var lo: i32 = 0;
var hi: i32 = #values;
loop narrow() {
if (lo >= hi) { break narrow(); }
let mid: i32 = lo + (hi - lo) / 2;
if (values[mid] <= target) { lo = mid + 1; } else { hi = mid; }
continue narrow();
}
return lo;
}
func reverse(values: &I32Values) -> void
Reverses values in place.
- Parameters
- values — the array to reverse
Source
func reverse(values: &I32Values) {
var lo: i32 = 0;
var hi: i32 = #values - 1;
loop swap() {
if (lo >= hi) { break swap(); }
let t: i32 = values[lo];
values[lo] = values[hi];
values[hi] = t;
lo = lo + 1;
hi = hi - 1;
continue swap();
}
}
func dedup(values: &I32Values) -> i32
Removes consecutive duplicates from a sorted array, in place.
Returns the number of elements kept; the array's tail past that point is left as it was rather than cleared, since the array's length cannot change. Only consecutive duplicates are removed, so this deduplicates a sorted array completely and an unsorted one only partially -- the same contract as C++'s std::unique.
- Parameters
- values — the sorted array to deduplicate
- Returns
- how many distinct elements are now at the front
Source
func dedup(values: &I32Values) -> i32 {
if (#values == 0) { return 0; }
var kept: i32 = 1;
for i in 1..#values {
if (values[i] != values[kept - 1]) {
values[kept] = values[i];
kept = kept + 1;
}
}
return kept;
}
Types
| IntCmp | A comparator over two i32 values. |
type IntCmp = func(i32, i32) -> i32
A comparator over two i32 values.
Returns a negative value when a orders before b, zero when they are equivalent, and a positive value when a orders after b. Only the sign is examined.