快速排序
快速排序的核心思想是分治法。快速排序不是一个稳定排序(如果有相同元素排序后元素的位置不变),但它是原地排序(不需要额外的空间),平均时间复杂度O(nlogn),最坏时间复杂度是O(n2),空间复杂度O(1)。
代码实现
快速排序核心是选择基准元素,然后将小于基准元素的元素放在基准元素左边,而大于基准元素的元素放在基准元素的右边
指针交换法
指针交换法是通过一个left指针和right指针,来寻找基准元素的方法。
// 指针交换法
function quickSort(array, startIndex, endIndex) {
if (startIndex >= endIndex) return;
const piovtIndex = partition(array, startIndex, endIndex);
quickSort(array, startIndex, piovtIndex - 1);
quickSort(array, piovtIndex + 1, endIndex);
}
function partition(array, startIndex, endIndex) {
// 基准点
let piovt = array[startIndex];
let left = startIndex;
let right = endIndex;
// 指针没有重合时
while (left !== right) {
// 先从右向左比较 ,比基准元素大则right指针向左移动一位,否则切换到left指针
while (left < right && array[right] > piovt) {
right--;
}
// 此时 right指针移动完毕 left指针比基准元素小则向右移动一位,否则交换left与right指针
while (left < right && array[left] <= piovt) {
left++;
}
// 交换left与right指针,因为left指针与right指针移动完毕,
// 他们停止移动的条件是right指针的元素比基准元素小而left指针的元素比基准元素大
// 我们最终实现的是基准元素的左边比基准元素小或者相等 而基准元素的右边比基准元素大
if (left < right) {
const temp = array[right];
array[right] = array[left];
array[left] = temp;
}
}
// 指针重合时 需要将基准点与left指针元素交换 因为要实现准元素的左边比基准元素小或者相等 而基准元素的右边比基准元素大
const temp = array[left];
array[left] = array[startIndex];
array[startIndex] = temp;
return left;
}
const array = [3, 4, 2, 1, 5, 6, 7, 8, 30, 50, 1, 33, 24, 5, -4, 7, 0];
quickSort(array, 0, array.length - 1);
console.log(array);
挖坑法
指针交换法是通过一个left指针、right指针和一个index坑位,来寻找基准元素的方法。
// 挖坑法
function quickSort(array, startIndex, endIndex) {
if (startIndex >= endIndex) return;
const piovtIndex = partition(array, startIndex, endIndex);
quickSort(array, startIndex, piovtIndex - 1);
quickSort(array, piovtIndex + 1, endIndex);
}
function partition(array, startIndex, endIndex) {
// 基准点
let piovt = array[startIndex];
let left = startIndex;
let right = endIndex;
// 坑的位置 初始等于pivot的位置
let index = startIndex;
//大循环在左右指针重合或者交错时结束
while (right >= left) {
// 先从右向左遍历比较
while (right >= left) {
// 如果当前元素比基准元素大,则right指针向左移动一位
// 否则将right指向的元素填入坑中,同时left指针向右移动一位
// 然后跳出此处循环,下次循环从左向右遍历
if (array[right] < piovt) {
// 将right指针的元素填入坑中
array[left] = array[right];
// 更新坑的位置
index = right;
// left指针需要向右移动一位,因为当前元素在本轮已有序
left++;
break;
}
right--;
}
// 从左向右遍历比较
while (right >= left) {
// 如果当前元素比基准元素小,则left指针向右移动一位
// 否则将left指向的元素填入坑中,同时right指针向左移动一位
// 然后跳出此处循环,下次循环从右向左遍历
if (array[left] > piovt) {
// 将left指针的元素填入坑中
array[right] = array[left];
// 更新坑的位置
index = left;
// right指针需要向右移动一位,因为当前元素在本轮已有序
right--;
break;
}
left++;
}
}
// 最后把基准元素的值放到index位置
// 此时 index左侧的元素都比index指向的元素小,右侧的元素都比index指向的元素大
// 本轮交换结束
array[index] = piovt;
return index;
}
const array = [3, 4, 2, 1, 5, 6, 7, 8, 30, 50, 1, 33, 24, 5, -4, 7, 0];
quickSort(array, 0, array.length - 1);
console.log(array);