当前位置: 首页 > news >正文

【算法】排序——选择排序和交换排序(快速排序)

 =========================================================================

主页点击直达:个人主页

我的小仓库:代码仓库

C语言偷着笑:C语言专栏

数据结构挨打小记:初阶数据结构专栏

Linux被操作记:Linux专栏

LeetCode刷题掉发记:LeetCode刷题

算法头疼记:算法专栏 

=========================================================================

目录

前言

选择排序

直接选择排序

交换排序

冒泡排序

快速排序

hoare法

 挖坑法

双指针法

快速排序优化

优化一、三数取中

优化二、小区间优化

快速排序非递归


前言

上篇文章讲述了插入排序及插入排序的优化希尔排序,今天我们继续给大家带来排序中的选择排序和交换排序,选择排序包括直接选择排序、 其中还包括堆排序,因为之前讲过堆排序,这篇文章就不多讲解,点击直达堆排序。交换排序包括冒泡排序、快速排序。让我们开始今天的选择排序之旅吧!!!


选择排序

基本思想:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

直接选择排序

在元素集合array[i]--array[n-1]中选择关键码最大(小)的数据元素
若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换

在剩余的array[i]--array[n-2](array[i+1]--array[n-1])集合中,重复上述步骤,直到集合剩余1个元素

 实现代码

//交换函数
void swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}
//直接选择排序
void SelectSort(int* a, int n)
{for (int i = 0; i < n; i++){int mini = i;for (int j = i + 1; j < n; j++){if (a[mini] > a[j]){mini = j;}}swap(&a[i], &a[mini]);}
}

直接选择排序的特性总结:
1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:不稳定


交换排序

基本思想:

所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置。

交换排序的特点是:

将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

冒泡排序

实现代码

void BubbleSort(int* a, int n)
{for (int j = 0; j < n; j++){for (int i = 0; i < n - 1-j; i++){if (a[i + 1] < a[i]){Swap(&a[i + 1], &a[i]);}}}}

如果我们给一个有序数组的话,冒泡排序还是会两两相比较,会很麻烦我们不妨给一个变量,如果发生交换的话就改变这个变量的值每一趟冒泡排序后我们判断这个值是否改变,如果没改变则这个数组是有序的。

冒泡排序优化

void BubbleSort(int* a, int n)
{for (int j = 0; j < n; j++){int tmp = 1;for (int i = 0; i < n - 1-j; i++){if (a[i + 1] < a[i]){Swap(&a[i + 1], &a[i]);tmp=0;}}if (tmp == 1){return;}}}

快速排序

快速排序Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

这里我们能发现每一趟排序后的基准值都会被排序到正确的位置,因此我们以排好序的基准值为分界线,将数组分成左右两部分,左右两部分再根据排序的方法进行排序。每次排序都会产生一个排好序的基准值,每次都要根据这个基准值将数组分成两部分。因此我们考虑使用递归。

hoare法

实现代码 

//hoare法
int PartSort1(int* a, int left, int right)
{int keyi = left;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[keyi], &a[left]);return left;
}
void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int keyi = PartSort1(a, begin, end);//[0 , keyi-1] keyi [keyi+1 , end]QuickSort(a, keyi + 1, end);QuickSort(a, begin, keyi - 1);
}

 挖坑法

实现代码

//挖坑法
int PartSort2(int* a, int left, int right)
{int key = a[left];int keyi = left;while (left < right){while (left < right && a[right] >= a[keyi]){right--;}a[keyi] = a[right];keyi = right;while (left < right && a[left] <= a[keyi]){left++;}a[keyi] = a[left];keyi = left;}a[keyi] = key;return keyi;
}
void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int keyi = PartSort2(a, begin, end);//[0 , keyi-1] keyi [keyi+1 , end]QuickSort(a, keyi + 1, end);QuickSort(a, begin, keyi - 1);
}

双指针法

 实现代码

//双指针法
int PartSort3(int* a, int left, int right)
{int prev = left;int cur = left + 1;int keyi = left;while (cur <= right){if (a[cur] < a[keyi]){Swap(&a[++prev], &a[cur]);}cur++;}Swap(&a[prev], &a[keyi]);return  prev;
}
void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int keyi = PartSort3(a, begin, end);//[0 , keyi-1] keyi [keyi+1 , end]QuickSort(a, keyi + 1, end);QuickSort(a, begin, keyi - 1);
}

 上面的三中方法我们使用函数递归来完成的,如果给予一个很大的数组需要排序,递归的深度可能会很深,会导致栈溢出。


快速排序优化

我们能否发现快速排序的递归很像二叉树的遍历,但是还有一个问题我们每次选的基准值排好序后都不一定都处于数组中大致的中间位置,这是我们理想的情况,如果不理想呢,每次选好的基准值排好序后都位于开头,这样只能将一个数组元素分割出去,而不是将近分开一半一半。
最好情况:每次都将近分开一半。

时间复杂度:O(N*logN)

最坏的情况:每次都分开一小部分

时间复杂度:O(N^2) 

优化一、三数取中

我们在传参数时会传数组的长度,我们不妨在在数组头,数组尾和数组中间这三个值之间挑出中间值放在数组的头部,作为基准值,在进行排序。

实现代码 

int GetMidi(int* a, int left, int right)
{int mid= (left + right) / 2;if (a[left] < a[mid]){if (a[mid] < a[right]){return mid;}else if (a[left] > a[right]){return left;}else{return right;}}else //left>mid{if (a[mid] > a[right]){return mid;}else if (a[left] < a[right]){return left;}else{return right;}}
}

这样我们实现了三数取中,再将下面的代码放到三种方法排序之前就可以了

int mid = GetMidi(a, left, right);Swap(&a[left], &a[mid]);

 这样我们初步的优化就完成了。

优化二、小区间优化

我们一上面的10个元素的数组为例,递归深度只有三四层没必要使用递归向下深入,继续浪费栈空间,我们不妨当数组元素大于等于10的时候递归,当数组元素小于10时使用插入排序

实现代码

void QuickSort(int* a, int begin,int end)
{if (begin >= end)return;//小区间优化,小区间不在递归分割排序,减少递归次数if((end-begin+1)>10){ int keyi = PartSort3(a, begin, end);//[begin,keyi-1] keyi [keyi+1 ,end]zdQuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);}else{InsertSort(a + begin, end - begin + 1);}
}

快速排序非递归

这里我们使用栈数据结构配合数组下标来完成非递归的实现。

实现代码

void QuickSortNonR(int* a, int left, int right)
{ST st;STInit(&st);STPush(&st, right);STPush(&st, left);while (!STEmpty(&st)){int begin = STTop(&st);STPop(&st);int end = STTop(&st);STPop(&st);int keyi = PartSort1(a, begin, end);if (keyi+1<end){STPush(&st, right);STPush(&st, keyi + 1);}if (keyi - 1 > begin){STPush(&st, keyi - 1);STPush(&st, left);}}STDer(&st);
}

快速排序的特性总结:
1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(logN)
4. 稳定性:不稳定 

选择排序和快速排序的基本内容及优化到这就讲完了,其中快速排序使用非递归来实现确实优点难理解,大家可以一边分析代码,一边画图来理解。希望能积极指出文章中的错误,下期带来排序的最后一篇文章归并排序,敬请期待!!! 

相关文章:

【算法】排序——选择排序和交换排序(快速排序)

主页点击直达&#xff1a;个人主页 我的小仓库&#xff1a;代码仓库 C语言偷着笑&#xff1a;C语言专栏 数据结构挨打小记&#xff1a;初阶数据结构专栏 Linux被操作记&#xff1a;Linux专栏 LeetCode刷题掉发记&#xff1a;LeetCode刷题 算法头疼记&#xff1a;算法专栏…...

Docker 容器监控 - Weave Scope

Author&#xff1a;rab 目录 前言一、环境二、部署三、监控3.1 容器监控 - 单 Host3.2 容器监控 - 多 Host 总结 前言 Docker 容器的监控方式有很多&#xff0c;如 cAdvisor、Prometheus 等。今天我们来看看其另一种监控方式 —— Weave Scope&#xff0c;此监控方法似乎用的人…...

Spring Boot集成redis集群拓扑动态刷新

项目场景&#xff1a; Spring Boot集成Redis集群&#xff0c;使用lettuce连接Cluster集群实例。 问题描述 redis其中一个节点挂了之后&#xff0c;springboot集成redis集群配置信息没有及时刷新&#xff0c;出现读取操作报错。 java.lang.IllegalArgumentException: Connec…...

COCI2022-2023#1 Neboderi

P9032 [COCI2022-2023#1] Neboderi 题目大意 有一个长度为 n n n的序列 h i h_i hi​&#xff0c;你需要从中选择一个长度大于等于 k k k的子区间 [ l , r ] [l,r] [l,r]&#xff0c;使得 g ( h l h l 1 ⋯ h r ) g\times (h_lh_{l1}\cdotsh_r) g(hl​hl1​⋯hr​)最小&…...

由于找不到d3dx9_43.dll无法继续执行此代码怎么解决?全面解析d3dx9_43.dll

在使用计算机过程中&#xff0c;我们可能会遇到各种各样的问题。其中之一就是d3dx9_43.dll文件丢失的问题。这个问题通常会出现在运行某些应用程序或游戏时&#xff0c;导致程序无法正常启动或运行。那么&#xff0c;如何解决这个问题呢&#xff1f;小编将为您提供一些解决方案…...

Linux--网络编程-字节序

进程间的通信&#xff1a; 管道、消息队列、共享内存、信号、信号量。 特点&#xff1a;都依赖于linux内核。 缺陷&#xff1a;无法多机通信。 一、网络编程&#xff1a; 1、地址&#xff1a;基于网络&#xff0c;ip地址端口号。 端口号作用&#xff1a; 一台拥有ip地址的主机…...

python实现http/https拦截

python实现http拦截 前言:为什么要使用http拦截一、技术调研二、技术选择三、使用方法前言:为什么要使用http拦截 大多数爬虫玩家会直接选择API请求数据,但是有的网站需要解决扫码登录、Cookie校验、数字签名等,这种方法实现时间长,难度高。需求里面不需要高并发,有没有…...

农产品团购配送商城小程序的作用是什么

农产品覆盖稻麦油蛋等多种细分类目&#xff0c;各地区经营商家众多&#xff0c;随着人们生活品质提升&#xff0c;对食物的要求也在提升&#xff0c;绿色无污染无激素的农产品往往受到不少人喜爱&#xff0c;而在销售中&#xff0c;也有不少人选择自建商城线上经营。 通过【雨…...

使用van-dialog二次封装微信小程序模态框

由于微信小程序的wx.showModal不支持富文本内容&#xff0c;无法实现更灵活的展示效果&#xff0c;故需要进行二次封装 实现思路&#xff1a;使用van-dialog以及微信小程序的rich-text实现 代码如下&#xff1a; // index.wxml <van-dialoguse-slottitle"提示"s…...

生鲜蔬果同城配送社区团购小程序商城的作用是什么

生鲜蔬果行业作为市场主要支撑之一&#xff0c;从业商家众多的同时消费者也从不缺&#xff0c;尤其对中高城市&#xff0c;生鲜蔬果除了传统线下超市、市场经营外&#xff0c;线上更是受到大量消费者信任&#xff0c;而很多商家也是自建了生鲜蔬果商城多场景生意经营。 那么通…...

Unity实现设计模式——状态模式

Unity实现设计模式——状态模式 状态模式最核心的设计思路就是将对象的状态抽象出一个接口&#xff0c;然后根据它的不同状态封装其行为&#xff0c;这样就可以实现状态和行为的绑定&#xff0c;最终实现对象和状态的有效解耦。 在实际开发中一般用到FSM有限状态机的实现&…...

差分数组的应用技巧

前缀和技巧 针对的算法场景是不需要对原始数组进行修改的情况下&#xff0c;频繁查询某个区间的累加和。 差分数组 主要适用场景是频繁对原始数组的某个区间的元素进行增减。 相关题目 1094. 拼车 1109. 航班预订统计 370. 区间加法 # 1094. 拼车 class Solution:def carPool…...

斯坦福数据挖掘教程·第三版》读书笔记(英文版)Chapter 10 Mining Social-Network Graphs

来源&#xff1a;《斯坦福数据挖掘教程第三版》对应的公开英文书和PPT。 Chapter 10 Mining Social-Network Graphs The essential characteristics of a social network are: There is a collection of entities that participate in the network. Typically, these entiti…...

DFS:842. 排列数字

给定一个整数 nn&#xff0c;将数字 1∼n1∼n 排成一排&#xff0c;将会有很多种排列方法。 现在&#xff0c;请你按照字典序将所有的排列方法输出。 输入格式 共一行&#xff0c;包含一个整数 nn。 输出格式 按字典序输出所有排列方案&#xff0c;每个方案占一行。 数据…...

pytorch之nn.Conv1d详解

自然语言处理中一个句子序列&#xff0c;一维的&#xff0c;所以使用Conv1d...

H5生成二维码

H5生成二维码&#xff1a; 1.引入js库&#xff0c;可自行点击链接复制使用 <script type"text/javascript" src"http://static.runoob.com/assets/qrcode/qrcode.min.js"></script>2.加入二维码占位区HTML <div id"qrCode">…...

Three.js加载360全景图片/视频

Three.js加载360全景图片/视频 效果 原理 将全景图片/视频作为texture引入到three.js场景中将贴图与球形网格模型融合&#xff0c;将球模型当做成环境容器使用处理视频时需要以dom为载体&#xff0c;加载与控制视频动作每次渲染时更新当前texture&#xff0c;以达到视频播放效…...

北大硕士7年嵌入式学习经验分享

阶段 1 大一到大三这个阶段我与大多数学生相同&#xff1a; 学习本专业知识&#xff08;EE专业&#xff09;&#xff0c;学习嵌入式软件开发需要的计算机课程&#xff08;汇编原理&#xff0c;计算机组成原理&#xff0c;操作系统&#xff0c;C语言等&#xff09;&#xff0c…...

华为鸿蒙手表开发之动态生成二维码

华为鸿蒙手表开发之动态生成二维码 前言&#xff1a; 最近入职新公司&#xff0c;由于之前的哥们临时离职&#xff0c;走得很突然&#xff0c;所以没有任何交接和文档&#xff0c;临时顶上公司手表应用的上架&#xff0c;更换了新的密钥和key之后重新测试功能和流程&#xff…...

2023-09-28 monetdb-databae的概念和作用-分析

摘要: 每个数据库对于db,schema以及user,role都有一套自己的设计, 不同数据库间对于相同名字的东西例如database和schema可以说南辕北辙, 例如mysql中schema其实是database的同义词. 本文分析monetdb的database的概念和作用 database的概念和作用: 和mysql的database完全不同…...

2024级199管理类联考之数学基础(上篇)

管理类考试介绍 管理综合200分,时间3小时 数学&#xff1a;75分/25题,是拉开差距的核心模块 问题求解题&#xff1a;15个,5选一条件充分性判断&#xff1a;10个,结合两个条件选择答案 条件一充分,条件二不充分&#xff1a;A条件一不充分,条件二充分&#xff1a;B条件一充分,条…...

RFID技术引领汽车零部件加工新时代

RFID技术的兴起引领了汽车零部件加工领域的新时代&#xff0c;作为一种利用无线电频率进行自动识别的技术&#xff0c;RFID技术能够快速、准确地识别物体并获取相关数据&#xff0c;在汽车零部件加工中&#xff0c;RFID技术具有重要的应用价值&#xff0c;可以提高生产效率、降…...

python中使用matplotlib绘图

一、背景 当我们在写python程序时&#xff0c;不可避免的需要将数据可视化&#xff0c;也就是绘制出数据的曲线图&#xff0c;以便我们更直观的观察数据间的变化&#xff0c;和方便对比。此时就要用到matplotlib库了。 matplotlib官方给出的定义是&#xff1a; 翻译过来也就是…...

Qt Creator 使用技巧

使用技巧 功能快捷键解释Switch Header/SourceF4在同名的头文件和源程序文件之间切换Follow Symbol Under CursorF2变量:跳转到声明;函数:声明和定义切换Refactor Rename Symbol Under CursorCtrlShiftR改名称&#xff0c;将替换所有用到这个符号的地方RefactorAdd Definition…...

来看看双阶段目标检测算法趴

&#x1f680; 作者 &#xff1a;“码上有钱” &#x1f680; 文章简介 &#xff1a;AI-目标检测算法 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac;简介 双阶段目标检测算法是一类深度学习算法&#xff0c;通常分为两个阶段来检测和识别图像中的…...

python利用matplotlib绘图,对于中文和负号不显示,显示方框“口口”完美解决办法!!

文章目录 一、问题展示二、问题分析三、解决办法四、结果展示 一、问题展示 二、问题分析 可以发现对中文&#xff0c;以及负号不显示。 三、解决办法 import matplotlib.pyplot as pltplt.rcParams[font.sans-serif] [usimHei] # 显示中文 plt.rcParams[axes.unicode_mi…...

【数组及指针经典笔试题解析】

1.数组和指针笔试题 题目1 int main(){int a[5] { 1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5};int * ptr (int * )(&a 1);printf("%d&#xff0c;%d"&#xff0c;*(a 1)&#xff0c;*(ptr - 1));return 0;}图文解析&#xff1a; int * ptr …...

Transformer学习-self-attention

这里写自定义目录标题 Self-attentionMulti-head self-attention用self-attention解决其他问题 Self-attention 用Wq、Wk、Wv分别乘输入向量得到q、k、v向量 用每个q向量乘所有的k向量得到对应项的attention&#xff0c;即用每项的query向量去匹配所有的key向量&#xff0c;得…...

Spring Boot:利用JPA进行数据库的增改

目录 JPA介绍Service接口Service和Autowired示例代码 Dao数据库操作层Repository示例代码 控制器文件示例代码-增加增加成功示例代码-修改修改成功 JPA介绍 JPA&#xff08;Javaa Persistence API)一种用于持久化 Java 对象到关系型数据库的标准规范。它提供了一种统一的方式来…...

列表的增删改查和遍历

任务概念 什么是任务 任务是一个参数为指针&#xff0c;无法返回的函数&#xff0c;函数体为死循环不能返回任务的实现过程 每个任务是独立的&#xff0c;需要为任务分别分配栈称为任务栈&#xff0c;通常是预定义的全局数组&#xff0c;也可以是动态分配的一段内存空间&#…...

如何优化移动端网站/网站关键词优化费用

终止正在运行的matlab文件&#xff0c;需要命令窗口按快捷键&#xff0c;有三种快捷键可以选择&#xff1a;  一&#xff1a;    ctrl c  二&#xff1a;    ctrlbreak  三&#xff1a;    ctrlaltbreak如果是在服务器上跑的代码的话,按完快捷键之后有时候需…...

wordpress 统计/税收大数据

win7日志管理:查:计算机-----》管理---》系统工具---》事件查看器关闭日志功能(不建议这么做)&#xff1a;计算机-----》管理---》服务和应用程序---》服务---》找到Event_log---》鼠标右键---》停止故障小插曲&#xff1a;故障一&#xff1a;windows系统中突然出现打印机无法打…...

做网站需要提供什么/百度账户托管

使用maxwell实时采集mysql数据 1. 什么是maxwell maxwell 是由美国zendesk开源&#xff0c;用java编写的Mysql实时抓取软件。 其抓取的原理也是基于binlog。 2. Maxwell与canal的对比 Maxwell 没有 Canal那种serverclient模式&#xff0c;只有一个server把数据发送到消息队…...

浙江省网站建设与管理试卷/百度导航2023年最新版

No1: 程序计数器、虚拟机栈、本地方法栈3个区域随线程而生&#xff0c;随线程而灭&#xff1a;栈中的栈帧随着方法的进入和退出而有条不紊的执行着出栈和入栈操作。每一个栈帧中分配多少内存基本上市在类结构确定下来时就已知的&#xff0c;因此这几个区域的内存分配和回收都具…...

javaweb是用java做网站吗/公关公司

1、同步和异步的区别 当未使用异步页时,一个线程只能为同一个页面的请求服务. 即使页面请求过程中处理其它的I/O等操作时,此线程也一直处于等待状态. 当此页面使用完此线程时,才将它放回到线程池. 线程数量是有限的! 所以当不使用线程时及时放回线池可以使系统性能大大提高! 当…...

如何选择建设网站类型/网络推广网站推广方法

web39这个地方被加上了.php后缀官方解释data://text/plain, 这样就相当于执行了php语句 .php 因为前面的php语句已经闭合了&#xff0c;所以后面的.php会被当成html页面直接显示在页面上&#xff0c;起不到什么 作用,这个cdata://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZm…...