algorighm/sort/quick-sort.mjs

196 lines
5.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { swap } from '../util/index.mjs';
/**
*
* @param {number[]} array - 需要排序的数组
*/
export function quickSort(array) {
function QuickSort(arr, left, right) {
if (left < right) {
const index = partition(arr, left, right);
QuickSort(arr, left, index - 1); // index是中心轴无需参与排序,若写成index会造成堆栈益处
QuickSort(arr, index + 1, right);
}
}
QuickSort(array, 0, array.length - 1);
return array;
}
/**
* @description 使用左右指针法来分数组
* @param {number[]} arr - 需要分治的函数
* @param {number} left - 开始的位置
* @param {number} right - 结束的位置
*/
function partition(arr, left, right) {
const pivot = arr[right]; // 以right作为pivot
const pivotIndex = right;
while (left < right) {
// left开始往右边找比pivot大的值
while (left < right && arr[left] <= pivot) {
left++;
}
// right开始往左边找比pivot小的值
while (left < right && arr[right] >= pivot) {
right--;
}
swap(arr, left, right);
}
swap(arr, left, pivotIndex);
return left;
}
/**
*
* @param {number[]} array - 需要快速排序的数组
*/
export function quickSort2(array) {
function QuickSort(arr, left, right) {
if (left < right) {
const pivot = partition2(arr, left, right);
QuickSort(arr, left, pivot - 1);
QuickSort(arr, pivot + 1, right);
}
}
QuickSort(array, 0, array.length - 1);
}
/**
* @description 使用挖坑法来分数组
* @param {number[]} arr - 需要分解的数组
* @param {number} left - 开始的位置
* @param {number} right - 结束的位置
*/
function partition2(arr, left, right) {
const pivot = arr[right];
while (left < right) {
while (left < right && arr[left] <= pivot) {
left++;
}
arr[right] = arr[left];
while (left < right && arr[right] >= pivot) {
right--;
}
arr[left] = arr[right];
}
arr[left] = pivot;
return left;
}
/**
* @description 使用前后指针法分数组
* @param {number[]} array - 需要排序的数组
*/
export function quickSort3(array) {
function QuickSort(arr, left, right) {
if (left < right) {
const pivot = partition4(arr, left, right);
QuickSort(arr, left, pivot - 1);
QuickSort(arr, pivot + 1, right);
}
}
QuickSort(array, 0, array.length - 1);
}
/**
* @description 使用前后指针法
* @param {number[]} arr
* @param {number} left - 开始的位置
* @param {number} right - 结束的位置
*/
// eslint-disable-next-line no-unused-vars
function partition3(arr, left, right) {
let cur = left;
let pre = left - 1;
const pivot = arr[right]; // 选取最后一个元素作为中枢
while (cur < right) {
if (arr[cur] < pivot) {
swap(arr, cur, ++pre);
}
cur++;
}
/*
循环结束之后pre所处的元素之前都是小于pivot包含pre,右侧的元素都是大于或等于pivot的交换cur+1和pviot的值
*/
swap(arr, pre + 1, right);
return pre + 1;
}
/**
* @description 使用前后指针法(优化版)
* @param {number[]} arr
* @param {number} left - 开始的位置
* @param {number} right - 结束的位置
*/
function partition4(arr, left, right) {
let cur = left;
let pre = left - 1;
const pivot = arr[right]; // 选取最后一个元素作为中枢
while (cur < right) {
if (arr[cur] < pivot && ++pre !== cur) {
swap(arr, pre, cur);
}
cur++;
}
/*
循环结束之后pre所处的元素之前都是小于pivot包含pre,右侧的元素都是大于或等于pivot的交换cur+1和pviot的值
*/
swap(arr, pre + 1, right);
return pre + 1;
}
/**
* @description 使用非递归方式实现快速排序
* @param {number[]} arr - 需要排序的数组
*/
export function quickSort4(arr) {
if (!arr.length || arr.length === 1) return; // 数组为空或者数组为1不处理
const left = 0;
const right = arr.length - 1;
const stack = []; // js的数组有push和pop符合栈结构
stack.push(right);
stack.push(left);
while (stack.length) {
const l = stack.pop(); // 弹出需要处理的左边l
const r = stack.pop(); // 弹出需要处理的有边界
const pivot = partition4(arr, l, r);
// l < pivot - 1 说明还可以分当l = pivot -1 说明pivot左侧就一个数说明左侧已经有序了无须再分
if (l < pivot - 1) {
stack.push(pivot - 1);
stack.push(l);
}
if (r > pivot + 1) {
stack.push(r);
stack.push(pivot + 1);
}
}
}
export function quickSort5(arr) {
const stack = [];
stack.push(arr.length - 1);
stack.push(0);
while (stack.length) {
const l = stack.pop();
const r = stack.pop();
const index = partition4(arr, l, r);
if (l < index - 1) {
stack.push(index - 1);
stack.push(l);
}
if (r > index + 1) {
stack.push(r);
stack.push(index + 1);
}
}
}
/*
1000000个数据测试下来发现partition partition3和4基本上无区别而且4只是减少了代码并没有减少执行
过程,而且使代码变得难以理解,不推荐使用,推荐使用挖坑法来分数组,
Function execution time: 464.513192 milliseconds
Function execution time: 418.692408 milliseconds
Function execution time: 467.99971000000005 milliseconds
*/