昨天学习了快速排序,平均时间复杂度 O(n log2n),
本文排序默认按升序处理。
快速排序
思路
目前快排大致分两种思路,一种是挖坑填补法,另一种是交换元素法。 我学习的是第二种 交换元素法,第一种等日后再复习快排时学习补充在这里吧(挖坑....) 交换元素法的基本思路是:
- 选定枢纽:某个数组中 某个元素,开头或结尾或中间元素均可。
- 找位置:我们要找到枢纽元素在即将有序的数组中的位置。方法如下:
假设我们选定最后一个元素
len - 1(len为数组长度)作为枢纽元素, 那么我们把除了枢纽元素剩下的元素分组,比枢纽元素小的一组,比枢纽元素大 的一组, 具体方法:(比较绕可以直接读代码)使用双指针将指向的元素与枢纽元素,依次比较并交换,左侧第一个比枢纽元素大的和右侧第一个比枢纽元素小的元素。 - 对枢纽两侧数组重复1 、2步骤。
快排的算法的核心是找位置这个步骤,找到枢纽元素本所在的位置,同时将两侧以枢纽元素为基准按大小分组
参考代码
arr = [5, 3, 6, 1, 8, 4, 7, 2, 0, 9];
// 快速排序(交换版本)
function quickSort(array, begin, end) {
if (array.length === 1) {//大小为1就返回
return;
}
// 排序部分
if (begin < end) {
let mid = separate(array, begin, end);
// 以下几行为展示快排数组区间代码
console.log(`区间${begin}-${end} 枢纽所在的位置${mid}`);
let showArr = array.map((index, value) => {
if (value >= begin && value <= end) {
return `${index}`;
} else {
return index;
}
});
console.log(showArr);
//————————————————————————————
quickSort(array, begin, mid - 1);
quickSort(array, mid + 1, end);
}
}
function separate(array, left, right) {
let pivot = array[right];//取最后的作枢纽
let i = left;
let j = right - 1;
while (true) {
while (i < right && array[i] < pivot) {
i++;
}
while (j > 0 && array[j] > pivot) {
j--;
}
if (i < j) {//上面的i j 分别从左右两个方向,向中间遍历到了i(比枢纽大的数) j(比枢纽小的数)
[array[i], array[j]] = [array[j], array[i]];
} else {//如果两个指针已经相遇了,就交换i和枢纽的位置。
[array[right], array[i]] = [array[i], array[right]];
break;
}
}
return i;
}
quickSort(arr, 0, arr.length - 1);
注意事项
- 分两个函数,一个是递归的快排自身,另一个是分区返回枢纽下标给mid的分离函数。
- 快排递归时,分左[begin, mid - 1] 右[mid + 1, end] 两个区间分别递归。
- 分区时,要在枢纽元素之外的数进行查找比较,查找时和交换时,都要确认两个指针的位置。
平均时间复杂度:O(nlog2n) 一般是左右两个区间二分。