diff --git a/TODO b/TODO index 580d8dc22..18100ca5a 100644 --- a/TODO +++ b/TODO @@ -1,15 +1,4 @@ -SORTS, IN PAIR - -Instead of mapFn, provide pair array to define sort mapping. -selectionSort, insertionSort, bubbleSort, mergeSort, (are all stable?) -quickSort, shellSort, radixSort, timSort, heapSort -https://en.wikipedia.org/wiki/Sorting_algorithm -https://www.npmjs.com/package/sort-algorithms-js -https://dl.acm.org/doi/10.5555/1778580.1778601 -https://stackoverflow.com/questions/463105/in-place-radix-sort/474040#474040 - - -MINNTH, MAXNTH, SORTEDSLICE (ARRAYVIEW) +MINNTH, MAXNTH Need only part of sorted array? [bag][nth] ... Selection algorithm: Quickselect @@ -23,75 +12,3 @@ PARSE, OTHERS INDEX -VE - moveWithin - - -OLD SORT ALGORITHMS - -/** - * Arrange values in order! - * @param x an array (updated!) - * @param fc compare function (a, b) - * @param fm map function (v, i, x) - * @param fs swap function (x, i, j) - * @returns x | x[i] ≤ x[j] ∀ i ≤ j - */ -function bubbleSort$(x: T[], fc: CompareFunction | null=null, fm: MapFunction | null=null, fs: SwapFunction | null=null): T[] { - var fc = fc || COMPARE; - var fm = fm || IDENTITY; // TODO: use map function - var fs = fs || swap$; - var X = x.length; - for (var i=0; i 0) fs(x, i, j); - } - return x; -} - - -/** - * Arrange values in order! - * @param x an array (updated!) - * @param fc compare function (a, b) - * @param fm map function (v, i, x) - * @param fs swap function (x, i, j) - * @returns x | x[i] ≤ x[j] ∀ i ≤ j - */ -function selectionSort$(x: T[], fc: CompareFunction | null=null, fm: MapFunction | null=null, fs: SwapFunction | null=null): T[] { - var fc = fc || COMPARE; - var fm = fm || IDENTITY; // TODO: use map function - var fs = fs || swap$; - var X = x.length; - for (var i=0; i 0) l = j; - fs(x, i, l); - } - return x; -} - - -// TODO: Check if this is correct! -/** - * Arrange values in order! - * @param x an array (updated!) - * @param fc compare function (a, b) - * @param fm map function (v, i, x) - * @param fs swap function (x, i, j) - * @returns x | x[i] ≤ x[j] ∀ i ≤ j - */ -function insertionSortOld$(x: T[], fc: CompareFunction | null=null, fm: MapFunction | null=null, fs: SwapFunction | null=null): T[] { - var fc = fc || COMPARE; - var fm = fm || IDENTITY; // TODO: use map function - var fs = fs || swap$; // TODO: use swap function - var X = x.length; - for (var i=X-2; i>=0; --i) { - var xv = x[i], mv = x[i]; - for (var j=i+1; j(x: T[], fc: CompareFunction | null=null, fm: MapFunction | null=null): T { +export function minimum(x: T[], fc: CompareFunction | null=null, fm: MapFunction | null=null): T { var i = searchMinimumValue(x, fc, fm); return x[i]; } +export {minimum as min}; /** @@ -686,10 +687,11 @@ export function min(x: T[], fc: CompareFunction | null=null, fm: Ma * @param fm map function (v, i, x) * @returns [min_index, min_value] */ -export function minEntry(x: T[], fc: CompareFunction | null=null, fm: MapFunction | null=null): [number, T] { +export function minimumEntry(x: T[], fc: CompareFunction | null=null, fm: MapFunction | null=null): [number, T] { var i = searchMinimumValue(x, fc, fm); return [i, x[i]]; } +export {minimumEntry as minEntry}; /** @@ -699,10 +701,11 @@ export function minEntry(x: T[], fc: CompareFunction | null=null, f * @param fm map function (v, i, x) * @returns v | v ≥ vᵢ; vᵢ ∈ x */ -export function max(x: T[], fc: CompareFunction | null=null, fm: MapFunction | null=null): T { +export function maximum(x: T[], fc: CompareFunction | null=null, fm: MapFunction | null=null): T { var i = searchMaximumValue(x, fc, fm); return x[i]; } +export {maximum as max}; /** @@ -712,10 +715,11 @@ export function max(x: T[], fc: CompareFunction | null=null, fm: Ma * @param fm map function (v, i, x) * @returns [max_index, max_value] */ -export function maxEntry(x: T[], fc: CompareFunction | null=null, fm: MapFunction | null=null): [number, T] { +export function maximumEntry(x: T[], fc: CompareFunction | null=null, fm: MapFunction | null=null): [number, T] { var i = searchMaximumValue(x, fc, fm); return [i, x[i]]; } +export {maximumEntry as maxEntry}; /** @@ -753,6 +757,62 @@ export function rangeEntries(x: T[], fc: CompareFunction | null=nul } return [[mi, mv], [ni, nv]]; } + + +/** + * Find smallest values. + * @param x an array + * @param n number of values + * @param fc compare function (a, b) + * @param fm map function (v, i, x) + * @returns n smallest values in ascending order + */ +export function minimums(x: T[], n: number, fc: CompareFunction | null=null, fm: MapFunction | null=null): T[] { + var is = searchMinimumValues(x, n, fc, fm); + return is.map(i => x[i]); +} + + +/** + * Find smallest entries. + * @param x an array + * @param n number of values + * @param fc compare function (a, b) + * @param fm map function (v, i, x) + * @returns n smallest entries in ascending order + */ +export function minimumEntries(x: T[], n: number, fc: CompareFunction | null=null, fm: MapFunction | null=null): [number, T][] { + var is = searchMinimumValues(x, n, fc, fm); + return is.map(i => [i, x[i]]); +} + + +/** + * Find largest values. + * @param x an array + * @param n number of values + * @param fc compare function (a, b) + * @param fm map function (v, i, x) + * @returns n largest values in descending order + */ +export function maximums(x: T[], n: number, fc: CompareFunction | null=null, fm: MapFunction | null=null): T[] { + var is = searchMaximumValues(x, n, fc, fm); + return is.map(i => x[i]); +} + + +/** + * Find largest entries. + * @param x an array + * @param n number of values + * @param fc compare function (a, b) + * @param fm map function (v, i, x) + * @returns n largest entries in descending order + */ +export function maximumEntries(x: T[], n: number, fc: CompareFunction | null=null, fm: MapFunction | null=null): [number, T][] { + var is = searchMaximumValues(x, n, fc, fm); + return is.map(i => [i, x[i]]); +} // #endregion @@ -1498,6 +1558,51 @@ export function searchMaximumValue(x: T[], fc: CompareFunction | nu } +/** + * Find indices of minimum values. + * @param x an array + * @param n number of values + * @param fc compare function (a, b) + * @param fm map function (v, i, x) + * @returns indices of minimum values in ascending order + */ +export function searchMinimumValues(x: T[], n: number, fc: CompareFunction | null=null, fm: MapFunction | null=null): number[] { + var fc = fc || COMPARE; + var fm = fm || IDENTITY; + var X = x.length; + // Create a max heap of indices. + var IH = Math.min(n, X); + var ih = fromRange(0, IH); + buildMaxHeap$(ih, 0, IH, fc, i => fm(x[i], i, x), swapRaw$); + var wr = fm(x[ih[0]], ih[0], x); + // Search for minimum values, and update heap. + for (var i=n, I=x.length; i= 0) continue; + ih[0] = i; wr = w; + maxHeapify$(ih, 0, IH, 0, fc, i => fm(x[i], i, x), swapRaw$); + } + // Sort max heap in ascending order. + ih.sort((i, j) => fc(fm(x[i], i, x), fm(x[j], j, x))); + return ih; +} + + +/** + * Find indices of maximum values. + * @param x an array + * @param n number of values + * @param fc compare function (a, b) + * @param fm map function (v, i, x) + * @returns indices of maximum values in descending order + */ +export function searchMaximumValues(x: T[], n: number, fc: CompareFunction | null=null, fm: MapFunction | null=null): number[] { + var fc = fc || COMPARE; + var fd = (a: T|U, b: T|U) => -fc(a, b); + return searchMinimumValues(x, n, fd, fm); +} + + /** * Find first index of an unsorted value. * @param x an array @@ -3272,8 +3377,8 @@ function buildReverseMinHeap$(x: T[], i: number, I: number, fc: CompareF */ function reverseMinHeapify$(x: T[], i: number, I: number, r: number, fc: CompareFunction, fm: MapFunction, fs: SwapFunction): void { var s = r; // Index of smallest value - var lt = 2*r - I; // Reverse of lt = 2*r+1 - var rt = lt - 1; // Reverse of rt = 2*r+2 + var lt = 2*r - I; // Left child, reverse of lt = 2*r+1 + var rt = lt - 1; // Right child, reverse of rt = 2*r+2 if (lt>=i && fc(fm(x[lt], lt, x), fm(x[s], s, x)) < 0) s = lt; // Left child is smaller? if (rt>=i && fc(fm(x[rt], rt, x), fm(x[s], s, x)) < 0) s = rt; // Right child is smaller? if (s !== r) { // Smallest is not root? @@ -3283,6 +3388,36 @@ function reverseMinHeapify$(x: T[], i: number, I: number, r: number, fc: } +// Build a max-heap, where root node is the smallest and placed at the beginning. +function buildMaxHeap$(x: T[], i: number, I: number, fc: CompareFunction, fm: MapFunction, fs: SwapFunction): void { + for (var r=i+Math.floor((I-i)/2)-1; r>=i; --r) + maxHeapify$(x, i, I, r, fc, fm, fs); +} + + +/** + * Max-heapify values, such that root node is the largest and placed at the beginning. + * @param x an array (updated!) + * @param i start index + * @param I end index (exclusive) + * @param r root index + * @param fc compare function (a, b) + * @param fm map function (v, i, x) + * @param fs swap function (x, i, j) + */ +function maxHeapify$(x: T[], i: number, I: number, r: number, fc: CompareFunction, fm: MapFunction, fs: SwapFunction): void { + var s = r; // Index of largest value + var lt = 2*r - i + 1; // Left child, like lt = 2*r+1 + var rt = lt + 1; // Right child, like rt = 2*r+2 + if (lt 0) s = lt; // Left child is larger? + if (rt 0) s = rt; // Right child is larger? + if (s !== r) { // Largest is not root? + fs(x, s, r); // Swap root with largest + maxHeapify$(x, i, I, s, fc, fm, fs); // Rebuild heap + } +} + + /** * Partially arrange values in order! * @param x an array (updated!) diff --git a/wiki b/wiki index 1706a1f2f..fa413b6bd 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 1706a1f2fa91905fb0ffd79900a065aee3ea20a7 +Subproject commit fa413b6bd06c8981553a81ce60da6e3646858f04