Java基础(十一)快速排序

news2024/11/27 8:31:16

4. 快速排序

>> 快速排序的思想
此图来自嘎嘎干饭的鹏鹏,快速排序

快速排序(QuickSort)是一种高效的排序算法,基于分治策略。它的原理可以概括为以下步骤:

  1. 选择一个基准元素(pivot),通常选择数组中的一个元素作为基准。这个基准元素将用来将数组分割为较小和较大的两个子数组。

  2. 分区过程(Partition):将数组中的元素重新排列,将所有比基准元素小的元素移动到其左边,所有比基准元素大的元素移动到其右边。基准元素的最终位置被确定,称为分区点(partition point),这个过程称为分区。

  3. 对两个子数组递归地应用上述过程。递归地将子数组分别进行分区,直到子数组的大小为零或一。递归的结束条件是当子数组的大小为零或一时,说明数组已经有序。

  4. 合并子数组:将所有子数组合并为最终的排序数组。

具体步骤如下:

  1. 选择基准元素,通常选择最右边的元素。
  2. 使用两个指针,一个指向数组的起始位置(low),另一个指向数组的结束位置(high)。
  3. 从起始位置开始,遍历数组,比较每个元素与基准元素的大小关系:
    • 如果元素小于基准元素,将指针 i 向后移动一位,并交换指针 i 和 j 对应的元素。
    • 如果元素大于或等于基准元素,只移动指针 j 向后移动一位。
  4. 当遍历结束时,将基准元素与指针 i 对应的元素交换位置,这样基准元素就处于正确的位置上。
  5. 以基准元素为界,将数组分为两个子数组。对左边的子数组和右边的子数组递归地应用上述过程,直到子数组的大小为零或一。
  6. 递归结束后,所有子数组都有序。将所有子数组合并起来,即得到最终的有序数组。

快速排序的平均时间复杂度为 O(n log n),其中 n 是待排序的元素数量。它是一种原地排序算法,不需要额外的空间。由于其高效性和普适性,快速排序是常用的排序算法之一。

>> 快速排序代码实现

package kfm.bases.Sort;

public class QuickSort {
    public static void main(String[] args) {
        int[] arr = {5, 9, 1, 3, 2, 7, 3};

        System.out.println("Original array: ");
        printArray(arr);

        quickSort(arr, 0, arr.length - 1);

        System.out.println("\nSorted array: ");
        printArray(arr);
    }

    public static void quickSort(int[] arr, int low, int high) {
        // 检查左边界 low 是否小于右边界 high
        if (low < high) {
            // 调用 partition 方法来确定枢轴元素的正确位置,并返回此位置作为 pivotIndex
            int pivotIndex = partition(arr, low, high);
            // 对数组左边进行快排
            quickSort(arr, low, pivotIndex - 1);
            // 对数组右边进行快排
            quickSort(arr, pivotIndex + 1,high);
        }
    }

    // 确定枢轴元素的正确位置,并将数组分为两个子数组。
    public static int partition(int[] arr, int low, int high) {
        // 选取最右边元素轴元素
//        int pivot = arr[high];
//        int i = low - 1;
//
//        for (int j = low; j < high; j++) {
//            if (arr[j] > pivot) {
//                i ++;
//                swap(arr, i, j);
//            }
//        }
//        swap(arr,i + 1, high);
//        return i + 1;

        // 选择最左边元素为轴元素
        int left = low;
        int right = high;
        int base = arr[low];
        while (left < right) {
            while (left < right && arr[right] >= base) {
                right--;
            }
            while (left < right && arr[left] <= base) {
                left++;
            }
            swap(arr, left, right);
        }
        swap(arr, low, left);
        return left;
    }

    // 输出数组元素
    public static void printArray(int[] arr) {
        for (int num : arr) {
            System.out.print(num + " ");
        }
        System.out.println();
    }

    // 交换位置
    public static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

在快速排序算法中,选择基准值的位置可以对算法的性能产生一定的影响。常见的选择基准值的方法有三种:选最左边元素、选最右边元素和选中间元素。

  • 选最左边元素和选最右边元素作为基准值是最简单和最常见的两种方法,它们之间的主要区别在于分区操作的开始位置。如果选择最左边元素作为基准值,分区操作将从序列的左端开始,而选择最右边元素作为基准值,分区操作将从序列的右端开始。

  • 在理想情况下,序列中的元素按照相对大小均匀分布,即序列近似有序。在这种情况下,选择最左边或最右边的元素作为基准值并不会导致分区不平衡的问题,因为分区操作的结果会大致均匀地将较小和较大的元素分布在两个子序列中。

  • 然而,如果序列中的元素出现大量的重复元素,或者序列已经按照近似有序排列,那么选择最左边或最右边的元素作为基准值可能会导致分区不平衡的情况。这样会使得算法的时间复杂度退化到 O(n^2),而不是平均情况下的期望时间复杂度 O(nlogn)

  • 为了避免这种情况,可以采用一些优化策略,如随机选择基准值、三数取中法(选取最左边、最右边和中间位置的元素的中位数作为基准值)等。这样可以增加算法的鲁棒性和适应性,降低时间复杂度的波动性。

综上所述,选择基准值的位置对快速排序算法可能会产生一定的影响,特别是在面对特定分布模式的输入数据时。因此,在实际应用中,根据具体情况选择合适的基准值选择策略,以获取更好的排序性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/877487.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux知识点 -- 进程概念(补充)

Linux知识点 – 进程概念&#xff08;补充&#xff09; 文章目录 Linux知识点 -- 进程概念&#xff08;补充&#xff09;一、进程地址空间的堆区二、虚拟地址到物理地址之间的转化三、虚拟地址到物理地址之间的映射 一、进程地址空间的堆区 在用户每次使用malloc等函数在进程的…

c高级:day4

1.思维导图 2.shell函数获取uid和gid&#xff0c;并用变量接 #!/bin/bashfunction fun() {read -p "输入用户名" necho uid:id -u $necho gid:id -g $n } afun echo $a3.冒泡、选择和快排代码整理 /**************************************************************…

MQTT宝典

文章目录 1.介绍2.发布和订阅3.MQTT 数据包结构4.Demo5.EMQX 1.介绍 什么是MQTT协议 MQTT&#xff08;消息队列遥测传输协议&#xff09;&#xff0c;是一种基于发布/订阅&#xff08;publish/subscribe&#xff09;模式的“轻量级”通讯协议&#xff0c;该协议构建于TCP/IP协…

opencv实战项目 手势识别-手势音量控制(opencv)

本项目是使用了谷歌开源的框架mediapipe&#xff0c;里面有非常多的模型提供给我们使用&#xff0c;例如面部检测&#xff0c;身体检测&#xff0c;手部检测等。 手势识别系列文章 1.opencv实现手部追踪&#xff08;定位手部关键点&#xff09; 2.opencv实战项目 实现手势跟踪…

探索 C++ 标准库:std::string 库函数用法示例

目录 引言 一、构造函数 1.1 string() 1.2 string (const string& str) 1.3 string (const string& str, size_t pos, size_t len npos) 1.4 string (const char* s) 1.5 string (const char* s, size_t n) 1.6 string (size_t n, char c&#xff09;​ 二、容…

剑指offer11-20

文章目录 11.旋转数组的最小数字12.矩阵中的路径13.机器人的运动范围15.二进制中1的个数16.数值的整数次方17.打印从1到最大的n位数&#xff08;待写&#xff09;18.删除链表的节点19.正则表达式匹配&#xff08;好难&#xff09;20. 没意义算了 11.旋转数组的最小数字 肯定不是…

【Git】—— 标签管理

目录 &#xff08;一&#xff09;理解标签 1、作用 &#xff08;二&#xff09;创建标签 &#xff08;三&#xff09;操作标签 1、删除标签 2、推送标签 3、删除远程标签 &#xff08;一&#xff09;理解标签 标签 tag &#xff0c;可以简单的理解为是对某次 commit 的…

C++11时间日期库chrono的使用

chrono是C11中新加入的时间日期操作库&#xff0c;可以方便地进行时间日期操作&#xff0c;主要包含了&#xff1a;duration, time_point, clock。 时钟与时间点 chrono中用time_point模板类表示时间点&#xff0c;其支持基本算术操作&#xff1b;不同时钟clock分别返回其对应…

Jenkins 监控dist.zip文件内容发生变化 触发自动部署

为Jenkins添加plugin http://xx:xx/manage 创建一个任务 构建触发器 每3分钟扫描一次&#xff0c;发现指定文件build.zip文件的MD5发生变化后 触发任务

脚本一键生成通用接口,一分钟实现增删改查

直接使用无需看此配置 快速生成通用接口业务配置 &#xff1a; https://blog.zysicyj.top/2023/08/14/快速生成通用接口业务配置 一、插件安装 二、脚本 关注绿色聊天软件【程序员朱永胜】回复&#xff1a;1013 下载 三、使用 拷贝到扩展目录下 修改mybatisCodehelper.vm 修改i…

【爱书不爱输的程序猿】CPOLAR+HFS,低成本搭建NAS

欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 通过HFS低成本搭建NAS&#xff0c;并内网穿透实现公网访问 - cpolar 极点云 前言1.下载安装cpolar1.1 设置HFS访客1.2 虚拟文件系统 2. 使用cpolar建立一条内网穿透数据隧道2.1 保留…

强化学习 PPO算法和代码

PPO 效果 字体找不到 ubuntu python findfont: Font family ‘Alibaba PuHuiTi 3.0’ not found. shell 清除缓存&#xff1a; rm ~/.cache/matplotlib -rf到这里下载 阿里巴巴普惠体3.0 https://fonts.alibabagroup.com/ 然后安装字体 PPO import matplotlib from mat…

​​C++多态​​

目录 1. 多态的概念 2. 多态的定义及实现 多态的构成条件 虚函数 虚函数的重写 特例 override 和 final 1. final&#xff1a;修饰虚函数&#xff0c;表示该虚函数不能再被重写 2.override: 检查派生类虚函数是否重写了基类某个虚函数&#xff0c;如果没有重写编译报错…

【数据结构】二叉树篇|超清晰图解和详解:二叉树的最近公共祖先

博主简介&#xff1a;努力学习的22级计算机科学与技术本科生一枚&#x1f338;博主主页&#xff1a; 是瑶瑶子啦每日一言&#x1f33c;: 你不能要求一片海洋&#xff0c;没有风暴&#xff0c;那不是海洋&#xff0c;是泥塘——毕淑敏 目录 一、题目二、题解三、代码 一、题目 …

Stable Diffusion +EbSynth应用实践和经验分享

Ebsynth应用 1.安装ffmpeg 2.安装pip install transparent-background,下载模型https://www.mediafire.com/file/gjvux7ys4to9b4v/latest.pth/file 放到C:\Users\自己的用户名.transparent-background\加一个ckpt_base.pth文件 3.秋叶安装ebsynth插件,重启webui 填写项目基本…

线段树-模板-区间查询-区间修改

【模板】线段树 2 传送门&#xff1a;https://www.luogu.com.cn/problem/P3373 题单&#xff1a;https://www.luogu.com.cn/training/16376#problems 题目描述 如题&#xff0c;已知一个数列&#xff0c;你需要进行下面三种操作&#xff1a; 将某区间每一个数乘上 x x x&a…

FPGA学习——驱动WS2812光源并进行动态显示

文章目录 一、WS2812手册分析1.1 WS2812灯源特性及概述1.2 手册重点内容分析1.2.1 产品概述1.2.2 码型及24bit数据设计 二、系统设计2.1 模块设计2.2 模块分析2.2.1 驱动模块2.2.1 数据控制模块 三、IP核设置及项目源码3.1 MIF文件设计3.2 ROM IP核调用3.3 FIFO IP核调用3.4 项…

机器学习-特征选择:如何使用递归特征消除算法自动筛选出最优特征?

一、引言 在实际应用中&#xff0c;特征选择作为机器学习和数据挖掘领域的重要环节&#xff0c;对于提高模型性能和减少计算开销具有关键影响。特征选择是从原始特征集中选择最相关和最具区分力的特征子集&#xff0c;以提高模型的泛化能力和可解释性。 特征选择在实践中具有以…

算法笔试 java 输入输出练习

在线编程题刷题训练 所有答案 scancer函数的用法 输入输出总结top&#xff01;&#xff01;&#xff01;&#xff01; java如何调用函数&#xff08;方法&#xff09; java刷acm的各种输入输出 vscode配置java环境 子函数的调用&#xff0c;直接定义一个static子函数调用就…

人工智能任务1-【NLP系列】句子嵌入的应用与多模型实现方式

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能任务1-【NLP系列】句子嵌入的应用与多模型实现方式。句子嵌入是将句子映射到一个固定维度的向量表示形式&#xff0c;它在自然语言处理&#xff08;NLP&#xff09;中有着广泛的应用。通过将句子转化为向量…