算法通关村之快速排序(基础知识 + 实战训练):简单的快速排序、查找数组第K大数、归并排序

基础知识(青铜挑战)

  • 快速排序通过多次比较与交换来完成排序。而这个过程又被分为了多次重复单趟排序,接下来我们先从每一趟的排序讲起。

  • 快速排序思想很简单,也很重要:

  • 在一个无序数组中取一个数key,每一趟排序的最终目的是:让key的左边的所有数小于key,key的右边都大于key(假设排升序)

  • 接下来,我们对key的左右区间进行单趟排序,可以预见的是,每次排序都固定好了一个数。而当我们对细分的左右区间进行单趟排序,最终整个数组都会化为有序

  • 最常用的快排实现方法:快慢指针法

    • 取最左边的数为key

    • 定义两个快慢指针,都从key的下一位往右走

    • ast每走一步判断一下它指向的元素是否小于key,若小于则交换fast和slow位置的元素,并且让slow向前走

    • 直到fast走到底,结束循环

    • 最后让slow和key位置的值交换,再返回key的位置

  • 具体代码如下:(2023/09/19午)
public void quickSort(int[] nums, int start, int end) {
        // 判断递归结束的条件
        if (start >= end) {
            return;
        }
        // 选定最左边的元素作为基准值
        int pivot = nums[start];
        // 初始化快慢指针
        int slow = start;
        int fast = start + 1;
​
        // 快慢指针法进行划分
        while (fast <= end) {
            if (nums[fast] < pivot) {
                // 如果当前元素小于基准值,将其交换到基准值的左侧
                slow++;
                swap(nums, slow, fast);
            }
            fast++;
        }
        // 将基准值交换到正确的位置
        swap(nums, start, slow);
​
        // 递归对基准值的左右两部分进行排序
        quickSort(nums, start, slow - 1);
        quickSort(nums, slow + 1, end);
    }
​
    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

实战训练(白银挑战)

数组中K大的数
  • 我们要找第K大的元素,如果我们能够将数组排好序,再取 nums[K - 1] 元素,就是目标值了
  • 试想一下,每一轮快排结束之后,我们能知晓基准值的位置,即我们知晓基准值的下标

    • 如果目标元素在基准元素的左侧,就对左侧进行递归快排

    • 否则,对右侧进行递归快排

    • 最后,在已经 ”排好序的“ 数组中,轻松就能找到第K大的元素

    • 其实就是快速排序对半砍,每次只快排一半元素,要么左侧,要么右侧(2023/09/27晚)
 public static void quicksort(int[] nums, int left, int right) {
        int start = left;
        int end = right;
        int pivot = nums[(end + start) / 2]; //取中位值作左右参考对比
​
        //每次循环都将大的放到左边,小的放到右边
        while (start < end) {
            while (nums[start] > pivot) {
                start++;
            }
​
            while (nums[end] < pivot) {
                end--;
            }
​
            //如果l>=r说明mid左边的值全部大于等于mid的值,右边全是小的,退出
            if (start >= end) {
                break;
            }
            //交换
            int temp = nums[start];
            nums[start] = nums[end];
            nums[end] = temp;
​
            //解决值相同的情况,如果交换后发现左边的值等于mid目标值,则使右边指针向左移
            if (nums[start] == pivot) {
                end--;
            }
            //右边的值等于mid目标值,则使左边指针向左移
            if (nums[end] == pivot) {
                start++;
            }
        }
​
        if (start == end) { //退出循环防止栈溢出
            start++;
            end--;
        }
        
        if (left < end) {
            quicksort(nums, left, end);   //向左递归
        }
        
        if (right > start) {
            quicksort(nums, start, right); //向右递归
        }
    }
归并排序
  • 好难好难,需要先理解思路,再考虑编码实现:

    • 归并排序简单来讲,就是将大的序列视为若干小的数组,利用归并思想实现排序的方法。

    • 分治策略(分:把问题分成小的问题分别求解;治:将分的阶段得到的各答案合在一起)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值