注意:我不想使用任何库。试图解决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; i<k; ++i) if (sequences[i].length > 0) {
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)和庞切卡(punchcards)。巨大的Punchcard集合,例如人口普查产生的Punchcard集合,通过将它们划分为批次,对每个批次进行排序,然后合并排序的批次,即所谓的“合并排序”。你在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));
我正在做一个项目,所以我把我的问题简化为: 任何帮助都将不胜感激。
问题内容: 已关闭 。这个问题是基于观点的。它当前不接受答案。 想改善这个问题吗? 更新问题,以便通过编辑此帖子以事实和引用的形式回答。 7年前关闭。 改善这个问题 我想将排序的列表合并到一个列表中。这个解决方案如何?我相信它运行时间为O(n)。有任何明显的缺陷,效率低下或样式问题吗? 我真的不喜欢为“这是第一次迭代”设置标志并使用它来确保“最低”具有默认值的习惯用法。有没有更好的办法解决呢? 注
我正试图想出一个分而治之的算法来合并j个排序列表和n个元素,但我被卡住了;我不知道如何把这个问题分成更小的子问题。我希望合并算法更高效,如下所示: 合并前两个列表;然后将结果列表与第三个列表合并;然后将结果列表与第四个列表合并,以此类推,该列表取O(j*jn)。
我想写一个时间O(n*lgk)的算法,将k个排序数组合并成一个排序数组,其中n是所有输入数组的元素总数。 你能告诉我怎么做吗? 编辑:我编写了以下算法: 你能告诉我这是否正确吗?
这些是家庭作业问题,但我想了解它们背后的概念,而不仅仅是得到答案。 我知道MergeSort的运行时间是O(nlogn)。似乎合并方法必须运行 n 次(因为它必须合并所有数组,最终会有 n 个数组)。因此,我想我可以推断出 MergeSort() 方法将被称为 logn times。我也认为这是有道理的,因为它正在划分数组,所以它会一直将自己除以 2,所以 logn。 因此,我觉得答案分别是C和A