快速排序
思路
如何选定一个数组内元素,将数组划分为小于等于该元素和大于该元素的部分?
我们可以找随机一个中心点,做一次划分操作:小于中心点的元素放在中心点的左边,大于中心点的元素放在中心点的右边。
这样划分完成后,中心点就放在了有序的位置,数组也变得相对有序。
我们可以不停的划分数组,一直把数组划分为单个元素为止,单个元素本身就是有序的,即所有的元素就都被排好了序。
这种思想在算法中通常叫做分治,一般用递归来实现。
例子
把数组从小到大排序。
首先我们把数组最后一个元素作为中心点。
接下来,我们在不改变内存的情况下,通过元素间的交换完成划分的操作,可以通过双指针的方式完成,第一个指针左边的元素小于等于中心点,第二个指针右边元素全部大于等于中心点。。
第一个指针从左边第一个元素开始,第二个指针从中心点开始。
当第一个指针指向的元素大于中心点时,将该元素与右指针的前一个元素交换,此时第一个指针位置不变,右指针向前一步。
当第一个指针指向的元素小于等于中心点时,将左指针向前一步。
循环比较第一个指针指向的元素与中心点,直到两指针相遇。
通过把划分的操作一直递归操作下去,至子数组为一个元素为止,递归完成后即排序完成。
快速排序过程如下图所示:
js实现
function swap(data, i, j) {
let temp = data[i];
data[i] = data[j];
data[j] = temp;
}
function sort(data, start = 0, end = data.length - 1) {
if (end - start < 1) return;
const mid = partition(data, start, end);
sort(data, 0, mid - 1);
sort(data, mid + 1, end);
}
function partition(data, start, end) {
const pivot = data[end];
let i = start, j = end;
while(i !== j) {
if(data[i] > pivot) {
swap(data, i, --j);
} else {
i++;
}
}
swap(data, j, end);
return j;
}
Tips
coding的难点在于数组的划分,通过双指针把数组划为三个部分:小于中心点部分,不符合规则部分,大于中心点部分。通过指针的移动,直到消除所有不符合规则的部分。
完成了划分,即可通过分治,控制好终止条件,一直向下划分即可。