快速排序
快速排序核心思想:分而治之
对于一组数据,我们随机取出一个枢纽值,将小于该值的放到左边,大于该值的放到右边。然后递归执行,最后即可完成排序。
在快速排序中,枢纽值是一个非常重要的值,这里我们采用取头,中,尾三个值得中位数作为枢纽值。
步骤:
- 对头,中,尾三个值进行排序,找到中位数作为枢纽值
- 将枢纽值放到right-1位置
- 定义 i=left, j=right-1,然后移动指针i和j,找到i对应值大于枢纽值的值,j对应值小于枢纽值的值,然后将两个值进行交换,循环进行。
- 当i大于j时,结束循环,将i的值与枢纽值进行交换,此时左边的值都小于枢纽值,右边的都大于枢纽值。
- 递归枢纽值左边的数值,递归枢纽值右边的数值,最后完成排序
代码实现;
//交换函数
function swap(i, j, arr) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//去除left,center,right三个下标对应值得中位数,作为枢纽值
function getPovit(left, right, arr) {
//这里需要向下取整,例如:left=4 right=5 ,如果向上取整,
//center=5,最后的center和right-1交换,会覆盖掉left值,会出错
let center = Math.floor((left + right) / 2);
//从小到大排序
if (arr[left] > arr[center]) {
swap(left, center, arr);
}
if (arr[center] > arr[right]) {
swap(center, right, arr);
}
//由于上面两步完成了最后right值肯定是最大的,那么最后我们还需要判断,left和center值的大小
if (arr[left] > arr[center]) {
swap(left, center, arr);
}
//将center这个枢纽值放到right-1位置
//原因:由于right肯定大于,放入right-1,只需对right-1之前的值进行判断和交换即可,避免枢纽值被移动
swap(center, right - 1, arr);
return arr[right - 1];
}
function quickSort(arr) {
function recSort(left, right) {
//递归结束条件
if (left >= right) return;
//基数
let povit = getPovit(left, right, arr);
let i = left;
let j = right - 1;
//将大于枢纽值得放入枢纽值右边,小于的放入枢纽值左边
while (i < j) {
//由于初始值i==left,left肯定小于枢纽值,因次要++i,而不是i++
while (arr[++i] < povit) {}
//由于初始值j==right-1,right-1等于枢纽值,因次要--j,而不是j--
while (arr[--j] > povit) {}
//交换找到的两个值
if (i < j) {
swap(i, j, arr);
}
}
swap(i, right - 1, arr);
//对左侧进行递归
recSort(left, i - 1);
//对有测进行递归
recSort(i + 1, right);
}
//开始递归
recSort(0, arr.length - 1);
return arr;
}