前言
快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为较小和较大的2个子序列,然后递归地排序两个子序列。
——维基百科
快速排序与归并排序相同,都是使用了分治法的思想,分而治之,只是两个算法的进行分的思想不同,并且,快速排序不存在归的操作,没有数组的合并,只是在原有数组基础上进行划分。在我们进行到最后一个步骤时(划分内只有一个元素时),其实就已经结束了。
算法分析
算法思想
官方的讲法,或许是有些抽象的。简单来说,快速排序,通过一个基准元素(用于和其他元素比较),将一段数组划为两个部分,左半部分的比该基准元素小,右半部分的比该基准元素大(至于等于?那就看设计者了,你可以将等于部分归到左半部分,或是归到右半部分,这并不重要,重要的是你考虑了等于的部分就行! )。典型的递归思想,显然,在完成一次排序后,基准元素已经回到它该回去的位置,而左半部分的和右半部分的再进行同样的操作,直到划分组内元素只剩一个(下面的left<right条件这样来)。
- 1.这里我们以第一个元素为基准元素,那么我们扫描开始时,左边只需要从第二个开始扫描。
- 2.i记录左边扫描到的数组下标,j记录右边扫描到的数组下标,以此双向扫描,直到左边扫描的元素比基准大时停下,右边扫描元素比基准小或等于(这个等于,前提是我们想让左边的元素小于等于基准元素,这个以具体算法为准)记录当前下标i,j,交换两个位置元素,** i++,j-- **,继续下一次扫描,直到我们扫描完。
- 3.如何算扫描完?这需要考虑好。当i==j或i>j时,显然,全部元素我们已经扫描一遍,本次划分已完成。
- 4.直到某次划分时,元素只剩一个/或者没有时,变不再划分,直接返回,这里需要明确的是,我们并没有开新的数组,而是在原来数组的基础上进行划分!。
代码分析
JavaScript代码
需要说明的是,上次归并排序用的结构有点小傻(说我自己,当时写的时候不知道在想啥。。。),本次JavaScript代码使用的是原型链编程,直接在原型上进行函数书写,至于好处?我提一下,this因指向问题可以直接改变数组数据,无需开辟数组接收再来返回。具体的原因,有空的话专门去写一篇说明。
准备代码
利用原型,直接将数组内指定两个元素交换。
/**
* JS原型编程 交换数组中的两个指定元素 i j为下标
*/
Array.prototype.swap = function (i, j) {
var t = this[i];
this[i] = this[j];
this[j] = t;
}
普通版
代码分析
/**
* QuickSort1函数
* 通过Partition1函数获取到当前已归为的数据的下标
* 将数组进行分割 分为归位的左半部分和归为的右半部分
*/
Array.prototype.QuickSort1 = function (left, right) {
// 传参 (首下标,尾下标) 这里是第一次传参
if (left < right) {
s = this.Partition1(left, right); // 当前已经排序好的一个元素的数组下标
this.QuickSort1(left, s - 1);
this