Array.prototype.sort():从一道面试题说起

前几天看一道面试题,要求根据num对下面的对象倒序排序。

var arr = [
    {name:'A',num:4},
    {name:'G',num:3},
    {name:'V',num:5},
    {name:'A',num:2},
    {name:'X',num:9},
    {name:'R',num:6},
    {name:'N',num:undefined},
];

对于对象按照属性排序 MDN-Array.sort() 上有介绍。下面是MDN上的栗子。

var items = [
  { name: 'Edward', value: 21 },
  { name: 'Sharpe', value: 37 },
  { name: 'And', value: 45 },
  { name: 'The', value: -12 },
  { name: 'Magnetic' },
  { name: 'Zeros', value: 37 }
];

items.sort(function (a, b) {
  if (a.value > b.value) {
    return 1;
  }
  if (a.value < b.value) {
    return -1;
  }
  // a 必须等于 b
  return 0;
});

 

于是我们可以简单地写出答案:

arr.sort(function(){
    return b.num - a.num;
});

我对数组中含有undefined时的排序情况有不小的疑惑。

当num的值全部是正常数字时, arr将会被正常倒序排序,那么在有特殊值的情况下将如何排序呢。这里分别测试了两种情况。

  • num的值为undefined

    

    在完成正常数值的倒序排序后,num值为undefined的对象被放到了最后。后来改成正序测试undefined仍然被放到了最后。

  • num的值未定义(在这里我将题中的num:undefined直接删去)

    

    不管正序还是倒序,num值未定义的对象依然被扔在最后。

 为了查看其排序原理,我们用一个简单的数组模拟一下来看看每一次排序后数组的变化。(正序)

var arr = [4, 3, 5, 2, undefined, 9 ,6 ];
function compare(a, b) {
    console.log(a, b, arr);
    return a - b;
}
arr.sort(compare);

 控制台结果:

 

undefined在第一次排序前就被扔到了后面,但对比一下原数组: [4, 3, 5, 2, undefined, 9 ,6 ]  >> [4, 3, 5, 2, 6, 9, undefined]

发现undefined与数组的最后一位做了交换。实际上我们的compare()函数压根没有将undefined列入考虑范围,而是遇到直接扔到数组最后再进行排序。num值未定义的时候也同理。

了解了undefined的情况,我们来看一下正常情况下的排序机制。

  第一次:  4大于3,两者交换位置 [3, 4, 5, 2, 6 ,9],看起来像是运用了冒泡排序。

  第二次:  4小于5,没有位置交换 [3, 4, 5, 2, 6 ,9]

  第三次:  5大于2,在这里仅仅是5覆盖了2的位置得到 [3, 4, 5, 5, 6, 9]

  第四次:  4大于2,4又覆盖了5的位置得到 [3, 4, 4, 5, 6, 9]

  第五次:  3大于2,这时2出现得到 [2, 3, 4, 5, 6, 9]

  第六次:  5小于6,位置不变,第七次同。

  最终得到正序排序结果。

上述的排序过程中只有第一次做了一次交换,再看第三四五次都与2做了比较并且有移位的过程。这与插入排序的过程类似。但是第一次不能确定是用了冒泡还是插入排序。

实际上第一次也同样使用了插入排序。假设确实是冒泡,那么第一次排序会将两两相邻的数一直比较至数列尽头(第二次倒着往前比较)。不能把一次交换就简单认为是冒泡排序。

使用冒泡的第一次排序后顺序应该是 [3, 4, 2, 5, 6, 9].

换一组数再来测验一下  var arr = [4, 3, 1, 2, -1];

可以得出结论sort()函数主要运用了简单插入排序算法。下面是我偷来的图解释了插入排序的动态过程。

 注:上面的测试全部在chrome环境下实现,不同的浏览器使用的排序机制可能不同。

原文地址:https://www.cnblogs.com/qimeng/p/6916576.html