Fork me on GitHub

数组的sort方法

数组的排序是面试以及实际应用中都会经常用到的知识点。除了被我们熟知的冒泡排序,快速排序等排序算法之外,js中也封装了相应的API以供调用。

arr.sort()对数组中的元素进行排序,直接操作原数组,默认为升序排列。

下面会对sort()的具体用法,在不同场景下的区别,具体的实现原理进行介绍。以及如何根据已知的方法对数组进行无序排列。

当数组中的元素为字符时:

1
2
3
var arr = ['b', 'e', 'd', 'a'];
arr.sort();
console.log(arr); //["a", "b", "d", "e"]

当数组中的元素为数字时:

1
2
3
var arr = [5, 8, 2, 6, 1];
arr.sort();
console.log(arr); //[1, 2, 5, 6, 8]

当直接调用arr.sort()方法时,默认为按照ASCII码对数组中的元素进行排列

所以下面的情况可能会与我们想要得到的结果有差异:

1
2
3
var arr = [10, 5, 8, 2, 61, 1];
arr.sort();
console.log(arr); //[1, 10, 2, 5, 61, 8]

此时比较时,会取出数组中每个元素的第一位依次比较。第一位不同时,按ASCII排列。第一位相同,再比较第二位。

所以从以上例子我们可以得到如下结论:

直接调用arr.sort()方法进行比较时,比较的是ASCII值,与数字位数无关

那么如果我们想不论数字位数,直接根据数字大小进行排序;或者是对数组进行降序排列应该怎么处理呢?

arr.sort()中可以传入一个回调函数用来对数组中的元素进行处理。原理如下:

当function返回值为负数时,两个相比较的数,前面的数在前(两个数不交换顺序);
当function返回值为正数时,两个相比较的数,后面的数在前(两个数要交换顺序)。

按照上面的原理,我们进一步探索sort方法:

1
2
3
4
5
6
7
8
9
10
var arr = [10, 5, 8, 2, 61, 1];

arr.sort(function (a, b) {
if(a > b) {
return 1;
}else {
return -1;
}
})
console.log(arr); // [1, 2, 5, 8, 10, 61]

当a > b时,返回正数,两个数交换顺序,将小的数(b)放在前面。

你可能会奇怪上面并没有提到当两个数相等时该如何处理?

返回去看上面的代码,当a == b时,if条件不成立,进入else,返回负数,两个数不交换顺序。

当a > b时,a - b > 0;所以上面的代码还可以进行以下修改:

1
2
3
4
5
6
7
8
9
10
var arr = [10, 5, 8, 2, 61, 1];

arr.sort(function (a, b) {
if (a - b > 0) {
return a - b; //此时a - b为正数
}else {
return a - b; //此时a - b为负数
}
})
console.log(arr); //[1, 2, 5, 8, 10, 61]

实现的原理为:
第一个数依次和后面的数比较,找到最小的数放在第一个;

第二个数依次和后面的数比较,找到第二小的放在第二个;

依次类推,直到元素有规律排列为止。

按照上面的原理,会发现他其实和选择排序的原理是一样的。

选择排序的原理:
数组里面的第一个数依次和后面的数作比较,如果后面的数小于第一个数,交换顺序(找出最小的放在第一位);

再选出第二个数依次和后面的数作比较,选出余下数组里面最小的放在第二位;

重复以上规律,直到数组有序为止。

具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var arr = [10, 5, 8, 2, 61, 1];
function selectSort (arr) {
var temple;
for (var i = 0; i < arr.length - 1; i++) { //取出数组每一位
for (var j = i + 1; j < arr.length; j++) { //循环次数
if (arr[i] > arr[j]) {
temple = arr[i];
arr[i] = arr[j];
arr[j] = temple;
}
}
}
return arr;
}

console.log(selectSort(arr)); //[1, 2, 5, 8, 10, 61]

综上所述,最终可以把arr.sort()总结为:
(1)默认对字符进行排序,直接调用arr.sort();

(2)升序排列(从小到大)

1
2
3
arr.sort(function (a, b) {
return a - b;
})

(3)降序排列(从大到小)

1
2
3
arr.sort(function (a, b) {
return b - a;
})

应用:将数组乱序排列,每次乱序的结果不一致。具体实现如下:

1
2
3
4
5
6
7
var arr = [10, 5, 8, 2, 61, 1];
setInterval(function () {
arr.sort(function (a, b) {
return Math.random() - 0.3;
})
console.log(arr);
}, 500)

运算结果如下:
数组乱序排列结果

Math.random()产生随机数,随机数的范围为[0, 1);当Math.random() - 0.5,随机数的范围为[-0.5, 0.5)。

调用arr.sort(),当返回正数时,a, b交换顺序;返回负数时,a, b顺序不变。