数据结构——快速排序的介绍

news2024/12/24 9:17:35

快速排序

快速排序是霍尔(Hoare)于1962年提出的一种二叉树结构的交换排序方法。快速排序是一种常用的排序算法,其基本思想是通过选择一个元素作为"基准值",将待排序序列分割成两个子序列,其中一个子序列的元素都小于等于基准值,另一个子序列的所有素都大于基准值。然后对这两个子序列分别进行递归排序,最后将排好序的子序列合并起来,即可得到完整的有序序列。

思想

任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。在这里插入图片描述

霍尔版本

霍尔版本单趟排序代码实现

定义两个下标left和right。假设keyi在最左边,那么右边先走。当右边找到比keyi小的就停下。然后左边开始走,当左边找到比keyi大的就停下。交换左右的值。然后直到左右指针碰面,那么将left和keyi的值交换。
在这里插入图片描述
在这里插入图片描述

void QuickSort(int* arr,int begin, int end)
{
   	int left = begin;
    int right = end;
    int keyi = left;
    while (left < right)
    {
        //右边先走
        while (left < right && arr[right] >= arr[keyi])
        {
            right--;
        }
        while (left < right && arr[left] <= arr[keyi])
        {
           left++;
        }
        Swap(&arr[left], &arr[right]);
    }
    Swap(&arr[keyi], &arr[left]);
}

霍尔版本排序代码实现

当单趟排序把第一个keyi的数据放到它应该蹲的位置时,此时数组就可以分成三个部分,分别是[begin,keyi-1],keyi,[keyi+1,end]。此时依据二叉树的递归分治的思路将子区间的数据再次选左边为keyi来进行单趟排序,直到子区间不存在。最后就能够将数据排序。
在这里插入图片描述

针对已有序数组的优化

针对已经有序数组的排序,上面的代码有一个致命的问题。即未优化的快排最坏的情况下时间复杂度为O(N^2)。当数据量大的时候,还会有因为递归而栈溢出的问题。下面介绍第一种优化的方式,即随机数选keyi。

随机数选keyi

通过取数组长度的随机数做keyi,可以在一定程度上避免了完全有序或者接近有序的情况下快速排序的时间复杂度问题。下面简单看一下处理的方式
在这里插入图片描述

三数取中

通过最左边、最右边和中间位置的值作比较,取中间值来做下标keyi。这样在一定程度上可以优化有序或局部有序情况下,快速排序效率下降的问题。

在这里插入图片描述
在这里插入图片描述

挖坑法

挖坑法单趟排序代码实现

由于霍尔大佬的方法比较晦涩难懂,所以就有了我们现在要介绍的挖坑法。挖坑法顾名思义就是根据快排思想下的优化出来的一个版本。先假设key在最左边的数,所以坑位在左边。那么从右边开始走,当碰到比key小的就把它放到坑中,并且将坑位改变到停下的位置。左边同理。
在这里插入图片描述

void QuickSort1(int* arr, int begin, int end)
{
    int left = begin;
    int right = end;
    随机选key
    通过随机数来选择key,优化了顺序和逆序的情况下的时间复杂度
    //int randi = left + (rand() % (right - left));
    //
    //Swap(&arr[randi], &arr[left]);

    //三数取中优化
    int ret = GetMidNum(arr, left, right);
    if (left != ret)
        Swap(&arr[ret], &arr[left]);

    //左边做key
    int key = arr[left];
    int hole = left;
    while (left < right)
    {
        //右边先走
        while (left < right && arr[right] >= key)
        {
            right--;
        }
        //右边比key小就把它填到坑里,并改变坑位
        arr[hole] = arr[right];
        hole = right;
        while (left < right && arr[left] <= key)
        {
            left++;
        }
        //左边比key大就把它填到坑里,并改变坑位
        arr[hole] = arr[left];
        hole = left;
    }
    //最后坑位就是key应该蹲的位置
    arr[hole] = key;
}

挖坑法代码实现

在这里插入图片描述

前后指针法

前后指针法单趟排序代码实现

实现思路如下:首先定义两个指针prev和cur。以最左边作key,cur找小,当cur指向的内容比key小,++prev,prev的值和cur值交换位置(位置重合可以不交换)。当cur找到的值比key大时,++cur。这种方法的大体情况分为两种,一、prev紧跟cur。二、prev和cur直接间隔这一段比key的值。那么此时比key大的值会逐步往后翻,比key小的值会逐步往前甩。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

前后指针法代码实现

在这里插入图片描述

小区间优化

我们知道快速排序其实就是运用了二叉树结构分治的思想来进行排序的。在二叉树这种结构中,当高度为h时,我们考虑最优情况下(满二叉树),最后一层的结点就是2^(h-1)个。占据整棵树的一半。倒数第二层的结点个数为2 ^ (h-2)个,占整棵树结点的25%。其实只要消灭了倒数三层的递归其实就可以在大体上减少递归带来的损耗,提高效率,并且可以让栈区空间的损耗降低。在一个局部有序的小区间内进行优化,我们可以选择的排序有很多种。但是,根据我们前面所学知识我们可以发现,其实使用堆排序和希尔排序相对于小区间优化的优势并没有很明显。前者需要建堆,后者需要根据gap来进行预排序。选择插入排序来小区间优化其实是最适合的。因为在局部有序的区间内,插入排序的效率是最高的。
在这里插入图片描述

在这里插入图片描述

快速排序非递归实现

利用栈来存需要递归的区间,然后根据栈后进先出的性质来模拟递归的顺序。把区间化成子区间进行继续排序。直到区间不存在或区间只有一个数就停止将区间的下标入栈。
在这里插入图片描述

在这里插入图片描述

快速排序的特性总结

一、快速排序是一个综合性能较好和使用场景比较广泛的排序。
二、快速排序的时间复杂度为O(NLogN)。
在这里插入图片描述
在最好情况下,快速排序的时间复杂度为O(nlogn)。当待排序的序列能够均匀地分成两个子序列时,每次分割操作都能将序列大致平分,此时递归调用层数为logn,每层需要的比较次数为n,因此总比较次数为O(N
LogN)。在最坏情况下,快速排序的时间复杂度为O(n ^ 2)。当待排序的序列已经有序或基本有序(例如,序列已经是升序排列,但选择的基准值总是最小或最大元素),每次分割操作只能切割出一个子序列,递归调用的层数为n,每层需要的比较次数为n,因此总比较次数为n ^ 2。然而,通过随机选择基准值或使用三数取中法等优化方法,可以减少最坏情况发生的可能性,从而提高了快速排序的平均性能。在实际应用中,快速排序通泛使用。
三、快速排序是一个不稳定的排序。

代码获取

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

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

相关文章

DAY29:回溯算法(四)组合总和+组合总和Ⅱ

文章目录 39.组合总和思路伪代码为什么传入i而不是i1&#xff0c;不会导致无限循环 完整版剪枝优化剪枝修改完整版补充&#xff1a;std::sort升降序的问题&#xff08;默认升序&#xff09; 40.组合总和Ⅱ思路最开始的写法debug测试&#xff1a;逻辑错误修改完整版&#xff1a;…

营销策划报告个人心得

营销策划报告个人心得篇1 20__年3月27日晚&#xff0c;我们12级市营专业的同学们早早的来到了大成楼。根据网络营销与策划课程实训要求&#xff0c;覃希老师邀请了校外企业经理给我们进行产品培训。 我们按实训项目分别安排在C302和C304教室培训&#xff0c;培训中同学们认认真…

基于深度学习的高精度水果检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度水果&#xff08;苹果、香蕉、葡萄、橘子、菠萝和西瓜&#xff09;检测识别系统可用于日常生活中或野外来检测与定位水果目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的水果目标检测识别&#xff0c;另外支持结果可视…

OpenGL 模板测试

1.示例效果图 选中模型对象&#xff0c;出现模型轮廓。 2.简介 当片段着色器处理完一个片段之后&#xff0c;模板测试会开始执行&#xff0c;和深度测试一样&#xff0c;它也可能会丢弃片段。接下来&#xff0c;被保留的片段会进入深度测试&#xff0c;它可能会丢弃更多的片…

MongoDB集群管理(三)

MongoDB集群管理 集群介绍 为什么使用集群 随着业务数据和并发量的增加&#xff0c;若只使用一台MongoDB服务器&#xff0c;存在着断电和数据风险的问题&#xff0c;故采用Mongodb复制集的方式&#xff0c;来提高项目的高可用、安全性等性能。 MongoDB复制是将数据同步到多个…

LNMP (Nginx网站服务) nginx 平滑升级

目录 1.1 Nginx的简介 1.2 Apache与Nginx的区别 Nginx对比Apache的优势&#xff1a; 1.3 Nginx的进程 Nginx的两个进程&#xff1a; 同步&#xff0c;异步&#xff0c;阻塞&#xff0c;非阻塞的概念补充 阻塞与非阻塞 同步和异步 2.1 编译安装Nginx 2.1 .1 关闭防火墙…

两点边值问题的有限元方法以及边值条件的处理示例

文章目录 引言题目补全方程刚度矩阵构造基底边值条件非齐次左边值条件非齐次右边值条件非齐次非齐次边值条件有限元方程 求数值解直接求总刚度矩阵先求单元刚度矩阵 引言 本文参考李荣华教授的《偏微分方程数值解法》一书 题目 对于非齐次第二边值问题 { − d d x ( p d u …

陶哲轩甩出调教GPT-4聊天记录,点击领取大佬的研究助理

量子位 | 公众号 QbitAI 鹅妹子嘤&#xff0c;天才数学家陶哲轩搞数学研究&#xff0c;已经离不开普通人手里的“数学菜鸡”GPT了&#xff01; 就在他最新解决的一个数学难题下面&#xff0c;陶哲轩明确指出自己“使用了GPT-4”&#xff0c;后者给他提出了一种可行的解决方法…

【FFmpeg实战】avformat_find_stream_info() 函数源码解析

转载自地址&#xff1a;https://cloud.tencent.com/developer/article/1873836 先来看一下 avformat_find_stream_info() 的头文件里的注释对该函数的介绍&#xff0c;本文我们基于 FFmpeg n4.2 版本的源码分析。 /*** Read packets of a media file to get stream informatio…

Apikit 自学日记:创建 API 文档

Apikit 中一共有5种创建API文档的方式&#xff1a; 新建API文档 导入API文档&#xff0c;详情可查看《导入、导出API文档》 从模板添加API文档&#xff0c;详情可查看《API文档模板》 自动生成API文档&#xff0c;详情可查看《自动生成API文档》 IDEA插件注释同步API文档 …

linux 在线安装 Redis

博主介绍&#xff1a; ✌博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家✌ Java知识图谱点击链接&#xff1a;体系化学习Java&#xff08;Java面试专题&#xff09; &#x1f495;&#x1f495; 感兴趣的同学可以收…

生成式AI掀起产业智能化新浪潮|爱分析报告

报告摘要 大模型支撑的生成式AI&#xff0c;让人类社会有望步入通用人工智能时代&#xff0c;拥有广阔的应用前景&#xff0c;有望赋能千行百业。当前生成式AI的落地整体处于初级阶段&#xff0c;不同模态的落地时间表差异明显&#xff0c;企业需求主要集中在数字化程度高、容…

地平线旭日x3派部署yolov8

地平线旭日x3派部署yolov8 总体流程1.导出onnx模型导出YOLOV8_onnxruntime.py验证onnxutils.py 2.在开发机转为bin模型2.1准备数据图片2.2转换必备的yaml文件2.3开始转换 3.开发机验证**quantized_model.onnx4.板子运行bin模型 资源链接 总体流程 1.导出onnx模型 导出 使用y…

03 | 事务隔离:为什么你改了我还看不见?

以下出自 《MySQL 实战 45 讲》 03 | 事务隔离&#xff1a;为什么你改了我还看不见&#xff1f; 隔离性与隔离级别 当数据库上有多个事务同时执行的时候&#xff0c;就可能出现脏读&#xff08;dirty read&#xff09;、不可重复读&#xff08;non-repeatable read&#xff0…

搜索功能全流程解析

在产品中一般会分布着大大小小的搜索&#xff0c;以便提升用户的信息获取效率和信息消费的能力。本文作者全流程角度&#xff0c;对搜索功能进行了讲解&#xff0c;并从搜索流程中寻找提升体验的触点&#xff0c;一起来看一下吧。 在产品中因多功能诉求和业务复杂性等因素&…

《Pytorch深度学习和图神经网络(卷 1)》学习笔记——第三章

学习基于如下书籍&#xff0c;仅供自己学习&#xff0c;用来记录回顾&#xff0c;非教程。 <PyTorch深度学习和图神经网络&#xff08;卷 1&#xff09;——基础知识>一书配套代码&#xff1a; https://github.com/aianaconda/pytorch-GNN-1st 百度网盘链接&#xff1a;…

vite优化

1.利用 rollup-plugin-analyzer 插件进行进行代码体积分析&#xff0c;从而优化你的代码。 根据项目体积分析&#xff0c;进行接下来的优化&#xff1a; &#xff08;一&#xff09;使用unplugin-vue-components插件按需加载antd vue 组件&#xff1a; 使用步骤 1、安装插件…

6.18 、Java初级:锁

1 同步锁 1.1 前言 经过前面多线程编程的学习,我们遇到了线程安全的相关问题,比如多线程售票情景下的超卖/重卖现象. 上节笔记点这里-进程与线程笔记 我们如何判断程序有没有可能出现线程安全问题,主要有以下三个条件: 在多线程程序中 有共享数据 多条语句操作共享数据 多…

GPT-4 的创造力全方位持平或碾压人类 | 一项最新研究发现

文章目录 一、前言二、主要内容三、总结 &#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一、前言 最近&#xff0c;一项有关 GPT-4 的创造力思维测试火了。来自蒙大拿大学和 UM Western 大学的研究团队发现&#xff0c;GPT-4 在 Torrance 创造性思维…

Sharding-JDBC之RangeShardingAlgorithm(范围分片算法)

目录 一、简介二、maven依赖三、数据库3.1、创建数据库3.2、创建表 四、配置&#xff08;二选一&#xff09;4.1、properties配置4.2、yml配置 五、范围分片算法六、实现6.1、实体层6.2、持久层6.3、服务层6.4、测试类6.4.1、保存订单数据6.4.2、根据时间范围查询订单 一、简介…