sort06-快速排序

2023-10-30

快速排序

快速排序是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

排序原理:

  • 1.首先设定一个分界值,通过该分界值将数组分成左右两部分;
  • 2.将大于或等于分界值的数据放到到数组右边,小于分界值的数据放到数组的左边。此时左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值;
  • 3.然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
  • 4.重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左侧和右侧两个部分的数据排完序后,整个数组的排序也就完成了。
    在这里插入图片描述

需求

排序前:{6, 1, 2, 7, 9, 3, 4, 5, 8}
排序后:{1, 2, 3, 4, 5, 6, 7, 8, 9}

切分原理:

把一个数组切分成两个子数组的基本思想:
1.找一个基准值,用两个指针分别指向数组的头部和尾部;
2.先从尾部向头部开始搜索一个比基准值小的元素,搜索到即停止,并记录指针的位置;
3.再从头部向尾部开始搜索一个比基准值大的元素,搜索到即停止,并记录指针的位置;
4.交换当前左边指针位置和右边指针位置的元素;
5.重复2,3,4步骤,直到左边指针的值大于右边指针的值停止。
在这里插入图片描述

代码实现

public class Quick {
    /*
      比较v元素是否小于w元素
   */
    private static boolean less(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }



    /*
   数组元素i和j交换位置
    */
    private static void exch(Comparable[] a, int i, int j) {
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }

    //对数组内的元素进行排序
    public static void sort(Comparable[] a) {
        int lo = 0;
        int hi = a.length-1;
        sort(a,lo,hi);
    }

    //对数组a中从索引lo到索引hi之间的元素进行排序
    private static void sort(Comparable[] a, int lo, int hi) {
        //安全性校验
        if (hi<=lo){
            return;
        }

        //需要对数组中lo索引到hi索引处的元素进行分组(左子组和右子组);
        int partition = partition(a, lo, hi);//返回的是分组的分界值所在的索引,分界值位置变换后的索引

        //让左子组有序
        sort(a,lo,partition-1);

        //让右子组有序
        sort(a,partition+1,hi);
    }

    //对数组a中,从索引 lo到索引 hi之间的元素进行分组,并返回分组界限对应的索引
    public static int partition(Comparable[] a, int lo, int hi) {
       //确定分界值
        Comparable key = a[lo];
        //定义两个指针,分别指向待切分元素的最小索引处和最大索引处的下一个位置
        int left=lo;
        int right=hi+1;

        //切分
        while(true){
            //先从右往左扫描,移动right指针,找到一个比分界值小的元素,停止
            while(less(key,a[--right])){
                if (right==lo){
                    break;
                }
            }

            //再从左往右扫描,移动left指针,找到一个比分界值大的元素,停止
            while(less(a[++left],key)){
                if (left==hi){
                    break;
                }
            }
            //判断 left>=right,如果是,则证明元素扫描完毕,结束循环,如果不是,则交换元素即可
            if (left>=right){
                break;
            }else{
                exch(a,left,right);
            }
        }

        //交换分界值
        exch(a,lo,right);

       return right;
    }

}

//test代码
public class QuickTest {
    public static void main(String[] args) {
        Integer[] a= {6, 1, 2, 7, 9, 3, 4, 5, 8};
        Quick.sort(a);
        System.out.println(Arrays.toString(a));//{1, 2, 3, 4, 5, 6, 7, 8, 9}
    }
}

快速排序和归并排序的区别:

快速排序是另外一种分治的排序算法,它将一个数组分成两个子数组,将两部分独立的排序。快速排序和归并排序是互补的:归并排序将数组分成两个子数组分别排序,并将有序的子数组归并从而将整个数组排序,而快速排序的方式则是当两个数组都有序时,整个数组自然就有序了。在归并排序中,一个数组被等分为两半,归并调用发生在处理整个数组之前,在快速排序中,切分数组的位置取决于数组的内容,递归调用发生在处理整个数组之后。

快速排序时间复杂度分析:

快速排序的一次切分从两头开始交替搜索,直到left和right重合,因此,一次切分算法的时间复杂度为O(n),但整个快速排序的时间复杂度和切分的次数相关。
最优情况:每一次切分选择的基准数字刚好将当前序列等分。
在这里插入图片描述
如果我们把数组的切分看做是一个树,那么上图就是它的最优情况的图示,共切分了 logn次,所以,最优情况下快速排序的时间复杂度为O(nlogn);
最坏情况:每一次切分选择的基准数字是当前序列中最大数或者最小数,这使得每次切分都会有一个子组,那么总共就得切分n次所以,最坏情况下,快速排序的时间复杂度为O(n^2);
在这里插入图片描述
平均情况:每一次切分选择的基准数字不是最大值和最小值,也不是中值,这种情况我们也可以用数学归纳法证明,快速排序的时间复杂度为O(nlogn),由于数学归纳法有很多数学相关的知识,容易使我们混乱,所以这里就不对平均情况的时间复杂度做证明了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

sort06-快速排序 的相关文章

  • 返回链表的中间结点

    返回链表的中间结点 给定一个带有头结点 head 的非空单链表 返回链表的中间结点 如果有两个中间结点 则返回第二个中间结点 用快慢指针来写 Node Fast Node Slow 先初始化 让Fast和Slow都指向第一个链表节点 然后让
  • 算法笔记之GD,BGD,SGD

    在讨论GBDT前 先来看看什么是GD BGD和SGD GD Gradient Descent 梯度下降 求损失函数最小值 梯度下降 求损失函数最大值 梯度上升 假设线性模型 其中 是参数 损失函数为 那么每次GD的更新算法为 BGD Bat
  • 2016腾旭研发工程师笔试题

    用C C 代码算出满足上述条件的值 我们首先来分析一下 step0 我们可以得到如下方程 step1 由方程 1 3 6 可得 我们可以把x1 x5 x6看成自变量 x2 x8 x7看成对应的函数 这样只要x1 x5 x6确定了 x2 x8
  • P1229 遍历问题洛谷

    洛谷P1229 遍历问题 题目描述 我们都很熟悉二叉树的前序 中序 后序遍历 在数据结构中常提出这样的问题 已知一棵二叉树的前序和中序遍历 求它的后序遍历 相应的 已知一棵二叉树的后序遍历和中序遍历序列你也能求出它的前序遍历 然而给定一棵二
  • 【PAT】1033 旧键盘打字 (20 分)

    1033 旧键盘打字 20 分 旧键盘上坏了几个键 于是在敲一段文字的时候 对应的字符就不会出现 现在给出应该输入的一段文字 以及坏掉的那些键 打出的结果文字会是怎样 输入格式 输入在 2 行中分别给出坏掉的那些键 以及应该输入的文字 其中
  • 小波变换

    原文地址 1 小波变换 小波变换是一种信号的时间 尺度 时间 频率 分析方法 它具有多分辨分析的特点 而且在时频两域都具有表征信号局部特征的能力 是一种窗口大小固定不变但其形状可改变 时间窗和频率窗都可以改变的时频局部化分析方法 即在低频部
  • 代码随想录一刷-Day08

    Offer58 II 左旋转字符串 使用中间数组很容易 public String reverseLeftWords String s int n if n 0 s null s length 0 return s 使用中间数组 char
  • 前缀和&差分

    前缀和 能快速求出来一段数的和 比如说从 l r 的和 可以说是最大的应用 是个很重要的技巧 下标从1开始 二维前缀和 leedcode练习 724 寻找数组的中心下标 思路 记数组的全部元素之和为 total 当遍历到第 i 个元素时 设
  • 两个有序序列的中位数(详解)

    1 实践题目 7 3 两个有序序列的中位数 2 问题描述 在一行中输出两个输入序列的并集序列的中位数 时间复杂度不能大于O logn 3 算法描述 不能粘贴程序 因为时间复杂度不能大于logn 所以把原序列排好序再来找中位数是不可能的了 快
  • 刷题之合并二叉树

    给定两个二叉树 想象当你将它们中的一个覆盖到另一个上时 两个二叉树的一些节点便会重叠 你需要将他们合并为一个新的二叉树 合并的规则是如果两个节点重叠 那么将他们的值相加作为节点合并后的新值 否则不为 NULL 的节点将直接作为新二叉树的节点
  • 模型选择、欠拟合和过拟合学习笔记

    训练误差 泛化误差 训练误差 模型在训练数据集上表现出的误差 泛化误差 指模型在任意一个测试数据样本上表现出的误差的期望 并常常通过测试数据集上的误差来近似 过拟合 欠拟合 过拟合 训练误差远小于其在测试数据集上的误差 欠拟合 模型无法得到
  • 二叉树——求两个节点的最近公共祖先

    题目 给定一颗二叉树的头结点 和这颗二叉树中2个节点n1和n2 求这两个节点的最近公共祖先 思路 利用后序遍历实现 对于当前节点cur 如果节点为null或者等于n1或n2中的一个 则直接返回cur 先处理左右子树 左子树返回left 右子
  • 刷题之455. 分发饼干 -----贪心初试

    假设你是一位很棒的家长 想要给你的孩子们一些小饼干 但是 每个孩子最多只能给一块饼干 对每个孩子 i 都有一个胃口值 g i 这是能让孩子们满足胃口的饼干的最小尺寸 并且每块饼干 j 都有一个尺寸 s j 如果 s j gt g i 我们可
  • 算法:链表

    单链表 单链表是一种链式存取的数据结构 链表中的数据是以结点来表示的 每个结点存储两个数据 一是该结点本身的值 二是其指向的下一结点的下标 用e i 表示节点i的值 用ne i 表示结点i指向的下一结点的坐标 head表示头结点的下标 id
  • 程序设计的基本方法

    IPO模式 输入 处理 算法 是程序的灵魂 输出 问题的计算部分 程序编写步骤 分析问题 确定问题 设计算法 编写实现 调试测试 升级维护 编程技巧之流程图 我们写的程序都是有逻辑顺序的 即是有流程的 流程图的作用则是对这种逻辑顺序的一种描
  • 计算几何学

    问题描述 对于线段s1 s2 如果相交则输出 1 否则输出 0 设s1的端点为p0 p1 s2的端点为p2 p3 输入 第1行输入问题数q 接下来q行给出q个问题 各问题线段s1 s2的坐标按照以下格式给出 x p 0 x p0
  • 递归行为时间复杂度计算:master公式

    master公式 T N a T N b O N d 公式解释 N是初始问题的负责度 a是次数的意思 也就是调用相同规模的递归次数 b是递归的划分 也就是将原问题划分成相同规模的b份 O N d d是除去递归代码外的其他运算的时间复杂度 例
  • 数论算法:唯一因子分解定理

    这里讲一下算法中常用到的唯一因子分解定理 合数a仅能以一种方式写成如下乘积形式 a p1 e1 p2 e2 pr er 其中pi为素数 p1
  • 数组的对数器

    原创是某客的左程云老师 我只是加了点自己的注释记个笔记 package basic class 01 import java util Arrays 对数器的作用 对数器可以验证算法是否正确 在比赛或者笔试的时候 如果需要大量的测试用例 而
  • 《算法通关村——滑动窗口高频问题之**寻找子串异位词**》

    算法通关村 滑动窗口高频问题之 寻找子串异位词 567 字符串的排列 给你两个字符串 s1 和 s2 写一个函数来判断 s2 是否包含 s1 的排列 如果是 返回 true 否则 返回 false 换句话说 s1 的排列之一是 s2 的 子

随机推荐

  • 深圳大学第三期“飞鹰计划”正式开班

    金秋九月 丹桂飘香 在这个充满着收获的季节里 迎来了期待已久的深圳大学机电与控制工程学院飞鹰计划2022级第三期开班典礼 受疫情影响 虽然典礼只能在线上举行 但是丝毫不影响电巢专家及学生们的热情 9月17日下午 百余位同学通过线上参加了此次
  • uCOS-II信号量OSSemCreate(0)和OSSemCreate(1)详解

    在ucos II中 为了实现任务之间的同步 用到的同步机制有 信号量 邮箱和消息队列 其中这里我主要说下对信号量的使用经验 信号量在创建时 调用OSSemCreate INT16U cnt 函数 cnt为信号量的初始值 对cnt赋予不同的值
  • Mac OS无法进入系统/数据备份/重装系统方法步骤

    之前我的Mac Mini不知为什么突然间不能进入到系统了 开机的时候基本都时进度条走到2 3的时候就会自动死机 打电话给客户 客服是不错 TM殊不知 聊了N就之后 发现这是要话费的 NM足足磨了1个多小时也没能解决我的问题 好吧 苹果系统时
  • Service Pack 6 for Visual Basic 6.0, Visual C++ 6.0 with Visual Source Safe 6.0d下载

    下载VC6 0的SP6补丁 网址http www microsoft com en us download details aspx id 9183 补充 英文版 http download microsoft com download 1
  • Java设计模式——适配器模式

    文章目录 介绍适配器模式 类适配器模式 对象的适配器模式 接口的适配器模式 介绍适配器模式 适配器主要用于接口的转换或者将接口不兼容的类对象组合在一起形成对外统一接口 是一种结构性模式 其本质是是一个中间件 适用于类及其对象 原理 通过继承
  • 全网最详!暗黑模式在 Trip.com App 的实践

    作者简介 本文为联合撰稿 作者为携程国际业务研发部UED团队静静 公共研发团队祥星 旭仔 俊仔 增翼 一 背景 在 2019 年 随着 iOS 13 与 Android Q 的推出 Apple 和 Google 同时推出主打功能暗黑模式 分
  • Jquery 菜单插件之 Superfish jQuery菜单

    大家如果想了解 Superfish jQuery菜单 插件 可以查看我发布的一篇 关于JQuery 菜单插件 这里已经告诉我们该jQuery菜单插件的相关优势和下载地址 在下载中包含基础的Demo 初始者可以依次入门 接下来 我们进入我们开
  • C语言:爱心程序

    1 效果展示 2 结构分析 该爱心主要采用暴力拼接上去的 主要由三部分组成 第一部分 头部 是固定的程序编码 第二部分 是一个长为29个 宽为3个的矩形 第三部分 有由一个三角形组成 最长的有27个 下一层较上一层少4个 一共有7层 3 代
  • 「查缺补漏」我的网易前端秘籍-如何准备面试

    前言 开门见山 这篇文章 适合 初级前端 如果你还在校招的话 或者还在求职的话 可以看看本文 找一找灵感 希望对你们有帮助呀 先说一下最近个人情况 2020年8月底已经拿到网易有道offer 这算是我的第一份web前端工作吧 一直以来都是自
  • Ubuntu : 18.04 使用root 帐号 SSH 登录

    Ubuntu 16 04 适用该方法 一 安装ssh 18 04 apt install openssh server 16 04 apt get install openssh server 安装openssh server报错 Depe
  • 移动端html5用什么软件开发,基于uniapp的移动端和web-h5技术开发的移动端区别与应用...

    一 两者的主要区别 基于uniapp前端框架技术开发的移动端 实现了前后端分离 可支持各种旅游小程序等电商系统搭建 实现旅游产品多端展现 让游客在哪里都可以购买到你的产品和服务 一个管理平台 十端同步展现 基于web h5开发的移动端 采用
  • 数据源自动重连机制设置

    一 场景 在网络状况不是非常良好 经常会出现暂时性的拥塞或者断开的情况 而且当我们重启数据库时也会发生类似的情况 所以需要配置中间件的连接池来实现连接测试以及自动重连 通过重新配置连接池 成功解决了这个问题 下面会给出一份数据源配置参数详单
  • Jupyter Lab设置切换虚拟环境

    在进行数据科学任务时 一般会用到交互式开发环境 即Jupyter Notebook Jupyter lab是Jupyter Notebook的升级版 功能更强大 更好用 但是默认情况下 是不能切换虚拟环境的 如下 或者查看内核列表 有2个位
  • promise介绍和使用

    promise实例讲解 1 Promise定义 es6提供的一种新的适合书写异步任务 尤其需要多次连续调用的异步任务的解决方案 是一个构造函数 直接在浏览器控制台打印看下 执行如下语句 console dir Promise 可以看到typ
  • 大数据导论第二章——数据预处理与特征工程

    一 数据预处理 数据预处理的目标 数据预处理的目标就是要从数据分析要解决的问题出发 产生高质量的 能够满足分析需求 提高分析质量的数据集 从现实生活中收集到的原始数据都是低质量的数据集 会存在数据缺失 有噪音等问题 而用低质的数据直接进行分
  • Linux下C和C++程序中内存泄露检测

    01 前言 C C 运行高效 不管是操作系统内核还是对性有要求的程序 比如游戏引擎 都要求使用C C 来编写 其实C C 强大的一点在于能够使用指针自由地控制内存的使用 适时的申请内存和释放内存 从而做到其他编程语言做不到的高效地运行 但是
  • 多体交叉存储器

    计算机中大容量的主存 可由多个存储体组成 每个体都具有自己的读写线路 地址寄存器和数据寄存器 称为 存储模块 这种多模块存储器可以实现重叠与交叉存取 如果在M个模块上交叉编址 M 2m 则称为模M交叉编址 模M交叉编址方式 设存储器包括M个
  • 服务器虚拟内存设置一下,服务器虚拟内存设置一下

    服务器虚拟内存设置一下 内容精选 换一换 对于不同的硬件设备 通过在BIOS中设置一些高级选项 可以有效提升服务器性能 服务器上的SMMU一般用来完成设备的地址转换 并且可以实现设备隔离 在虚拟化中很实用 但是在物理机测试场景下 SMMU可
  • 两个ESP32和Raspberry Pi代理间的MQTT通讯

    在本教程中 您将了解有关 MQTT 消息传递协议 为什么要使用它以及它是如何实现的所有信息 简而言之 MQTT 使用您现有的 Internet 家庭网络向您的 IoT 设备发送消息并响应这些消息 要按照本教程中的示例进行操作 您将需要以下硬
  • sort06-快速排序

    sort 快速排序 排序原理 需求 切分原理 代码实现 快速排序和归并排序的区别 快速排序时间复杂度分析 快速排序 快速排序是对冒泡排序的一种改进 它的基本思想是 通过一趟排序将要排序的数据分割成独立的两部分 其中一部分的所有数据都比另外一