1 回答
TA贡献1871条经验 获得超13个赞
var mid = lo + (lo + hi) / 2有多个问题。如果您试图防止溢出,lo + hi则有问题(正确的公式是lo + (hi - lo) / 2)。加lo回来算两次。/ 2可能会给出一个浮点结果,这将破坏递归逻辑并作为索引失败。
在设计方面,我认为没有理由让合并排序成为一个有状态的类并创建一个实例来对数组进行排序。这是不必要的开销,使调用代码冗长,并可能引入错误。假设您需要一个类(即使这可能是矫枉过正),使这些方法static更有意义。
this.aux在多个方法调用和调用之间持续存在错误已经成熟,感觉就像过早的优化;将其完全设置为sort方法的本地可以提高可读性、封装性并确保在调用之间没有陈旧的数据存在。是的,为每一帧创建一个数组merge很昂贵,但是如果需要优化,可以将合并数组添加到闭包中或作为参数传递。或者合并可以就地完成。再说一次,Array#sort如果性能是您的目标,这是更好的选择。
我还发现,使用传统的数组长度协议运行所有拆分,其中lo包含mid和lo不包含以及包含和不mid包含的第二个块更直观。这避免了我觉得更难推理的和循环。midhimid + 1hi - 1<=
class MergeSorter {
static merge(a, lo, mid, hi) {
const sorted = [];
let i = lo;
let j = mid;
while (i < mid && j < hi) {
if (a[i] < a[j]) {
sorted.push(a[i++]);
}
else {
sorted.push(a[j++]);
}
}
while (i < mid) sorted.push(a[i++]);
for (let i = 0; i < sorted.length; i++) {
a[lo++] = sorted[i];
}
}
static sort(a, lo=0, hi=a.length) {
if (lo < hi - 1) {
const mid = Math.floor((lo + hi) / 2);
MergeSorter.sort(a, lo, mid);
MergeSorter.sort(a, mid, hi);
MergeSorter.merge(a, lo, mid, hi);
}
}
}
const a = [..."MERGESORTEXAMPLE"];
MergeSorter.sort(a);
console.log(a.join(""));
const rnd = n => ~~(Math.random() * n);
let passes = 0;
const tests = 10000;
for (let i = 0; i < tests; i++) {
const a = Array(rnd(25)).fill().map(() => rnd(25));
const b = a.slice();
MergeSorter.sort(a);
b.sort((a, b) => a - b);
if ("" + a === "" + b) {
passes++;
}
}
console.log(`${passes}/${tests} tests passed`);
添加回答
举报