【数据结构与算法】如何对快速排序进行细节优化以及实现非递归版本的快速排序?

在这里插入图片描述

君兮_的个人主页

即使走的再远,也勿忘启程时的初心

C/C++ 游戏开发

Hello,米娜桑们,这里是君兮_,国庆长假结束了,无论是工作还是学习都该回到正轨上来了,从今天开始恢复正常的更新频率,今天为大家带来的内容是快速排序的两大优化和非递归实现

  • 好了废话不多说,开始我们今天的学习吧!!

    快排优化与非递归实现

    • 快速排序优化
      • 三数去中优化
      • 对递归次数的优化
    • 非递归的快速排序
    • 总结

快速排序优化

  • 有关快速排序的基本内容可以去看看这篇博客,讲的已经非常详细了
    【算法速查】万字图解带你快速入门八大排序(下)
  • 我们在这里就以hoare版本的快速排序来讲讲还可以优化的地方以及为什么
  • hoare版本的快速排序代码如下:
Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
int getMid(int* a, int left, int right)
{assert(a);int mid = (left + right) / 2;if (a[left] > a[mid]){if (a[mid] > a[right])return mid;else if(a[right]>a[left]){return left;}else{return right;}}else{if (a[mid] < a[right])return mid;else if (a[left] > a[right]){return left;}else{return right;}}
}
int PartSort1(int* a, int left, int right)
{int mid = getMid(a, left, right);//三数取中//把取好的key放到left中Swap(&a[left], &a[mid]);int key = left;while (left<right){//右边先走while (left < right && a[right] >= a[key]){right--;}//左边走while (left<right&&a[left]<=a[key]){left++;}//交换Swap(&a[left], &a[right]);}//交换停下的位置的值把key换到此时左右相遇的位置Swap(&a[key], &a[left]);//此时key的左右都有序,由于right,left都指处于key的位置返回任意即可return right;
}
void QuickSort(int* a, int left,int right)
{//只剩下一个值了,说明已经有序,不需要再排,递归结束if (left >= right)return;int key = PartSort1(a,left,right);//key已经满足左右都有序了不需要再排//排key的左边QuickSort(a, left, key-1);//排key的右边QuickSort(a, key+1, right);}

三数去中优化

  • 我们知道,快速排序是先取一个key值然后让左右两边有序来进行排序的,因此key值的取值对我们快速排序的速度是有比较大的影响的,举个最坏的例子,假设每次我们取到的key值都是此次所需排序数据中最小的,如下图所示
    在这里插入图片描述

  • 此时的时间复杂度就是O(N^2)了,因此,我们需要对快速排序进行优化,尽量减少出现图示的这种情况,就有了以下的代码

int getMid(int* a, int left, int right)
{assert(a);int mid = (left + right) / 2;if (a[left] > a[mid]){if (a[mid] > a[right])return mid;else if(a[right]>a[left]){return left;}else{return right;}}else{if (a[mid] < a[right])return mid;else if (a[left] > a[right]){return left;}else{return right;}}
}
  • 简单的来说,上述这段代码表示的是这样的意思
    取最左,最右,中间三个数,分别对三个数进行比较,最终取得的值就是处于三个值中中间的这个值。
  • 通过上述这个优化,此时所需排序的数据中总要比我们取得的key值小以及比我们取得的key值大的值存在,就能较大的提供我们的快排效率啦!

对递归次数的优化

  • 我们在使用递归版本的快速排序时,当区间中的数比较少时,仍然使用递归的方式进行是会消耗非常多不必要消耗的内存的,还是举个例子:假设此时区间中还有10个数需要排
    在这里插入图片描述
  • 我们递归返回的条件是left>=right,递归是栈中开辟空间进行的,当递归的层数过深,栈的大小又不是很大,就容易造成“爆栈”,如上图所示,为了排序这十个数,我们又递归了这么多层,是非常不明智的选择,因此,我们在数据较少的情况出现时,可以使用插入排序等方法进行排序,减少不必要的空间浪费,也能提供我们快排的速度
void QuickSort1(int* a, int begin, int end)
{if (begin >= end)return;// 小区间优化,小区间不再递归分割排序,降低递归次数if ((end - begin + 1) > 10){int keyi = PartSort1(a, begin, end);// [begin, keyi-1] keyi [keyi+1, end]QuickSort1(a, begin, keyi - 1);QuickSort1(a, keyi + 1, end);}else{InsertSort(a + begin, end - begin + 1);}
}
  • 好了,讲完了上述对递归版本的快排优化,接下来我们讲讲快速排序的非递归版本

非递归的快速排序

  • 我们上面讲了,递归是在栈空间中进行的,栈空间又比较小,当递归层数比较深时就会造成“爆栈”,因此对于快速排序这种我们常用的排序算法来说,掌握其非递归版本也是非常重要的
  • 想要了解非递归,我们就必须从递归开始下手,我们再来看看递归的这段代码
void QuickSort1(int* a, int begin, int end)
{if (begin >= end)return;// 小区间优化,小区间不再递归分割排序,降低递归次数if ((end - begin + 1) > 10){int keyi = PartSort1(a, begin, end);// [begin, keyi-1] keyi [keyi+1, end]QuickSort1(a, begin, keyi - 1);QuickSort1(a, keyi + 1, end);}else{InsertSort(a + begin, end - begin + 1);}
}
  • 如果你学过数据结构的话,会发现我们递归与栈是非常类似的,栈是后进先出,最后再处理最先放入的,而递归也是先往深处走,再往回返,因此,我们在实现非递归的快速排序时,选用栈这种数据结构来帮助我们进行。
void QuickSortNonR(int* a, int left,int right)
{Stack st;StackInit(&st);//初始化栈StackPush(&st, left);//入栈StackPush(&st, right);while (!StackEmpty(&st))//判断栈是否为空{int right = StackTop(&st);//后进先出,取栈顶元素StackPop(&st);//此时的栈顶元素出栈int left = StackTop(&st);//此时的栈顶为leftStackPop(&st);int key = PartSort1(a, left, right);//选key值if (key + 1 < right)//此时key+1小于right 把key+1作为下一次排序的左 right作为右入栈{StackPush(&st, key + 1);StackPush(&st, right);}if (left < key - 1)//key-1大于left key-1就为下一次循环的右,left为左{StackPush(&st, left);StackPush(&st, key - 1);}}//当栈中没有元素了,说明此时的左大于等于右,此时已经没有数据未进行排序了StackDestroy(&st);//销毁栈
}
  • 和递归大致是一样的,只不过我们是用栈的方式来模拟递归朝深度进行,如果你能理解递归实现的快速排序,相信非递归实现的快速排序对你来说也非常好理解
  • 唯一需要注意的是入栈和出栈的顺序,当你开始先入右再入左的话,由于后进先出的原因,先出的是左其中是右,这点在取栈顶元素作为排序的左右区间时一定要注意避免取错。

总结

  • 好啦,我们总算把八大排序算法都讲完了,算法这一块光靠看代码不是那么容易理解的,因此我花了大量的时间画图分析,希望能对你有所帮助
  • 当然,这篇文章创作的初衷是希望帮助初学者对排序算法有一个大致的了解,对已经学过的人起到在需要使用的时候快速回忆的效果,因此可能还有一部分细节不全,之后我会挑出重点单独出博客讲解
  • 有任何的问题和对文章内容的疑惑欢迎在评论区中提出,当然也可以私信我,我会在第一时间回复的!!

新人博主创作不易,如果感觉文章内容对你有所帮助的话不妨三连一下再走呗。你们的支持就是我更新的动力!!!

**(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)**

在这里插入图片描述

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

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

相关文章

【Python_PySide2学习笔记(十八)】勾选按钮QCheckBox类的基本用法

勾选按钮QCheckBox类的基本用法 前言正文1、创建勾选按钮2、勾选按钮获取选中状态3、创建按钮组4、按钮组添加勾选按钮5、按钮组设置单选6、按钮组信号&#xff1a;选中状态改变7、按钮组获取所有勾选按钮7.1、获取勾选按钮对象7.2、获取勾选按钮文本7.3、获取勾选按钮ID7.4、按…

win11安装IIS步骤-已验证23.10.10

IIS服务使用 步骤一&#xff1a;打开控制面板 通过 控制面板— 程序— 启用或关闭Windows功能 — 选择Internet Information Services默认安装IIS&#xff0c;如下图步骤所示 步骤二&#xff1a;打开IIS服务 建议根据下图勾选&#xff0c;建议全选安装&#xff0c;以便后续发…

聊聊2023年怎么入局小游戏赛道?

一、微信小游戏赛道发展史 第一阶段&#xff1a;轻度试水期&#xff0c;2017&#xff5e;2019年 微信小游戏于2017年底上线&#xff0c;初期以轻度休闲为主&#xff0c;例如棋牌、合成消除以及益智相关游戏类型。一是开发门槛不高&#xff0c;产品可以快速上线; 二是大部分厂…

虹科方案 | 汽车CAN/LIN总线数据采集解决方案

全文导读&#xff1a;现代汽车配备了复杂的电子系统&#xff0c;CAN和LIN总线已成为这些系统之间实现通信的标准协议&#xff0c;为了开发和优化汽车的电子功能&#xff0c;汽车制造商和工程师需要可靠的数据采集解决方案。基于PCAN和PLIN设备&#xff0c;虹科提供了一种高效、…

mac(M1)卸载miniconda3

参考https://stackoverflow.com/questions/29596350/how-to-uninstall-mini-conda-python step1 因为我目前只有一个base环境&#xff0c;所以直接在这个环境中安装 anaconda-clean即可 conda install anaconda-clean然后继续输入 anaconda-clean如果不加–yes&#xff0c;那…

[nltk_data] Error loading stopwords: <urlopen error [WinError 10054]

报错提示&#xff1a; >>> import nltk >>> nltk.download(stopwords) 按照提示执行后 [nltk_data] Error loading stopwords: <urlopen error [WinError 10054] 找到路径C:\\Users\\EDY\\nltk_data&#xff0c;如果没有nltk_data文件夹&#xff0c;在…

《安富莱嵌入式周报》第324期:单对以太网技术实战,IROS2023迪士尼逼真机器人展示,数百万模具CAD文件下载,闭环步进电机驱动器,CANopen全解析

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 更新一期视频教程&#xff1a; 第8期ThreadX视频教程&#xff1a;应用实战&#xff0c;将裸机工程移植到RTOS的任务划分…

黑马点评-05缓存穿透问题及其解决方案,缓存空字符串或使用布隆过滤器

缓存穿透问题(缓存空) 缓存穿透的解决方案 缓存穿透(数据穿透缓存直击数据库): 缓存穿透是指客户端请求访问缓存中和数据库中都不存在的数据,此时缓存永远不会生效并且用户的请求都会打到数据库 数据库能够承载的并发不如Redis这么高&#xff0c;如果大量的请求同时访问这种…

基于YOLOv5、YOLOv8的火灾检测(超实用项目)

目录 1.简介 2.YOLO算法 3.基于YOLOv5、YOLOv8的火灾检测 视频已上传b站 YOLOv5/YOLOv8的火灾检测&#xff08;超实用项目&#xff09;_哔哩哔哩_bilibili 本文为系列专栏&#xff0c;包括各种YOLO检测算法项目、追踪算法项目、双目视觉、深度结构光相机测距测速三维测量项…

[鹏城杯 2022]简单的php - 无数字字母RCE(取反)【*】

[鹏城杯 2022]简单的php 一、解题流程二、思考总结 题目代码&#xff1a; <?php show_source(__FILE__);$code $_GET[code];if(strlen($code) > 80 or preg_match(/[A-Za-z0-9]|\|"||\ |,|\.|-|\||\/|\\|<|>|\$|\?|\^|&|\|/is,$code)){die( Hello);}e…

epoll 定时器

参考&#xff1a; Linux下使用epoll监听定时器-CSDN博客 但是这个用的是gettimeofday。 本人使用的是 #include <stdlib.h> #include<stdio.h> #include <sys/timerfd.h> #include <sys/epoll.h> #include <unistd.h> #include <sys/time.…

hbba网站下载国家标准/行业标准的方法

hbba网站是不提供下载按钮并且不支持右键的&#xff0c;那么如何下载呢&#xff1f; 1、首先看一下pdf有多少页&#xff0c;一般标准介绍上有写。 2、使用edge或google浏览器打开pdf预览页面&#xff0c;打开开发者模式&#xff0c;用小箭头指向第一页&#xff0c;这样就获取到…

短视频矩阵源码开发部署---技术解析

一、短视频SEO源码搜索技术需要考虑以下几点&#xff1a; 1. 关键词优化&#xff1a;通过研究目标受众的搜索习惯&#xff0c;选择合适的关键词&#xff0c;并在标题、描述、标签等元素中进行优化&#xff0c;提高视频的搜索排名。 2. 内容质量&#xff1a;优质、有吸引力的内…

Qt QGridLayout和QFormLayout案例分析

QGridLayout和QFormLayout是Qt中常用的布局管理器&#xff0c;可以用于在应用程序中设置控件的位置和大小。 QGridLayout网格布局(栅格布局) QGridLayout是一个网格布局管理器&#xff0c;可以将控件放置在一个二维网格中。在QGridLayout中&#xff0c;控件可以跨越多个行和列…

在原生html中使用less

引入less <link rel"stylesheet/less" href"./lessDemo.less" /><script src"./js/less.min.js"></script> less.min.js文件下载地址:https://github.com/less/less.js 注意&#xff1a;less文件在前&#xff0c;js文件在后…

LabVIEW玩转魔方

LabVIEW玩转魔方 使用LabVIEW创建一个3D魔方&#xff0c;并找出解谜题的秘密&#xff0c;给朋友留下深刻深刻的印象。游戏中内置的机制使每张脸都能独立转动&#xff0c;从而混合颜色。要解决难题&#xff0c;每个面必须是相同的纯色 魔方的奥秘在于它的简单性和不可解性。这是…

阶段六-Day02-Maven

一、学习Maven 使用Maven创建Web项目&#xff0c;并部署到服务器。 二、Maven介绍及加载原理 1. 介绍 Maven是使用Java语言编写的基于项目对象模型&#xff08;POM&#xff09;的项目管理工具。开发者可以通过一小段描述信息来管理项目的构建、报告和文档。 使用Maven可以…

【已解决】Python打包文件执行报错:ModuleNotFoundError: No module named ‘pymssql‘

【已解决】Python打包文件执行报错&#xff1a;ModuleNotFoundError: No module named pymssql 1、问题2、原因3、解决 1、问题 今天打包一个 tkinter pymssql 的项目的时候&#xff0c;打包过程很顺利&#xff0c;但是打开软件的时候&#xff0c;报错 ModuleNotFoundError: …

unity操作_刚体 c#

刚体Rigidbody 首先在场景中创建一个Plane 位置重置一下 再创建一个Cube 充值 y0.5 我们可以看出创建的Cube 和 Plane都自带碰撞器 Plane用的是网格碰撞器 我们可以通过网格世界看到不同的网格碰撞器 发生碰撞&#xff08;条件&#xff09;&#xff1a; 两个物体都有碰撞器 …

CentOS Integration SIG 正式成立

导读CentOS 董事会已批准成立 CentOS Integration Special Interest Group (SIG)。该小组旨在帮助那些在 Red Hat Enterprise Linux (RHEL) 或特别是其上游 CentOS Stream 上构建产品和服务的人员&#xff0c;验证其能否在未来版本中继续运行。 红帽 RHEL CI 工程师 Aleksandr…