Javascript:对长度为N的数组进行排序并获得顶部m的最佳方法
我有一个长度超过200000的巨大数组。我需要得到前10个值。我知道排序不是最好的解决方案。我尝试了以下解决方案:Javascript:对长度为N的数组进行排序并获得顶部m的最佳方法,javascript,arrays,algorithm,Javascript,Arrays,Algorithm,我有一个长度超过200000的巨大数组。我需要得到前10个值。我知道排序不是最好的解决方案。我尝试了以下解决方案: const sortBy = 'key'; const results = []; const m = 10; const N = array.length; while (array.length && results.length < m) { let currentMax = 0; let currentMaxIndex = 0;
const sortBy = 'key';
const results = [];
const m = 10;
const N = array.length;
while (array.length && results.length < m) {
let currentMax = 0;
let currentMaxIndex = 0;
array.forEach((record, i) => {
if (record[sortBy] >= currentMax) {
currentMax = record[sortBy];
currentMaxIndex = i;
}
});
results.push(...array.splice(currentMaxIndex, 1));
}
const sortBy='key';
常量结果=[];
常数m=10;
常数N=数组长度;
while(array.length&&results.length{
if(记录[sortBy]>=currentMax){
currentMax=记录[排序];
currentMaxIndex=i;
}
});
结果.push(…数组.splice(currentMaxIndex,1));
}
这里的数组是长度为200000的数组
问题是,我认为如果m
等于N
,那么
将比排序本身花费更多的时间。我想知道是否有
是一个更好的解决方案,可以处理这两种情况
谢谢你的帮助,但实际问题是m∈ (0,N)
m
可以取最大为N
的任何值。那么,在哪一点上最好切换到内置的排序
根据我的理解,当m
达到N
时,复杂性增加,排序是m==N
我已经用@t-j-crowder提供的示例进行了测试。从100个参赛作品中选出前10名的测试
当在m
中使用不同的值进行测试时,更快的算法将在m==85
处变为sort
。因此,我想知道是否有任何方法可以确定何时我们应该切换回排序,以在所有情况下都获得最佳性能。您不需要对整个数组进行排序,只需按数字顺序插入前10个数组并删除任何其他条目:
vara=Array.from({length:100},()=>Math.floor(Math.random()*1000000));
var check=a.slice().sort((左,右)=>right-left).slice(0,10);
控制台日志(“检查”,检查);
函数检查结果(top10){
var n;
对于(n=0;n<10;++n){
如果(top10[n]!==检查[n]){
log(“在#“+n+”测试中出错,应为“+check[n]+”,应为“+top10[n]);
返回false;
}
}
返回true;
}
var-top10=[];
var截止=-无穷大;
var full=假;
变量n,len,值;
对于(n=0,len=a.length;n=截止){
//插入前10名
让发现=错误;
对于(设n=0;n
。作为控制台包装器{
最大高度:100%!重要;
}
函数限制排序(数组、排序比、限制){
常量结果=[];
//在数组*上迭代一次*
for(阵列常数){
//排除最终不在结果数组中的所有元素
if(result.length结果[0]){
//确定需要插入元素的位置(插入排序)
设insertAt=0;
while(insertAt限制)
结果:拼接(0,1);
}
}
返回结果;
}
这实现了上面提出的算法。取数组的第一个限制元素,并“假设”它们是前10个。对其排序(微小)列表。遍历大数组中的其余元素。如果它大于您提取的最小元素,则删除该最小元素并将新元素插入其有序位置。继续,直到扫描整个数组。这基本上应该是O(nm)
使用n
作为输入的大小,m
作为输出的大小。迭代,对照下一个值检查每个值,将最大值存储在limit
size max数组中,并替换数组中的最小值,直到考虑到两种有效算法:K-select和使用K-size优先级队列排序不是最好的解决方案。你怎么知道?排序和切片前10名是最有效的算法,除非你使用选择算法(中间值的中值——按线性时间运行)这是一件复杂的事情,大多数时候麻烦比它的价值还多。@Redu你是在开玩笑吧?使用Quickselect比它的价值更麻烦?我的经验大不相同。文章并没有说它比它的价值更麻烦。在一个小数组中,是的。但是如果你有一百万个项目,排序将花费很多时间比使用Quickselect或简单的堆选择算法更长。28毫秒和358毫秒之间的差异绝对值得付出努力。如果(top10.length>10){top10.length=10;}这是做什么的?@AvcS它将数组修剪为10个元素。我认为,尽一切努力保持top10
数组排序、拼接以及所有这些,这一定有点效率低下。你可以将先排序大数组然后将前10个元素与此进行切片的性能进行比较。@Redu:我非常非常怀疑拼接到top1的效果0 将会接近排序200000元素数组的成本。但是,是的,无论如何,测量它。-)你的代码并不是非常低效,甚至与FF(神秘的例子)排序和切片一样。但是,由于您对一个包含m
项的阵列进行了n
多次检查,并且在该阵列上进行了条件拼接,因此效率确实不高
function limitSort(array, sortBy, limit) {
const result = [];
// Iterate over the array *once*
for(const el of array) {
// Exclude all elements that are definetly not in the resulting array
if(result.length < limit || el[sortBy] > result[0]) {
// Determine the position were the element needs to be inserted (Insertion sort)
let insertAt = 0;
while(insertAt < result.length && result[insertAt][sortBy] < el[sortBy]) insertAt++;
// Finally insert it
result.splice(insertAt, 0, el);
// If the results are getting to long, remove the lowest element
if(result.length > limit)
result.splice(0, 1);
}
}
return result;
}