浅析快速排序和归并排序

快速排序

伪代码框架
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函数对数组的切分排序了。

基本思想:
  1. 选取array[low]作为基准值,临时保存到pivot
  2. 比较array[high]和基准值pivothigh指针向左移动,直到array[high]小于基准值pivot时,将array[high]赋值到array[low]
  3. 比较array[low]和基准值pivotlow指针向右移动,直到array[low]大于基准值pivot时,将array[low]赋值到array[high];
  4. 循环2,3操作,直到low大于等于high,结束循环;
  5. 将基准值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函数对数组的合并排序了。

基本思想
  1. 明确左右两个数组边界[leftStart, leftEnd][rightStart, rightEnd],临时数组索引值index = 0;
  2. 循环遍历两个数组,如果array[leftStart]小于等于array[rightStart],小的值array[leftStart]填充到临时数组中,leftStart++, index++;如果array[leftStart]大于array[rightStart],小的值array[rightStart填充到临时数组中,rightStart++, index++
  3. 有可能存在左侧数组还剩余元素,依次加入临时数组。
  4. 有可能存在右侧数组还剩余元素,依次加入临时数组。
  5. 将临时数组中这些有序的数依次赋值到原始数组中,便于下次递归按照最新值进行排序。
实现
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--;
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青菜小王子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值