繁体   English   中英

为什么这种排序算法会在浏览器中产生不一致的结果?

[英]Why is this sorting algorithm producing inconsistent results across browsers?

我正试图在Javascript中实现一个(非常简单的)绝对偏差排序算法。 绝对偏差定义为一个元素与所有元素平均值之差的绝对值。 例如,给定元素1,4,5和9,平均值为(1 + 4 + 5 + 9)/ 4 = 4.75,因此每个元素的绝对偏差计算如下:

  • absDev(1)= | 1 - 4.75 | = 3.75
  • absDev(4)= | 4 - 4.75 | = 0.75
  • absDev(5)= | 5 - 4.75 | = 0.25
  • absDev(9)= | 9 - 4.75 | = 4.25

因此,通过递增绝对偏差对元素进行排序将给出序列5,4,1,9。到目前为止,我目前的Javascript实现在不同的浏览器中给出了不同的结果。

这是: http//jsfiddle.net/WVvuu/

  • 在Firefox和Safari中,我得到了预期的结果5,4,1,9
  • 在Chrome和Opera中,我得到4,5,1,9
  • 在IE 10中,我得到1,4,5,9

我想我的代码中可能存在一些非常简单的错误,但我似乎无法找到它。 我想了解它的错误以及为什么我在更改浏览器时会得到不同的结果。 如果有人能够解释我所缺少的东西,我会很感激。 再次,这是代码:

var array = [1, 4, 5, 9];

function absDev(x) {
    return Math.abs(x - average(array));
}

function average(array) {
    var sum = array.reduce(function(previousValue, currentValue) {
        return previousValue + currentValue;
    }, 0);
    return sum / array.length;
}

array.sort(function(x, y) {
    return absDev(x) - absDev(y);
});

alert("Sorted array: " + array);

怀疑这是因为排序进行时数组的状态不一定一致。 你真的不应该重新计算每次比较的平均值:

array.sort(function(array) {
  var avg = array.reduce(function(previousValue, currentValue) {
    return previousValue + currentValue;
  }, 0);
  avg /= array.length;
  return function(x, y) {
    return Math.abs(x - avg) - Math.abs(y - avg);
  };
}(array));

看看它是否更好。 编辑 - 它在Chrome中为我提供了正确答案。)

更详细地说,我怀疑你看到奇怪结果的排序函数可能在阵列上执行交换,并且可能存在一个间隔,在此期间,一个或多个原始数组值丢失或复制,而排序机制是做它的事。 因此,您的平均函数会看到一个数组(有时)具有不同的值列表,这意味着平均值会有所不同(有时)。

排序函数重新计算排序的每个步骤的数组的平均值。 在排序过程中,不同的浏览器可能无法使阵列保持完整。 如果添加console.log(previousValue, currentValue);则可以看到此效果console.log(previousValue, currentValue); 进入array.reduce函数。

您需要先计算数组的平均值,然后将其存储到变量中。 然后将该变量传递给sort函数。 以下是我对您的代码所做的更改:

var array = [1, 4, 5, 9];
var mean = average(array);

function absDev(x, mean) {
    return Math.abs(x - mean);
}

function average(array) {
    var sum = array.reduce(function(previousValue, currentValue) {
        console.log(previousValue, currentValue);
        return previousValue + currentValue;
    }, 0);
    return sum / array.length;
}

array.sort(function(x, y) {
    return absDev(x, mean) - absDev(y, mean);
});

console.log("Sorted array: " + array);

排序正在进行时的数组状态被指定为实现定义,因此您无法在排序期间以特定方式信任项目在数组中。 您必须在开始排序过程之前预先计算平均值。

参考

http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.11

引用

对obj的[[Get]],[[Put]]和[[Delete]]内部方法执行依赖于实现的调用序列

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM