快速排序
伪代码框架
quickSort(array, low, high) {
if(low >= high) return;
let mid = partition(array, low, high); // 切分数组,并返回分界点mid
quickSort(array, low, mid - 1); // 递归左区间
quickSort(array, mid + 1, high); // 递归右区间
}
快排和二叉树的前序遍历
框架很类似
traverse(root){
root.val // 前序遍历
traverse(root.left);
traverse(root.right);
}
那么核心代码就剩下partition
函数对数组的切分排序了。
基本思想:
- 选取
array[low]
作为基准值,临时保存到pivot
; - 比较
array[high]
和基准值pivot
,high
指针向左移动,直到array[high]
小于基准值pivot
时,将array[high]
赋值到array[low]
; - 比较
array[low]
和基准值pivot
,low
指针向右移动,直到array[low]
大于基准值pivot
时,将array[low]
赋值到array[high]
; - 循环2,3操作,直到
low
大于等于high
,结束循环; - 将基准值pivot赋值到
array[low]
,此时low
已经等于high
,返回分界点low
即完成一次切分。基准值左侧是比它小的值,右侧是比它大的值。
实现
const partition = (array, low, high) => {
let pivot = array[low]; // 选取基准值
while (low < high) {
while (low < high && array[high] >= pivot) { // array[high]小于pivot,退出循环
high--;
}
array[low] = array[high];
while (low < high && array[low] <= pivot) { // array[low]大于pivot,退出循环
low++;
}
array[high] = array[low];
}
array[low] = pivot;
return low;
}
图例
选取基准值3,扫描右边,找到2小于3,将arr[9]赋值到arr[0];扫描左边,44大于3,将arr[1]赋值给arr[9]; 此时low小于high,继续扫描右边,知道low==high,基准值归位。
归并排序
伪代码框架
mergeSort(array, low, high){
if(low >= high) return;
const mid = parseInt((low + high) / 2); // 获取中间分界点 mid
mergeSort(array, low, mid); // 递归左区间
mergeSort(array, mid + 1, high);
merge(array, low, mid, high); //对两个数组进行合并,使得有序
}
归并排序和二叉树的后序遍历
框架很类似
traverse(root){
traverse(root.left);
traverse(root.right);
root.val // 后序遍历
}
那么核心代码就剩下merge
函数对数组的合并排序了。
基本思想
- 明确左右两个数组边界
[leftStart, leftEnd]
和[rightStart, rightEnd]
,临时数组索引值index = 0; - 循环遍历两个数组,如果
array[leftStart]
小于等于array[rightStart]
,小的值array[leftStart]
填充到临时数组中,leftStart++, index++
;如果array[leftStart]
大于array[rightStart]
,小的值array[rightStart
填充到临时数组中,rightStart++, index++
; - 有可能存在左侧数组还剩余元素,依次加入临时数组。
- 有可能存在右侧数组还剩余元素,依次加入临时数组。
- 将临时数组中这些有序的数依次赋值到原始数组中,便于下次递归按照最新值进行排序。
实现
const merge = (array, leftStart, leftEnd, rightEnd) => {
const newArr = [];
let rightStart = leftEnd + 1; // 右侧数组起始索引
let newIndex = leftStart;
let count = rightEnd - leftStart + 1; // 当前已排好序的元素数
while (leftStart <= leftEnd && rightStart <= rightEnd) {
if (array[leftStart] <= array[rightStart]) {
newArr[newIndex] = array[leftStart];
leftStart++;
newIndex++;
} else if (array[leftStart] > array[rightStart]) {
newArr[newIndex] = array[rightStart];
rightStart++;
newIndex++;
}
}
// 处理左区间剩余元素
while (leftStart <= leftEnd) {
newArr[newIndex] = array[leftStart];
leftStart++;
newIndex++;
}
// 处理右区间剩余元素
while (rightStart <= rightEnd) {
newArr[newIndex] = array[rightStart];
rightStart++;
newIndex++;
}
// 拷贝排好序的数据到原数组中,方便下次循环,按照已排序的值进行比较
for (let i = 0; i < count; i++) {
array[rightEnd] = newArr[rightEnd]
rightEnd--;
}
}