面试题: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()方法;
 
})

上面的代码我从别人的博客上复制过来的,里面很多结论有错误:

  1. a代表当前项 ,b代表后一项,我们进行一个验证,看下面的代码块
arr.sort(function() {
    console.log(arguments) //打印arguments对象
})

打印输出的arguments结果如下:

jquery array 排序 js array.sort排序原理_数组

得出结论
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];
})
  1. 上面讲的原理也不对,因为如果我们直接return 一个数,当这个数为正数或者0时,可以看到数组没有任何变化。 反而是为负数时才会有调用reverse()方法,达到反转数组的效果。
var arr = [2, 34, 242, 12, 3, 2, 23, 3]; // 定义一个数组
var data = []
arr.sort(function() {   
    return -5; //返回>=0那么就不会交换,如果返回<0则会交换变量值
})

输出结果是:

jquery array 排序 js array.sort排序原理_升序_02


由此可见,原理应该是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])

  1. a-b实则是后面的元素减去前面的元素 :
    如果值大于等于0 ,则不交换,说明是升序 如果a-b的值于0说明后面的比前面小 那就需要交换
  2. b-a实则是前面的元素减去后面的元素 如果前面的元素小于后面的元素, 那么说明不是降序,return 负数,需要交换值