快速排序

快速排序

快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。

快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。

快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。

算法步骤

  1. 从数列中挑出一个元素,称为 “基准”(pivot);

  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

动图演示

image

JavaScript代码实现

我们首先来看看基准(pivot)的原理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function quickSort(arr) {
var pivot = arr[0], //选择数组的第一项作为基准
left = [], //所有比基准小的放到基准的左边
right = []; //所有比基准大的放到基准的右边
for (var i = 1; i < arr.length; i++) { //从数组的第二项开始遍历
if (arr[i] < pivot) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
return left.concat(pivot, right); //返回一个按照left、pivot、right的顺序数组
}
var shuzu = [54, 21, 212, 1, 789, 52, 12, 50];
var arr = quickSort(shuzu);
console.log(arr);// [21, 1, 52, 12, 50, 54, 212, 789, 54]

第一次排序之后,基准“54”左边的都比它小,右边的都比它大。

然后一直递归下去(注意自己调用自己的时候一定要有终点):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function quickSort(arr) {

if (arr.length<=1) { //结束的条件
return arr
}

var pivot = arr[0], //选择数组的第一项作为基准
left = [], //所有比基准小的放到基准的左边
right = []; //所有比基准大的放到基准的右边
for (var i = 1; i < arr.length; i++) { //从数组的第二项开始遍历
if (arr[i] < pivot) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
return quickSort(left).concat(pivot, quickSort(right)); //返回一个按照left、pivot、right的顺序数组
}

var shuzu = [54, 21, 212, 1, 789, 52, 12, 50];
var arr = quickSort(shuzu);
console.log(arr); //[1, 12, 21, 50, 52, 54, 212, 789]
------ 本文结束 ------
0%