简单理解
首先我觉得我们要明确一般算法都是需要递归的,所以我们首先完成第一循环
第一个循环我们找到一个主元(数组的中间),我们把大于的放右边,小于的放左边
然后在分别把主元左边的和右边的在重复上面的过程就可以达到排序了
具体步骤
1.首先,从数组中选择中间一项作为主元
2.创建两发指针,一个指第一项(左边),一个指最后一项(右边)
3.我们要在左边找大的值,右边找小的值,让他们相互交换,交换完后左边++,右边--,当达到左边的指针和右边的指针相同位置或者左边的指针大于右边指针的位置的时候声明第一次循环结束了,在主元左边都是比主元小的值,右边都是大的值
4.在将主元左右两边分为2个数组在进行上面的操作,(递归)
5.设置好递归出口,就是某一个主元他的左边或者右边只有一个值或者没有值了的时候退出
代码解析
准备
/*
* 普通的交换,将a[i]和a[j]的数值交换;
*/
function swap(arr, i, j) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
首页我们要递归完成,那么我们就要写出第一次循环的函数,然后在递归找出口
函数定义
/**
* 快排执行函数
* @param {Array} [array] 需要快拍的数组
* @param {string} [left] 左边指针开始的位置
* @param {string} [right] 右边指针开始的位置
*/
var partition = function (array, left, right) {
var pivot = array[Math.floor(left + right) / 2] // 主元
i = left; // 左边指针开始指向位置
j = right; // 右变指针指向位置
}
函数第一次执行的代码
/**
* 快排执行函数
* @param {Array} [array] 需要快拍的数组
* @param {string} [left] 左边指针开始的位置
* @param {string} [right] 右边指针开始的位置
*/
var partition = function (array, left, right) {
// 中间数
var pivot = array[Math.floor(left + right) / 2]
i = left; // 左边指针开始指向位置
j = right; // 右变指针指向位置
while (i <= j) {
// 找大的
while (array[i] < pivot) {
i++
}
// 要找一个小的
while (array[j] > pivot) {
j--
}
// 对换
if (i <= j) {
swap(array, i, j)
i++
j--
}
}
return i // 为什么返回一个指针的位置,后面回说
}
把左指针开始向主元的方向++找到大于等于主元的值(找到后不动),开始右指针向主元方向--找到小于主元的值,当他们都找到的情况下,如果这个时候左指针和右指针没有在同一个位置或者他们已经交替的情况(就是左指针的位置大于右指针),那么就将左边找到大于的值,和右边找到小的值替换,然后左指针++,右指针--,直到左指针和右指针没有在同一个位置或者他们已经交替的情况(就是左指针的位置大于右指针)的时候,那么就可以是主元左边全是大于的值,右边全是小的值
左指针和右指针没有在同一个位置或者他们已经交替的情况(就是左指针的位置大于右指针):这个是什么意思?当左边和右边都开始找,当左边大于或等于指针右边指针了说明已经左边都是小的了,右边都是大的了,这个时候就可以停止了,
什么时候的等于,就是一开始主元左边都是小的,右边都是大的值,当左边指针和右边指针同时到主元这个值的时候,左指针指向的值不小于主元(所以到主元这个时候暂停了),右指针不大于主元(到主元这个值也刚好停了)
什么时候的左大于右:其他任意情况,当某一次换完了位置之后,我们在继续指针在同时去找下一个值来对换的时候回进行左++,右--,然后发现,回判断左边是否大于右边了,如果是那么就第一次循环结束
开始递归
var quick = function (array, left, right) {
var index; // 接收回调函数返回的最终左边指针返回的位置
if (array.length > 1) {
index = partition(array, left, right);
if (left < index - 1) {
quick(array, left, index - 1);
}
if (index < right) {
quick(array, index, right)
}
}
}
一旦开始递归处理的时候我们就要注意了,我们要先找递归的出口,然后在开始递归
思考:既然我要递归,那么我们是要递归那个部分的,对了就是主元左边的和右边的,(虽然左边的都是大的值,但是是没顺序的)
好既然我们要左边的数组,和右边的数组,那么我们就需要某一个指针最后的位置来判断右边数组,和左边数组
我们这里用左边指针的位置,所以上面我们返回的是i的值
出口:就是数组的长度要么是0要么是1,那么我们就不需要了
那么什么情况下是0或者1呢?
左边:left < (左边指针的位置 -1),为什么这里要减一,当第一次结束的时候左边指针指向的值一点大于右边指针指向的值,所以减一,那么前面的值都是小值
右边:(左边指针的值)> right
因为只有是大于或者小于了就说明至少数组是有2个值,那么就可以继续递归,
最终
从里到外递归完后,那么一个一个位置就回被按从小到大调整过来