【数据结构】——排序篇(中)

前面我们已经了解了几大排序了,那么我们今天就来再了解一下剩下的快速排序法,这是一种非常经典的方法,时间复杂度是N*logN。

在这里插入图片描述

快速排序法:

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

我们的快速排序可以通过递归和非递归来实现,我们先来看看递归实现快排,我们的递归快排又分为三个版本,三种方法各有各的特点,我们接下来就来看看吧。

需要调用的函数代码:

void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}int GetMidi(int* a, int begin, int end)
{int midi = (begin + end) / 2;// begin midi end 三个数选中位数if (a[begin] < a[midi]){if (a[midi] < a[end])return midi;else if (a[begin] > a[end])return begin;elsereturn end;}else // a[begin] > a[midi]{if (a[midi] > a[end])return midi;else if (a[begin] < a[end])return begin;elsereturn end;}
}

hoare版本单趟排序:

// hoare
int PartSort1(int* a, int begin, int end)
{int midi = GetMidi(a, begin, end);Swap(&a[midi], &a[begin]);int left = begin, right = end;int keyi = begin;while (left < right){// 右边找小while (left < right && a[right] >= a[keyi]){--right;}// 左边找大while (left < right && a[left] <= a[keyi]){++left;}Swap(&a[left], &a[right]);}Swap(&a[left], &a[keyi]);return left;
}

这个版本的单趟排序理解起来很容易,但是我们的坑点比较多,所以难度对于我们而言还是有点挑战性,我们需要两个变量来实现,我们的left从左边数组的首元素开始走,找比keyi位置大的元素,keyi代表的就是我们数组首元素的下标,我们用right从最后一个元素开始走,找比keyi位置小的元素,找到了一个大的元素和一个小的元素就交换,但是我们的数组中可能有多个相等的元素,所以我们内嵌循环就得用<=。我们最后left和right相遇时结束,相遇位置的右边的元素大于等于keyi位置的元素,而相遇位置左边的元素都小于等于keyi位置的元素,我们最后就将left位置的元素和keyi位置的元素交换再返回left就完成了。

挖坑法单趟排序:

int PartSort2(int* a, int begin, int end)
{int midi = GetMidi(a, begin, end);Swap(&a[midi], &a[begin]);int key = a[begin];int hole = begin;while (begin < end){// 右边找小,填到左边的坑while (begin < end && a[end] >= key){--end;}a[hole] = a[end];hole = end;// 左边找大,填到右边的坑while (begin < end && a[begin] <= key){++begin;}a[hole] = a[begin];hole = begin;}a[hole] = key;return hole;
}

我们先将第一个数据存放在临时变量key中形成一个坑位,我们同样用到left和right,同样的用法,left从第一个元素往后走,right从最后一个元素往前走。我们的right先走,找到一个比hole下标小的元素就于hole下标的元素交换,交换之后left再走,找到一个比hole位置大的元素就与hole位置的元素交换,然后再left位置形成一个坑点。然后又是right走,交换后left走,反复进行,最后在相遇的时候就结束循环。因为我们的hole下标的值都是空的,所以在最后我们将key的数据给hole下标的坑位就可以了,最后再返回坑位的数据。具体的过程如下图所示:
在这里插入图片描述

前后指针版本单趟排序:

int PartSort3(int* a, int begin, int end)
{int midi = GetMidi(a, begin, end);Swap(&a[midi], &a[begin]);int keyi = begin;int prev = begin;int cur = prev + 1;while (cur <= end){if (a[cur] < a[keyi] && ++prev != cur)Swap(&a[prev], &a[cur]);++cur;}Swap(&a[prev], &a[keyi]);keyi = prev;return keyi;
}

我们的前后指针版本看起来比前两个版本更加的容易,因为我们的两个指针prev指向我们数组首元素的下标,而cur是我们首元素的下一个元素的下标,我们的cur先走,如果我们指向的元素比keyi位置的元素大的话我们就cur++向前走一位,如果比keyi位置的元素小的话我们就prev++向前走一位再与cur位置的交换,cur再继续往前走知道cur>end的时候就结束循环。最后我们再将prev位置的数据给keyi位置就完成了。
在这里插入图片描述

单趟优化版本:

void QuickSort(int* a, int begin, int end)
{if (begin >= end)return;if (end - begin + 1 <= 10){InsertSort(a + begin, end - begin + 1);}else{int midi = GetMidi(a, begin, end);Swap(&a[midi], &a[begin]);int left = begin, right = end;int keyi = begin;while (left < right){// 右边找小while (left < right && a[right] >= a[keyi]){--right;}// 左边找大while (left < right && a[left] <= a[keyi]){++left;}Swap(&a[left], &a[right]);}Swap(&a[left], &a[keyi]);keyi = left;// [begin, keyi-1] keyi [keyi+1, end]QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);}
}

单趟优化版本就是我们的区间数据不大时,我们用直接插入排序法,而数据太大的时候我们就用hoare版本的单趟排序。

函数递归实现快排:

void QuickSort(int* a, int begin, int end)
{if (begin >= end)return;int keyi = PartSort2(a, begin, end);QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);
}

实现我们只需要调用一个版本的单趟排序在进行递归就可以了。我们代码中是用的挖坑法的单趟排序,我们就直接调用PartSort2就可以了。

递归的我们已经了解完了,那么我们就来看看非递归的怎么实现吧:

void QuickSortNonR(int* a, int begin, int end)
{ST s;STInit(&s);STPush(&s, end);STPush(&s, begin);while (!STEmpty(&s)){int left = STTop(&s);STPop(&s);int right = STTop(&s);STPop(&s);int keyi = PartSort3(a, left, right);// [left, keyi-1] keyi [keyi+1, right]if (left < keyi - 1){STPush(&s, keyi - 1);STPush(&s, left);}if (keyi + 1 < right){STPush(&s, right);STPush(&s, keyi + 1);}}STDestroy(&s);
}

非递归版本的快速排序。我们需要起始位置 begin 和结束位置 end。首先,函数创建一个栈 st,用于存储待处理的子数组的起始和结束位置。将 end 和 begin 分别压入栈中,表示对整个数组进行排序。进入循环,只要栈不为空,从栈中弹出两个元素,分别赋值给 left 和 right,表示当前要处理的子数组的起始和结束位置。调用 PartSort3 函数对子数组进行分区,得到基准元素的位置 keyi。根据分区的结果,将子数组划分为 [left, keyi-1]、[keyi]、[keyi+1, right] 三个部分。如果 keyi + 1 < right,说明右侧子数组仍然有元素需要排序,将右侧子数组的起始位置 keyi + 1 和结束位置 right 压入栈中。如果 left < keyi - 1,说明左侧子数组仍然有元素需要排序,将左侧子数组的起始位置 left 和结束位置 keyi - 1 压入栈中。循环继续进行,直到栈为空,表示所有子数组都被处理完毕。最后,销毁栈 st,就完成了非递归版本的快速排序。
在这里插入图片描述

如果对大家有所帮助的话就支持一下吧!

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

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

相关文章

C++ queue 和priority_queue

目录 1.什么是queue 2.模拟实现 3.仿函数 模板参数Compare 仿函数 4.什么是priority_queue 模拟实现 1.什么是queue 1.队列是一种容器适配器&#xff0c;专门用于在FIFO上下文(先进先出)中操作&#xff0c;其中从容器一端插入元素&#xff0c;另一端提取元素。 2.队列作为…

Cglib动态代理从入门到掌握

Cglib 动态代理 本文的写作目的是为了探究 Spring 框架中在使用Transactional标注的方法中使用 this 进行自调用时事务失效的原因&#xff0c;各种视频教程中只是简单指出 this 指向的不是代理类对象&#xff0c;而是目标类对象&#xff0c;但是并没有解释为什么 this 不是代理…

麒麟系统使用桌面共享远程桌面

客户端安装vinager 服务端 安装 vnc4server xrdp tightvncserver vino 安装完成后 需要重启 在用户的家目录下新建 .xsession 写入xfce4-session防止闪退 雪花屏 开启xrdp服务 远程链接 Vnc只能链接系统登录的用户 Rdp可以链接所有普通用户

【C语言】结构体内存对齐

目录 引入结构体 结构的声明 创建和初始化 内部元素的使用&#xff1b; 特殊声明&#xff1a; 结构体在内存中的对齐 练习&#xff1a; 引入结构体 C语言有各种数据类型&#xff0c;我们已经对一些数据类型很熟悉&#xff1a; 整型&#xff08;int&#xff09;- 存储整…

京东商品详情数据在数据分析行业中的重要性

京东商品详情数据在数据分析行业中具有重要作用。这些数据提供了丰富的信息&#xff0c;可以帮助企业了解市场趋势、消费者需求、产品表现以及运营策略等多个方面。 首先&#xff0c;京东商品详情数据可以为企业提供市场趋势分析的依据。通过观察商品的销售量、销售额、价格等…

c语言:理解和避免野指针

野指针的定义&#xff1a; 野指针是指一个指针变量存储了一个无效的地址&#xff0c;通常是一个未初始化的指针或者指向已经被释放的内存地址。当程序尝试使用野指针时&#xff0c;可能会导致程序崩溃、内存泄漏或者其他不可预测的行为。因此&#xff0c;在编程中需要特别注意…

Pandas中DataFrame对象的创建与常用属性方法(第2讲)

Pandas中DataFrame对象的创建与常用属性方法(第2讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔…

智能优化算法应用:基于孔雀算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于孔雀算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于孔雀算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.孔雀算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

[足式机器人]Part2 Dr. CAN学习笔记-数学基础Ch0-2 特征值与特征向量

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-数学基础Ch0-2 特征值与特征向量 1. 定义1.1 线性变换1.2 求解特征值&#xff0c;特征向量1.3 应用&#xff1a;对角化矩阵——解耦Decouple 2. Summary 1. 定义 A v ⃗ λ v ⃗ A\vec{v}\lambd…

【网络奇缘】- 计算机网络|深入学习物理层|网络安全

​ &#x1f308;个人主页: Aileen_0v0&#x1f525;系列专栏: 一见倾心,再见倾城 --- 计算机网络~&#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 回顾链接&#xff1a;http://t.csdnimg.cn/ZvPOS 这篇文章是关于深入学习原理参考模型-物理层的相关知识点&…

Linux权限命令详解

Linux权限命令详解 文章目录 Linux权限命令详解一、什么是权限&#xff1f;二、权限的本质三、Linux中的用户四、linux中文件的权限4.1 文件访问者的分类&#xff08;人&#xff09;4.2 文件类型和访问权限&#xff08;事物属性&#xff09; 五、快速掌握修改权限的做法【第一种…

实战1-python爬取安全客新闻

一般步骤&#xff1a;确定网站--搭建关系--发送请求--接受响应--筛选数据--保存本地 1.拿到网站首先要查看我们要爬取的目录是否被允许 一般网站都会议/robots.txt目录&#xff0c;告诉你哪些地址可爬&#xff0c;哪些不可爬&#xff0c;以安全客为例子 2. 首先测试在不登录的…

Docker Network(网络)——8

目录&#xff1a; Docker 为什么需要网络管理Docker 网络架构简介 CNMLibnetwork驱动常见网络类型 bridge 网络host 网络container 网络none 网络overlay 网络docker 网络管理命令 docker network createdocker network inspectdocker network connectdocker network disconne…

class072 最长递增子序列问题与扩展【算法】

class072 最长递增子序列问题与扩展【算法】 code1 300. 最长递增子序列 // 最长递增子序列和最长不下降子序列 // 给定一个整数数组nums // 找到其中最长严格递增子序列长度、最长不下降子序列长度 // 测试链接 : https://leetcode.cn/problems/longest-increasing-subsequen…

你知道MySQL中 group by 怎么优化吗

更好的阅读体验&#xff0c;请点击 YinKai s Blog。 ​ 在 MySQL 中 group by 用于按照一个或多个列对结果集进行分组。在讨论 group by 怎么优化之前&#xff0c;我们先来看看 group by 的执行流程&#xff0c;这样我们才能对症下药。 group by 执行流程 ​ 我们先用下面的 …

Ubuntu 18.04使用Qemu和GDB搭建运行内核的环境

安装busybox 参考博客&#xff1a; 使用GDBQEMU调试Linux内核环境搭建 一文教你如何使用GDBQemu调试Linux内核 ubuntu22.04搭建qemu环境测试内核 交叉编译busybox 编译busybox出现Library m is needed, can’t exclude it (yet)的解释 S3C2440 制作最新busybox文件系统 https:…

2024年网络安全竞赛-Web安全应用

Web安全应用 (一)拓扑图 任务环境说明: 1.获取PHP的版本号作为Flag值提交;(例如:5.2.14) 2.获取MySQL数据库的版本号作为Flag值提交;(例如:5.0.22) 3.获取系统的内核版本号作为Flag值提交;(例如:2.6.18) 4.获取网站后台管理员admin用户的密码作为Flag值提交…

udp多播组播

import socket ,struct,time# 组播地址和端口号 MCAST_GRP 239.0.0.1 MCAST_PORT 8888 # 创建UDP socket对象 sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # 绑定socket对象到本地端口号 # sock.bind((MCAST_GRP, MCAST_PORT)) …

【4】PyQt输入框

1. 单行文本输入框 QLineEdit控件可以输入单行文本 from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QVBoxLayout from PyQt5.QtCore import * from PyQt5.QtGui import QIcon import sysdef init_widget(w: QWidget):# 修改窗口标题w.setWindowTitle(单行输…