周周爱学习之快速排序

        快速排序,顾名思义,快速排序是一种速度非常快的一种排序算法

  • 平均时间复杂度为O(nlog_{2}n),最坏时间复杂度为O(n^{^{2}})
  • 数据量较大时,优势非常明显
  • 属于不稳定排序

1.算法描述

  1. 每一轮排序选择一个基准点(pivot)进行分区

    1. 让小于基准点的元素的进入一个分区,大于基准点的元素的进入另一个分区

    2. 当分区完成时,基准点元素的位置就是其最终位置

  2. 在子分区内重复以上过程,直至子分区元素个数少于等于 1,这体现的是分而治之的思想 (divide-and-conquer

  3. 从以上描述可以看出,一个关键在于分区算法,常见的有洛穆托分区方案、双边循环分区方案、霍尔分区方案

2.单边循环快排(lomuto 洛穆托分区方案)

  1. 选择最右元素作为基准点元素

  2. j 指针负责找到比基准点小的元素,一旦找到则与 i 进行交换

  3. i 指针维护小于基准点元素的边界,也是每次交换的目标索引

  4. 最后基准点与 i 交换,i 即为分区位置

代码实现

    public static void main(String[] args) {
        int[] a = {5, 3, 7, 2, 9, 8, 1, 4};
        System.out.println(Arrays.toString(a));
        quick(a, 0, a.length - 1);
    }

    public static void quick(int[] a, int l, int h) {
        if (l >= h) {
            return;
        }
        int p = partition(a, l, h); // p 索引值
        quick(a, l, p - 1); // 左边分区的范围确定
        quick(a, p + 1, h); // 左边分区的范围确定
    }

    private static int partition(int[] a, int l, int h) {
        int pv = a[h]; // 基准点元素
        int i = l;
        for (int j = l; j < h; j++) {
            if (a[j] < pv) {
                if (i != j) {
                    swap(a, i, j);
                }
                i++;
            }
        }
        if (i != h) {
            swap(a, h, i);
        }
        System.out.println(Arrays.toString(a) + " i=" + i);
        // 返回值代表了基准点元素所在的正确索引,用它确定下一轮分区的边界
        return i;
    }

3.双边循环快排(不完全等价于 hoare 霍尔分区方案)

  1. 选择最左元素作为基准点元素

  2. j 指针负责从右向左找比基准点小的元素,i 指针负责从左向右找比基准点大的元素,一旦找到二者交换,直至 i,j 相交

  3. 最后基准点与 i(此时 i 与 j 相等)交换,i 即为分区位置

要点

  1. 基准点在左边,并且要先 j 后 i

  2. while( i < j && a[j] > pv ) j--

  3. while ( i < j && a[i] <= pv ) i++

代码实现

    public static void main(String[] args) {
        int[] a = {5, 3, 7, 2, 9, 8, 1, 4};
        System.out.println(Arrays.toString(a));
        quick(a, 0, a.length - 1);
    }

    private static void quick(int[] a, int l, int h) {
        if (l >= h) {
            return;
        }
        int p = partition(a, l, h);
        quick(a, l, p - 1);
        quick(a, p + 1, h);
    }

    private static int partition(int[] a, int l, int h) {
        int pv = a[l];
        int i = l;
        int j = h;
        while (i < j) {
            // j 从右找小的
            while (i < j && a[j] > pv) {
                j--;
            }
            // i 从左找大的
            while (i < j && a[i] <= pv) {
                i++;
            }
            swap(a, i, j);
        }
        swap(a, l, j);
        System.out.println(Arrays.toString(a) + " j=" + j);
        return j;
    }

相关推荐

  1. 蓝桥 第三 分治 排序

    2023-12-06 05:52:04       35 阅读
  2. 2.4学习

    2023-12-06 05:52:04       24 阅读
  3. 近两学习计划

    2023-12-06 05:52:04       17 阅读
  4. 排序快速排序

    2023-12-06 05:52:04       36 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-06 05:52:04       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-06 05:52:04       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-06 05:52:04       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-06 05:52:04       18 阅读

热门阅读

  1. vue自定义指令配置小程序按钮权限

    2023-12-06 05:52:04       36 阅读
  2. 第八章 List、Set、数据结构、Collections

    2023-12-06 05:52:04       32 阅读
  3. cookie,session、中间件、csrf认证相关【补充】

    2023-12-06 05:52:04       32 阅读
  4. 【ListView】

    2023-12-06 05:52:04       39 阅读
  5. docker安装常用的中间件脚本

    2023-12-06 05:52:04       28 阅读
  6. 水库监管AI视觉算法与边缘计算盒子

    2023-12-06 05:52:04       62 阅读
  7. 在Vue3中使用缓存组件keep-alive vue3缓存组件

    2023-12-06 05:52:04       41 阅读
  8. 企业微信协议开发,API接口调用

    2023-12-06 05:52:04       36 阅读
  9. C#-剖析文件和流并快速使用

    2023-12-06 05:52:04       41 阅读