我的长度超过200,000。我需要获得前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;
array.forEach((record, i) => {
if (record[sortBy] >= currentMax) {
currentMax = record[sortBy];
currentMaxIndex = i;
}
});
results.push(...array.splice(currentMaxIndex, 1));
}
此处数组是长度为200,000的Array
。
问题是,我认为如果
m
等于N
,那么这就是 比sort
本身需要更多的时间。我想知道是否有 是一个更好的解决方案,可以处理这两种情况。
感谢您的帮助,但实际问题是m ∈ (0, N)
。 m
可以使用N
之前的任何值。那么,在哪一点上建议切换到内置的sort
?
根据我的理解,当m
到达N
时,复杂度会增加,排序是m === N
我已经使用@ t-j-crowder here提供的示例进行了测试。从100个条目中获得前10名的测试。
在m
中使用不同的值进行测试时,更快的算法会在sort
更改为m === 85
。所以,我想知道是否有办法确定何时应该切换回排序,以便在所有情况下都能获得最佳性能。
答案 0 :(得分:2)
您不需要对整个数组进行排序,只需按数字顺序插入前10个数组并删除任何其他条目:
var a = Array.from({length:100}, () => Math.floor(Math.random() * 1000000));
var check = a.slice().sort((left, right) => right - left).slice(0, 10);
console.log("check", check);
function checkResult(top10) {
var n;
for (n = 0; n < 10; ++n) {
if (top10[n] !== check[n]) {
console.log("Error in test at #" + n + ", expected " + check[n] + ", got " + top10[n]);
return false;
}
}
return true;
}
var top10 = [];
var cutoff = -Infinity;
var full = false;
var n, len, value;
for (n = 0, len = a.length; n < len; ++n) {
value = a[n];
// If the value may be in the top 10...
if (!full || value >= cutoff) {
// Insert into top10
let found = false;
for (let n = 0; n < top10.length; ++n) {
if (top10[n] <= value) {
top10.splice(n, 0, value);
found = true;
break;
}
}
if (!found) {
top10.push(value);
}
// Trim it
if (top10.length > 10) {
full = true;
top10.length = 10;
}
// Remember the lowest of the top 10 candidates we have now so we can not bother with checking lower ones
cutoff = top10[top10.length - 1];
}
}
console.log("top10", top10);
console.log("Good? " + checkResult(top10));
&#13;
.as-console-wrapper {
max-height: 100% !important;
}
&#13;
你可以稍微整理一下,进一步优化它,但你明白了。维护一份仅列出前10名的最高名单,如果其他人加入,则将其从最底层删除。
Benchmark here,轻松击败排名,然后抢占Chrome和Firefox的前10名;相反,在Edge上也是如此。
答案 1 :(得分:0)
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;
}
这实现了上面提出的算法Niet the Dark Absol。 Try it!