面试题:sort方法的实现原理
有一次面试中,面试官问到我sort方法实现排序的原理是什么,返回值怎样影响数组顺序的? 我很羞愧,没研究过,所以我好好想了一下,发现,目前看到的很多技术博客上的观点都是错误的!!!!
首先我们看大多数博客上复制粘贴的代码:
var arr = [2,34,242,12,3,2,23,3];// 定义一个数组
arr.sort(function (a,b) {
// a 代表每一次执行匿名函时候,找到的数组中的当前项;
// b 代表当前项的后一项;
// 升序时: 如果a>b,那么返回的值>0,a和b交换位置;
return a - b;
// 降序时: 如果b>a,那么返回的值>0,a和b交换位置;
return b - a;
原理:
return的值可能是一个大于0的数也或者可能是小于等于0的数,
如果return后的值大于0则让数组a和b交换一下位置;小于等于0,
则原来数组中的位置不变;
return 1; // 表示不管a和b谁大,每一次都返回一个恒大于0的数,
也就是说每一次a和b都要交换位置,最后的结果就是原有数组
倒过来排列了,相当于数组的reverse()方法;
})
上面的代码我从别人的博客上复制过来的,里面很多结论有错误:
- a代表当前项 ,b代表后一项,我们进行一个验证,看下面的代码块
arr.sort(function() {
console.log(arguments) //打印arguments对象
})
打印输出的arguments结果如下:
得出结论:
arguments[0] -->代表找到的数组中下标在后面的数;
arguments[1] -->代表数组中下标在前面的数;
为什么会这样!!! 我还没找到原因,欢迎小伙伴指点。
var arr = [2, 34, 242, 12, 6, 3, 2, 23, 3]; // 定义一个数组
var data = []
arr.sort(function() {
console.log(arguments)
data.push(arguments[1] - arguments[0]) //由于 返回负数才会交换值
return arguments[1] - arguments[0];
})
- 上面讲的原理也不对,因为如果我们直接return 一个数,当这个数为正数或者0时,可以看到数组没有任何变化。 反而是为负数时才会有调用reverse()方法,达到反转数组的效果。
var arr = [2, 34, 242, 12, 3, 2, 23, 3]; // 定义一个数组
var data = []
arr.sort(function() {
return -5; //返回>=0那么就不会交换,如果返回<0则会交换变量值
})
输出结果是:
由此可见,原理应该是return 负数时才会交换二者的值。那么问题来了,上面的升序a-b和降序 b-a是怎么做到的?
我定义了一个data数组用来保存每一次的差值
var arr = [2, 34, 242, 12, 3, 2, 23, 3]; // 定义一个数组
var data = []
arr.sort(function(a,b) {
data.push(b- a) //保存每一次比较的差值
return b-a; //降序
//升序
data.push(a-b)
return a-b
})
输出结果(降序):
data数组的值:
[
-32, -208, 230, 22, -10,
9, -1, 10, 0, -20,
11, -11, 9, -1, 0
]
降序排序之后的数组:
[
242, 34, 23, 12,
3, 3, 2, 2
]
输出结果(升序):
data数组的值:
[
32, 208, -230, -22, 10,
-31, -9, 1, -10, -1,
0, 11, -219, -11, -9,
1, 0
]
升序排序之后的数组:
[
2, 2, 3, 3,
12, 23, 34, 242
]
所以原理就是 当return 负数时,交换两个值,当return是正数或者0时不发生改变。
那为什么 a-b升序 ,b-a降序?(这里的a表示arguments[0],b表示arguments[1])
- a-b实则是后面的元素减去前面的元素 :
如果值大于等于0 ,则不交换,说明是升序 如果a-b的值于0说明后面的比前面小 那就需要交换 - b-a实则是前面的元素减去后面的元素 如果前面的元素小于后面的元素, 那么说明不是降序,return 负数,需要交换值