我正在寻找一种算法来合并多个排序的序列,让我们说X排序的序列有n个元素,在javascript中放入一个排序的序列,你能提供一些例子吗?
注意:我不想使用任何库.试图解决https://icpc.kattis.com/problems/stacking
在条件下,合并排序数组所需的最小操作数是多少:
拆分:通过提升堆栈的任何顶部并将其放在一边以形成新堆栈,可以将单个堆栈拆分为两个堆栈.
加入:可以通过将一个堆叠放在另一个堆叠的顶部来连接两个堆栈.仅当顶部堆叠的底板不大于底部堆叠的顶板时才允许这样做,即,必须正确地订购连接的堆叠.
天真的方法是连接所有k
序列,并对结果进行排序.但如果每个序列都有n
元素,那么成本就是O(k*n*log(k*n))
.太多了!
相反,您可以使用优先级队列或堆.像这样:
var sorted = []; var pq = new MinPriorityQueue(function(a, b) { return a.number < b.number; }); var indices = new Array(k).fill(0); for (var i=0; i0) { pq.insert({number: sequences[i][0], sequence: i}); } while (!pq.empty()) { var min = pq.findAndDeleteMin(); sorted.push(min.number); ++indices[min.sequence]; if (indices[min.sequence] < sequences[i].length) pq.insert({ number: sequences[i][indices[min.sequence]], sequence: min.sequence }); }
优先级队列最多只包含多个k
元素,每个序列一个.您将继续提取最小值,并在该序列中插入以下元素.
有了这个,成本将是:
k*n
插入k
元素堆:O(k*n)
k*n
k
元素堆中的删除:O(k*n*log(k))
每个数字的各种常量操作: O(k*n)
所以只有 O(k*n*log(k))
这个问题已经解决了一个多世纪,回到了Hermann Hollerith和电子贺卡.大量的信用卡,例如人口普查产生的信用卡,通过将它们分成批次,对每个批次进行分类,然后合并分类的批次 - 所谓的 "合并排序"进行排序.你在1950年的科幻电影中看到旋转的那些磁带驱动器很可能将多个分类的磁带合并到一个磁带上.
您可以在https://en.wikipedia.org/wiki/Merge_algorithm找到所需的所有算法.用JS编写这个很简单.有关N路合并的算法问题,请参阅更多信息.另请参阅这个问题,这个问题几乎完全相同,但我不确定任何答案都非常好.
天真的连续和度假方法甚至没有资格作为问题的答案.有点天真的接下来最小值从任何输入方法要好得多,但不是最优的,因为找到下一个输入来获取值需要花费更多的时间.这就是使用称为"最小堆"或"优先级队列"的最佳解决方案的原因.
这是一个真正的简单版本,除了能够看到它正在做什么之外,我没有声称要进行优化:
const data = [[1, 3, 5], [2, 4]];
// Merge an array or pre-sorted arrays, based on the given sort criteria.
function merge(arrays, sortFunc) {
let result = [], next;
// Add an 'index' property to each array to keep track of where we are in it.
arrays.forEach(array => array.index = 0);
// Find the next array to pull from.
// Just sort the list of arrays by their current value and take the first one.
function findNext() {
return arrays.filter(array => array.index < array.length)
.sort((a, b) => sortFunc(a[a.index], b[b.index]))[0];
}
// This is the heart of the algorithm.
while (next = findNext()) result.push(next[next.index++]);
return result;
}
function arithAscending(a, b) { return a - b; }
console.log(merge(data, arithAscending));