快排三种递归及其优化,非递归和三路划分

个人主页:Lei宝啊 

愿所有美好如期而遇


目录

快排简介:

快排的三种递归实现:

Hoare:

挖坑:

双指针:

小区间优化:

三数取中优化:

快排非递归实现:

快排的三路划分实现:


快排简介:

快速排序,参见: qsort详解及其模拟实现


快排的三种递归实现:

Hoare:

此法乃Hoare大佬所创,我等一个不注意便就掉入陷阱,大坑于代码处自有注释,诸君慢品:

//Hoare版本  right传数组下标
void QuickSort_Binary(int* arr, int left, int right)
{if (left >= right)return;//选定一个数keyi,最好是不大也不小,上面加个三数取中int keyi = left;//快排开始的区间,都是闭区间int begin = left;int end = right;while (begin < end){//一坑在=,若无此,循环不止//二坑在begin < end,若无此,有越界之忧,end或减减不止//三坑在要从右先行,以此保证begin与end相遇时//					二者所指处值小于keyi所指值while (begin < end && arr[end] >= arr[keyi]){end--;}while (begin < end && arr[begin] <= arr[keyi]){begin++;}Swap(&arr[end], &arr[begin]);}Swap(&arr[begin], &arr[keyi]);QuickSort_Binary(arr, left, begin - 1);QuickSort_Binary(arr, begin + 1, right);}

挖坑:

此法则无关左右矣

//挖坑法  传数组下标
void QuickSort_Binary(int* arr, int left, int right)
{if (left >= right)return;int hole = left;int temp = arr[left];//定义这两变量主要是为了区分后面递归时的区间int begin = left;int end = right;while(begin < end){while(begin < end && arr[end] >= temp){end--;}//交换爽啊,赋值的话循环结束后,还要把temp的值赋给hole位置Swap(&arr[hole], &arr[end]);hole = end;while (begin < end && arr[begin] <= temp){begin++;}Swap(&arr[hole], &arr[begin]);hole = begin;}QuickSort_Binary(arr, left, begin - 1);QuickSort_Binary(arr, begin + 1, right);
}

双指针:

//双指针法 传数组下标
void QuickSort_Binary(int* arr, int left, int right)
{if (left >= right)return;int temp = arr[left];int prev = left;int cur = left;while (cur <= right){while (arr[cur] < temp  && ++prev != cur){Swap(&arr[prev], &arr[cur]);}cur++;}//想法大致都是keyi位置的值不动,从下一个位置开始,最后交换keyi位置和停止位置//停止位置的值一定比keyi位置的值要小Swap(&arr[left], &arr[prev]);QuickSort_Binary(arr, left, prev - 1);QuickSort_Binary(arr, prev + 1, right);}

小区间优化:

我们可以发现的是,递归像一座金字塔,越是到下面,递归次数越多,而我们通过计算得知,一颗满二叉树节点数为2^n-1,最后一层节点数为2^(n-1),也就是说,最后三层节点数占到总数的近87.5%,

也就是说,剩余的节点小于15就不要递归了,可以使用插入排序,这个还是比较好的,插入排序参见:插入排序与希尔排序

以Hoare大佬的排序为例:

//Hoare版本  right传数组下标
void QuickSort_Binary(int* arr, int left, int right)
{if (left >= right)return;if(right-left+1 >= 15){//选定一个数keyi,最好是不大也不小,上面加个三数取中int keyi = left;//快排开始的区间,都是闭区间int begin = left;int end = right;while (begin < end){//一坑在=,若无此,循环不止//二坑在begin < end,若无此,有越界之忧,end或减减不止//三坑在要从右先行,以此保证begin与end相遇时//					二者所指处值小于keyi所指值while (begin < end && arr[end] >= arr[keyi]){end--;}while (begin < end && arr[begin] <= arr[keyi]){begin++;}Swap(&arr[end], &arr[begin]);}Swap(&arr[begin], &arr[keyi]);QuickSort_Binary(arr, left, begin - 1);QuickSort_Binary(arr, begin + 1, right);}else{InsertSort(arr,right-left+1);}
}

三数取中优化:

再一个,如果说一个序列已然有序,我们再使用快排就很难受,此时时间复杂度直达O(N^2),所以如果我们加上三数取中,就不会出现最坏情况,但是力扣老贼针对快排,快排的三数取中我们仍要修改,改为随机数取中。

int GetMidNum(int* a, int left, int right)
{int mid = left + (rand() % (right - left));if (a[left] > a[mid]){if (a[mid] > a[right]){return mid;}else if (a[left] > a[right]){return right;}else{return left;}}else{if (a[left] > a[right]){return left;}else if (a[mid] > a[right]){return right;}else{return mid;}}
}

这样我们返回这个中间值坐标后,这样做:

int mid = GetMidNum(arr, left, right);
Swap(&arr[left], &arr[mid]);

 

快排非递归实现:

快排掌握递归并不够,虽然说他的空间复杂度不高,尽管我们有了上述优化,但是仍然难以保证他不会爆栈,所以掌握非递归还是很有必要的。

快速排序的非递归类似于二叉树的前序遍历,我们在这里需要借助于栈,当然队列也可,但是这样的话就类似于二叉树的层序遍历了。

栈和队列参考:栈和队列的实现

二叉树的前序遍历参考:二叉树的几个递归问题

二叉树的层序参考:二叉树的层序遍历及判断完全二叉树

void QuickSortNonR(int* a, int left, int right)
{Stack stack;Init(&stack);Push(&stack, right - 1);Push(&stack, left);while (!Empty(&stack)){int begin = GetTop(&stack);Pop(&stack);int end = GetTop(&stack);Pop(&stack);int mid = SortWay_two(a, begin, end);if (mid + 1 < end){Push(&stack, end);Push(&stack, mid + 1);			}if (begin < mid){Push(&stack, mid);Push(&stack, begin);		}}
}

这里注意栈的特性是先进后出。 

快排的三路划分实现:

在力扣的针对下,有大佬推出了这个算法,使得快排终于能够通过。

我们的快排是大等于或小等于,而三路划分是小的在左,相等于keyi的在中间,大的在右,使得我们直接递归相等数的左边和右边就可。

//快排三路划分
void QuickSort_ThrDiv(int *arr,int left,int right)
{if (left >= right)return;srand((unsigned int)time(NULL));int mid = GetMidNum(arr, left, right);Swap(&arr[left], &arr[mid]);int begin = left;int end = right;int keyi = arr[left];int cur = left + 1;	while (cur <= right){if (arr[cur] < keyi){Swap(&arr[cur], &arr[left]);left++;cur++;}else if (arr[cur] > keyi){Swap(&arr[cur], &arr[right]);right--;}else{cur++;}}QuickSort_ThrDiv(arr, begin, left - 1);QuickSort_ThrDiv(arr, right + 1, end);}

今晚的风,吹得好浪漫~

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

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

相关文章

基于PSO算法的功率角摆动曲线优化研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【设计模式】五、原型模式

文章目录 概述示例传统的方式的优缺点原型模式原理结构图-uml 类图 原型模式解决克隆羊问题的应用实例Sheep类实现clone()运行原型模式在 Spring 框架中源码分析 深入讨论-浅拷贝和深拷贝浅拷贝的介绍 小结 概述 示例 克隆羊问题 现在有一只羊 tom&#xff0c;姓名为: tom, 年…

V4L2 驱动架构介绍

V4L2 简介 Video for Linux two(Video4Linux2)简称 V4L2&#xff0c;是 V4L 的改进版。V4L2 是 linux操作系统下用于视频和音频数据采集设备的驱动框架&#xff0c;为驱动和应用程序提供了一套统一的接口规范。 在 Linux 下&#xff0c;所有外设都被看成一种特殊的文件&#xf…

freertos简介与移植

freertos是一个可裁剪的小型rtos系统&#xff0c;特点&#xff1a; 支持抢占式&#xff0c;合作式和时间片调度saferos衍生自freertos&#xff0c;更完整提供了一个用于低功耗的tickless模式系统的组件在创建时可以选择动态或者静态的ram&#xff0c;例如任务&#xff0c;消息…

MARS: An Instance-aware, Modular and Realistic Simulator for Autonomous Driving

● MARS: An Instance-aware, Modular and Realistic Simulator for Autonomous Driving&#xff08;基于神经辐射场的自动驾驶仿真器&#xff09; ● https://github.com/OPEN-AIR-SUN/mars ● https://arxiv.org/pdf/2307.15058.pdf ● https://mp.weixin.qq.com/s/6Ion_DZGJ…

【新版】系统架构设计师 - 层次式架构设计理论与实践

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 层次式架构设计理论与实践考点摘要层次式体系结构概述表现层框架设计MVC模式MVP模式MVVM模式使用XML设计表现层表现层中UIP设计思想 中间层架构设计业务逻辑层工作流设计业务逻辑层设计 数据访问层…

代码随想录算法训练营第五十一天 |309.最佳买卖股票时机含冷冻期、714.买卖股票的最佳时机含手续费、总结

一、309.最佳买卖股票时机含冷冻期 题目链接/文章讲解&#xff1a;代码随想录 视频讲解&#xff1a;动态规划来决定最佳时机&#xff0c;这次有冷冻期&#xff01;| LeetCode&#xff1a;309.买卖股票的最佳时机含冷冻期_哔哩哔哩_bilibili 思考&#xff1a; 1.确定dp数组&…

MySQL SQL性能分析(SQL优化 一)

在开发和维护数据库应用程序时&#xff0c;优化SQL查询的性能是至关重要的。MySQL提供了一些强大的工具和技术&#xff0c;帮助我们进行SQL性能分析&#xff0c;找出潜在的瓶颈并进行相应的优化。 查看SQL的执行频率 show [ session| global ] status 命令查看服务器状态信息…

Android Live Edit 给 Android开发者带来的福音

Android Live Edit 是一个允许开发者实时更新模拟器和物理设备中的可组合内容的功能。 微信公众号【biglead】的每日提醒 随时随记 每日积累 此功能最大限度地减少了编写和构建应用程序之间的上下文切换&#xff0c;让开发者专注于编写代码更长时间而不会中断。 在AndroidStu…

【VIM】VIm初步使用

玩转Vim-从放弃到入门_哔哩哔哩_bilibili

传输层协议—UDP协议

传输层协议—UDP协议 文章目录 传输层协议—UDP协议传输层再谈端口号端口号范围划分pidofnetstat UDP协议端格式UDP报文UDP特点UDP缓冲区基于UDP的应用层协议 传输层 在学习HTTP/HTTPS等应用层协议时&#xff0c;为了方便理解&#xff0c;可以简单认为HTTP将请求和响应直接发送…

643. 子数组最大平均数I(滑动窗口)

目录 一、题目 二、代码 一、题目 643. 子数组最大平均数 I - 力扣&#xff08;LeetCode&#xff09; 二、代码 class Solution { public:double findMaxAverage(vector<int>& nums, int k) {double Average INT_MIN;double sum nums[0];int left 0, right 0…

oracle-使用PLSQL工具自行修改用户密码

1、使用PLSQL工具&#xff0c;输入用户名和原密码登录&#xff0c;如下图 2、登录后&#xff0c;在会话下拉菜单中找到”Change password..” 3、在跳出的窗口中配置新密码&#xff0c;修改完成后单击”确认”&#xff0c;后退出PLSQL 4、重新打开PLSQL&#xff0c;使用新密码登…

竞赛 机器学习股票大数据量化分析与预测系统 - python 竞赛

文章目录 0 前言1 课题背景2 实现效果UI界面设计web预测界面RSRS选股界面 3 软件架构4 工具介绍Flask框架MySQL数据库LSTM 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 机器学习股票大数据量化分析与预测系统 该项目较为新颖&am…

Vue3 引入使用 vant组件详解

目录 Vue3 引入使用 vant组件详解1.安装2.引入2.1 全局引入2.2 按需引入2.2.1 vite项目:vite.config.js2.2.2 Webpack项目&#xff1a;webpack.config.js2.2.3 配置在vue.config.js中 3.使用 Vue3 引入使用 vant组件详解 Vant是一个强大的移动端组件库&#xff0c;目前Vant 官…

Android stdio的Gradle菜单栏无内容问题的解决方法

右边Gradle菜单栏里没有Tasks选项内容的问题 正常情况↓ 如果这个问题如果无法解决的话&#xff0c;Gradle打包就只能通过控制台输入命令来解决&#xff0c;但这无疑是把简单问题复杂化了&#xff0c;我们来看看怎么解决这个问题吧。 这里有几个方法提供&#xff0c;可以自行选…

网络-Ajax

文章目录 前言一、Ajax优点&#xff1a;缺点&#xff1a; 二、使用步骤XNLHttpRequest对象完整代码 总结 前言 本文主要记录Ajax技术的简介&#xff0c;以及用法。 一、Ajax Ajax是一组用于在Web浏览器和Web服务器之间进行异步通信的Web开发技术。 它代表着Asynchronous Java…

RocketMQ Dashboard说解

RocketMQ Dashboard 是 RocketMQ 的管控利器&#xff0c;为用户提供客户端和应用程序的各种事件、性能的统计信息&#xff0c;支持以可视化工具代替 Topic 配置、Broker 管理等命令行操作。 介绍​ 功能概览​ 面板功能运维修改nameserver 地址; 选用 VIPChannel驾驶舱查看 …

MeterSphere v2.10.X-lts 双节点HA部署方案

一、MeterSphere高可用部署架构及服务器配置 1.1 服务器信息 序号应用名称操作系统要求配置要求描述1负载均衡器CentOS 7.X /RedHat 7.X2C,4G&#xff0c;200GB部署Nginx&#xff0c;实现负载路由。 部署NFS服务器。2MeterSphere应用节点1CentOS 7.X /RedHat 7.X8C,16GB,200G…

【算法】动态规划

文章目录 概述背包问题01背包问题&#xff1a;代码示例部分背包代码示例 完全背包代码示例 多重背包代码示例 总结提升 概述 动态规划&#xff08;Dynamic Programming&#xff09;是一种通过将问题划分为相互重叠的子问题来解决问题的算法思想。其核心思想是通过保存已经计算…