先简单说明一下sort()函数
1、当不给sort函数传递一个比较函数时,他会将数组按照字典顺序排序。
这种排序
var arr = [456,12345];
arr.sort();
// 排序后arr = [12345,456]
arr = ["z","a","adc","acdef"];
arr.sort();
// 排序后arr = ["a", "acdef", "adc", "z"]
arr = ["77","768"];
arr.sort();
// 排序后arr = ["768","77"]
这种排序用来排序非数字类型数组比较合理,但是用来排序数字显然不是我们想要的。
2、为了使用sort函数正确地给数字类型数组排序,sort函数提供了一个参数,让我们可以根据我们的实际需要(不只是升序、降序)对数组经行排序。
var arr=[16,123,654,1,53,22,512,55,3];
arr.sort();
// 排序后arr = [1, 123, 16, 22, 3, 512, 53, 55, 654]
arr.sort(function(a,b){
if (a < b ) {
return -1;
}
if (a > b ) {
return 1;
}
return 0;
});
// 一般简写为arr.sort(function(a,b){return a-b;});
// arr.sort(function(a,b){return b-a;}); 这样子是降序排序
// arr.sort(function(a,b){return -1}); 这样子是数组反转,不排序。
// 排序后arr = [1, 3, 16, 22, 53, 55, 123, 512, 654]
可以看到当我们传递一个比较函数进去的时候,sort对这个数字数组进行了正确的排序。
可以得出一些结论:
1、sort提供的这个参数接收一个函数,这个函数的主要作用是可以让你自定义数组的排序方式,称之为比较函数。
2、该比较函数又有两个参数。
3、我们需要对这两个参数进行比较后,返回一个值给sort函数,告诉sort函数a,b哪个是较大的数。
那么问题来了,这个比较函数的两个参数到底指的是这个数组中的那两个数,他的返回值-1,0,1又到底代表什么意思。
不要小看这两个问题,在做一些复杂排序的时候,不搞懂很难用sort函数按照你想要的顺序排序数组。
我们来看一下比较权威的MDN是怎么解释这个比较函数的。
MDN对sort函数的说明:
firstEl
第一个用于比较的元素。
secondEl
第二个用于比较的元素。
如果指明了 compareFunction ,那么数组会按照调用该函数的返回值排序。即 a 和 b 是两个将要被比较的元素:
如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。备 注: ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003 年之前的版本);
如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。
compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。
MDN对a,b的解释是第一个用于比较的元素、第二个用于比较的元素,emmmm,个人觉得描述不太准确。这里打印看一下就知道了。
var arr = [3,2];
arr.sort(function(a,b){console.log(a,b)}) //打印出2 3
欸,这跟描述的有点不太对吧,为什么打印出来a是2。接着测试
var arr = [4,2,3,1];
arr.sort(function(a,b){console.log(a,b)})
//打印出2 3,3 2,1,3
相信这里大家应该看出来,它内部使用的插入排序(不了解的可以先了解一下,大概是从数组第二个元素开始,插入到该元素之前的子数组中,使其有序,然后指向下一个元素,接着插入到前面的数组里,直到整个数组有序)。
所以该比较函数的第一个参数应该是从数组下标为1的元素,每次比较完都指向下一个元素。第二个参数指向第一个参数之前子数组的中间元素(因为该方法用的不是简单的直接插入排序,而是二分插入排序)
其实sort函数内部实现的排序不单单只是插入排序,只是当数据量不大的时候,显然插入排序更有效率,他也会根据数组的规模选择使用快速排序还是插入排序对数组进行排序。
简单说一下快速排序。选择数组的一个元素,通过某种算法找到他在这个数组中的确切位置,当查找结束的时候,刚好他左边的元素都小于这个元素,他右边的所有元素都大于这个元素。然后以该元素为间隔将数组分成两半,再查找他左边数组某个元素确切的位置,查找他左边数组某个元素确切的位置,直到整个数组有序。
sort() V8 源码,从710行开始
// In-place QuickSort algorithm.
// For short (length <= 22) arrays, insertion sort is used for efficiency.
这是源码里面的某段注释,大概意思是当数组长度小于等于22的时候,插入排序更有效率。可以看出,当数组规模较大时,sort()采用快速排序对数组经行排序,否则用插入排序。
从排序算法的应用场景来说这样安排也比较合理,没有一个排序算法是万能,适用所有数据场景的。对于数据规模较小、基本有序的数组插入排序更为高效。在普通、平均条件下,快速排序更为高效。