diff --git a/sort/quick-sort.mjs b/sort/quick-sort.mjs new file mode 100644 index 0000000..b769333 --- /dev/null +++ b/sort/quick-sort.mjs @@ -0,0 +1,150 @@ +import { swap } from "../util/index.mjs" + +/** + * + * @param {number[]} arr + */ +export function quickSort(arr) { + function QuickSort(arr, left, right) { + if (left < right) { + let index = partition(arr, left, right) + QuickSort(arr, left, index-1) // index是中心轴无需参与排序,若写成index会造成堆栈益处 + QuickSort(arr, index+1, right) + } + } + QuickSort(arr,0, arr.length - 1) + return arr +} + + +/** + * @description 使用左右指针法来分数组 + * @param {number[]} arr - 需要分治的函数 + * @param {number} left - 开始的位置 + * @param {number} right - 结束的位置 + */ +function partition(arr, left, right) { + let pivot = arr[right] // 以right作为pivot + let 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[]} arr - 需要快速排序的数组 + */ +export function quickSort2(arr){ + 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(arr,0, arr.length-1) +} + +/** + * @description 使用挖坑法来分数组 + * @param {number[]} arr - 需要分解的数组 + * @param {number} left - 开始的位置 + * @param {number} right - 结束的位置 + */ +function partition2(arr, left, right){ + let pivot = arr[right] + while(left < right) { + while(left= pivot) { + right-- + } + arr[left] = arr[right] + } + arr[left] = pivot + return left +} + +/** + * @description 使用前后指针法分数组 + * @param {number[]} arr - 需要排序的数组 + */ +export function quickSort3(arr) { + 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(arr, 0, arr.length -1) +} + +/** + * @description 使用前后指针法 + * @param {number[]} arr + * @param {number} left - 开始的位置 + * @param {number} right - 结束的位置 + */ +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 +} + +/* + 1000000个数据测试下来发现,partition ,partition3和4基本上无区别,而且4只是减少了代码,并没有减少执行 + 过程,而且使代码变得难以理解,不推荐使用,推荐使用挖坑法来分数组, + Function execution time: 464.513192 milliseconds + Function execution time: 418.692408 milliseconds + Function execution time: 467.99971000000005 milliseconds + + */