【数据结构与算法】第11课—数据结构之选择排序和交换排序

文章目录

  • 1. 选择排序
    • 1.1 直接选择排序
    • 1.2 堆排序
  • 2. 交换排序
    • 2.1 冒泡排序
    • 2.2 快速排序(找基准值法1----Hoare版本)
      • 2.2.1 特殊场景1
      • 2.2.2 特殊场景2
      • 2.2.3 代码
      • 2.2.4 快速排序的时间复杂度
    • 2.3 快速排序(找基准值法2---挖坑法)
      • 2.3.1 特殊情况1处理
      • 2.3.2 特殊情况2处理
    • 2.4 快速排序(找基准值法3-----lomuto(双指针法))
    • 2.5 快速排序(非递归版本)

   前面我们讲了插入排序的两种,接下来我们来学习其他几种排序算法吧

1. 选择排序

  • 选择排序的思想:每次从待排序的数据中选取最小(最大)的元素,然后存放在序列的起始位置,直到数据全部排完序
  • 选择排序分为两种:直接选择排序、堆排序

1.1 直接选择排序

  • 直接选择排序的思想:首先选取待排序集合的最大(最小)的数据元素,如果最大的元素不是序列的最后一个位置,则让它与最后的元素交换;同样,最小的元素如果不再数据的起始位置,那么让它与第一个元素交换,之后继续重复上述操作待排序的数据,直到排好序

  下面我将用图示的方式来帮助大家理解
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


  • 以上是我们对特殊情况的分析,接下来我们还是继第三步继续分析

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


  • 接下来我们就看下代码是如何实现的吧
//直接选择排序
void SelectSort(int* arr, int sz)
{int begin = 0;int end = sz - 1;while (begin < end){int max = begin;int min = begin;//寻找最大、最小元素for (int i = begin + 1; i <= end; i++)//由于max和min都在首元素,这里直接从begin+1开始找就行{//寻找最大元素if (arr[i] > arr[max]){max = i;}//寻找最小元素if (arr[i] < arr[min]){min = i;}}//特殊情况处理(begin == max)if (begin == max){max = min;}//交换if (min != begin){Swap(&arr[min], &arr[begin]);}if (max != end){Swap(&arr[max], &arr[end]);}begin++;end--;}
}
  • 直接选择排序的时间复杂度是O(n^2),空间复杂度是O(1)

1.2 堆排序

  • 前面我们讲二叉树的时候就已经讲过堆了,这里只带大家简单熟悉一下,需要深入了解的小伙伴可点击下面的链接
  • 链接: 【数据结构与算法】第8课—数据结构之二叉树(堆)

在这里插入图片描述


  • 总体来讲,堆排序的时间复杂度是O(nlogn),它是一个比较好的排序算法
  • 接下来附上堆排序的代码
//交换
void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}//向下调整算法
void AdjustDown(int* arr, int parent, int n)
{int child = parent * 2 + 1;//左孩子节点while (child < n){//先找最小的孩子if (child + 1 < n && arr[child] < arr[child + 1]){child++;}//交换if (arr[child] > arr[parent]){Swap(&arr[child], &arr[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}//堆排序
void HeapSort(int* arr, int sz)
{//向下调整算法建堆for (int i = (sz - 1 - 1) / 2; i >= 0; i--){AdjustDown(arr, i, sz);}//堆排序int end = sz - 1;while (end){Swap(&arr[0], &arr[end]);AdjustDown(arr, 0, end);end--;}
}

2. 交换排序

  • 交换排序的思想:就是根据序列交换数据的位置
  • 交换排序的特点:数据大(小)的值向尾部移动,而数据小(大)的值向头部移动
  • 交换排序也分为两种:冒泡排序和快速排序

2.1 冒泡排序

  学到这里我们对冒泡排序应该很熟悉了,尽管它是一个很差的排序算法,它的时间复杂度是O(N^2),如果还有小伙伴对冒泡排序不熟悉的,可点击下面的链接,不废话,直接上代码
  链接: C语言进阶版第8课—指针(2)

//冒泡排序
void BubbleSort(int* arr, int sz)
{for (int i = 0; i < sz; i++){int flag = 0;for (int j = 0; j < sz - i - 1; j++){if (arr[j] > arr[j + 1]){flag = 1;int tmp = arr[j + 1];arr[j + 1] = arr[j];arr[j] = tmp;}}if (flag == 0)break;}
}

2.2 快速排序(找基准值法1----Hoare版本)

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

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


  • Hoare提出的快速排序其实可以看成二叉树递归,首先定义一个基准值,然后调整基准值位置,再根据基准值二分数组,将划分的每个子树重新定义一个基准值,再调整新的基准值位置,然后根据新的基准值再二分新的数组,直到最后只剩一个元素时结束递归,这时快速排序就完成了

2.2.1 特殊场景1

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

2.2.2 特殊场景2

  • 最特殊的场景

在这里插入图片描述


在这里插入图片描述


2.2.3 代码

  • 接下来看看代码是如何实现的

在这里插入图片描述

//找基准值
int _QuickSort(int* arr, int left, int right)
{int key = left;left++;while (left <= right){//right:从右向左找比基准值小的数while (left <= right && arr[right] > arr[key]){right--;}//left:从左向右找比基准值大的数while (left <= right && arr[left] < arr[key]){left++;}//left和right交换if (left <= right){Swap(&arr[left], &arr[right]);left++;right--;}}//此时left>right,且arr[right]<arr[key],arr[left]>arr[key]//交换arr[key]和arr[right]Swap(&arr[key], &arr[right]);//此时right就是基准值校准后的下标return right;
}//快速排序
void QuickSort(int* arr, int left, int right)
{if (left >= right){return;}//找基准值int key = _QuickSort(arr, left, right);//二分QuickSort(arr, left, key - 1);//左子树QuickSort(arr, key + 1, right);//右子树
}

2.2.4 快速排序的时间复杂度

在这里插入图片描述


2.3 快速排序(找基准值法2—挖坑法)

  • 创建左右指针。首先从右向左找出比基准小的数据,找到后立即放入左边坑中,当前位置变为新的"坑",然后从左向右找出比基准⼤的数据,找到后立即放入右边坑中,当前位置变为新的"坑",结束循环后将最开始存储的分界值放入当前的"坑"中,返回当前"坑"下标(即分界值下标)

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


2.3.1 特殊情况1处理

在这里插入图片描述


2.3.2 特殊情况2处理

在这里插入图片描述


  • 代码实现
//找基准值法2---挖坑
int _QuickSort2(int* arr, int left, int right)
{int key = arr[left];//先定义基准值int hole = left;while (left < right){//right向左找比基准值小的数while (left < right && arr[right] >= key){right--;}//找到后arr[hole] = arr[right];hole = right;//left向右找比基准值大的数while (left < right && arr[left] <= key){left++;}//找到后arr[hole] = arr[left];hole = left;}//此时left=right,将基准值放入坑位arr[hole] = key;return hole;
}//快速排序
void QuickSort(int* arr, int left, int right)
{if (left >= right){return;}//找基准值int key = _QuickSort2(arr, left, right);//二分QuickSort(arr, left, key - 1);//左子树QuickSort(arr, key + 1, right);//右子树
}

2.4 快速排序(找基准值法3-----lomuto(双指针法))

  • 双指针法法:定义两个指针prev和cur,cur指针用来探路,找比基准值要小的数
  • 两种情况:
  • cur未找到比基准值小的数据:cur++
  • cur找到了比基准值小的数据:prev++,然后prev和cur位置的数据互换,cur再++找比基准值小的数,直到cur越界都未找到,那么交换prev位置的数据和基准值

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


  • 代码实现
//找基准值法3---双指针法
int _QuickSort3(int* arr, int left, int right)
{int key = left;//基准值int prev = left;int cur = left + 1;//cur指针用来探路找比基准值小的数while (cur <= right){//cur找到比基准值小的数if (cur <= right && arr[cur] < arr[key]){prev++;if (prev != cur){Swap(&arr[prev], &arr[cur]);}}//cur未找到比基准值小的数,不论找没找到,cur都得++cur++;}//cur越界,交换arr[prev]和基准值Swap(&arr[prev], &arr[key]);return prev;//prev为校准后的基准值下标
}//快速排序
void QuickSort(int* arr, int left, int right)
{if (left >= right){return;}//找基准值int key = _QuickSort3(arr, left, right);//二分QuickSort(arr, left, key - 1);//左子树QuickSort(arr, key + 1, right);//右子树
}

2.5 快速排序(非递归版本)

  • 非递归版本的思路:需要借助数据结构——栈,首先将数组的尾元素下标入栈,再让数组的首元素的下标入栈,保证栈不为空,然后取栈顶元素,先后将栈顶元素赋给begin和end,然后利用双指针法找基准值,找到基准值后将数组二分,然后先让右子树入栈,再让左子树入栈,入栈依然是尾元素下标优先,且入栈的都是子树的首尾元素下标,然后再取栈顶元素分别赋给begin和end,然后双指针找基准值,二分数组,入栈,取栈顶元素,以此往复,直到栈为空,排序完成
  • 接下来我将用图示来帮助大家理解

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


  • 代码实现
//快速排序---非递归版本
void QuickSortNone(int* arr, int left, int right)
{Stack st;//定义栈的变量StackInit(&st);//初始化//入栈StackPush(&st, right);StackPush(&st, left);//栈不为空while (!StackEmpty(&st)){//取栈顶元素int begin = StackTop(&st);StackPop(&st);//取出一个销毁一个int end = StackTop(&st);StackPop(&st);//找基准值---双指针法int key = begin;int prev = begin;int cur = prev + 1;//探路,找比基准值小的数while (cur <= end){//找比基准值小的数if (arr[cur] < arr[key]){prev++;//找到了,prev先往后走if (cur != prev){Swap(&arr[cur], &arr[prev]);}}//未找到/找到cur都得++cur++;}//cur越界,交换arr[prev]和基准值,此时prev就是校准后的基准值位置Swap(&arr[prev], &arr[key]);key = prev;//右子树先入栈if (key + 1 < end){StackPush(&st, end);//右子树尾元素下标StackPush(&st, key + 1);//右子树首元素下标}//左子树入栈if (begin < key-1){StackPush(&st, key - 1);//左子树尾元素下标StackPush(&st, begin);//左子树首元素下标}}StackDestroy(&st);//销毁栈
}

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

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

相关文章

MySQL技巧之跨服务器数据查询:进阶篇-从A数据库复制到B数据库的表中

MySQL技巧之跨服务器数据查询&#xff1a;进阶篇-从A数据库复制到B数据库的表中 基础篇已经描述&#xff1a;借用微软的SQL Server ODBC 即可实现MySQL跨服务器间的数据查询。 而且还介绍了如何获得一个在MS SQL Server 可以连接指定实例的MySQL数据库的连接名: MY_ODBC_MYSQ…

UVC 输出视频格式修改和windows下数据分析

文章目录 前言一、UVC MJPEG视频帧描述符1.MJPG视频帧格式示例 二、UVC YUV2、NV12、M420、I420无压缩视频帧描述符GUID1.如YUV2数据参数初始为: 三、UVC Windows下UVC摄像头数据分析总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 项目需要&#…

大数据开发面试宝典

312个问题&#xff0c;问题涵盖广、从自我介绍到大厂实战、19大主题&#xff0c;一网打尽、真正提高面试成功率 一、Linux 1. 说⼀下linux的常⽤命令&#xff1f; 说一些高级命令即可 systemctl 设置系统参数 如&#xff1a;systemctl stop firewalld关闭防火墙 tail / hea…

更改Ubuntu22.04锁屏壁纸

更改Ubuntu22.04锁屏壁纸 sudo apt install gnome-shell-extensions gnome-shell-extension-manager安装Gnome Shell 扩展管理器后&#xff0c;打开“扩展管理器”并使用搜索栏找到“锁屏背景”扩展

GxtWaitCursor:Qt下基于RAII的鼠标等待光标类

有时我们需要以阻塞的方式执行一点耗时的操作&#xff0c;这时需要主窗口光标呈现忙状态&#xff0c;GxtWaitCursor正是为此设计&#xff1b;重载的构造函数&#xff0c;可以让光标呈现忙状态一定时间后自动恢复。 GxtWaitCursor.h #pragma once#include <QObject>// // …

Unity3D实现视频和模型融合效果

系列文章目录 unity工具 文章目录 系列文章目录👉前言👉一、效果展示如下👉二、VideoPlayer播放视频(一)👉2-1、Hieraechy面板右键创建videoPlayer👉2-2、Assets面板右键创建RenderTexture👉2-3、把设置好的RenderTexture拖到videoPlayer里面还有本地视频视频�…

探索Pillow库:Python图像处理的瑞士军刀

文章目录 **探索Pillow库&#xff1a;Python图像处理的瑞士军刀**1. 背景&#xff1a;为何选择Pillow&#xff1f;2. Pillow是什么&#xff1f;3. 如何安装Pillow&#xff1f;4. 五个简单的库函数使用方法4.1 打开图像4.2 显示图像4.3 转换图像格式4.4 调整图像大小4.5 旋转图像…

HelloMeme 上手即用教程

HelloMeme是一个集成空间编织注意力的扩散模型&#xff0c;用于生成高保真图像和视频。它提供了一个代码库&#xff0c;包含实验代码和预训练模型&#xff0c;支持PyTorch和FFmpeg。用户可以通过简单的命令行操作来生成图像和视频。 本文将详细介绍&#xff0c;如何在GPU算力租…

JVM详解:JVM的系统架构

计算机语言大致可以分为两类&#xff0c;一直是编译性语言&#xff0c;典型的如C&#xff0c;他会先有编译器编译成可执行文件&#xff08;操作系统可读&#xff0c;不同的操作系统需要编译成不同的可执行文件&#xff09;&#xff0c;而另一种则是翻译性语言&#xff0c;这种语…

21. Drag-Drop拖放操作(二) - 文件、表格和树的拖放实现

本了继上节内容&#xff0c;讲述几种常用的拖放场景示例&#xff0c;包括文件、表格和树的拖放实现。 文件拖放 实现从系统目录拖放文件到App中。 自定义接收视图 自定义应用内部接收拖放的view视图类FileDragView&#xff0c;注册拖放类型&#xff0c;实现目标拖放协议NS…

力扣515:在每个树行中找最大值

给定一棵二叉树的根节点 root &#xff0c;请找出该二叉树中每一层的最大值。 示例1&#xff1a; 输入: root [1,3,2,5,3,null,9] 输出: [1,3,9]示例2&#xff1a; 输入: root [1,2,3] 输出: [1,3]提示&#xff1a; 二叉树的节点个数的范围是 [0,104]-231 < Node.val &l…

vivo 游戏中心包体积优化方案与实践

作者&#xff1a;来自 vivo 互联网大前端团队- Ke Jie 介绍 App 包体积优化的必要性&#xff0c;游戏中心 App 在实际优化过程中的有效措施&#xff0c;包括一些优化建议以及优化思路。 一、包体积优化的必要性 安装包大小与下载转化率的关系大致是成反比的&#xff0c;即安装…

数据库SQL——连接表达式(JOIN)图解

目录 一、基本概念 二、常见类型 内连接&#xff08;INNER JOIN&#xff09;&#xff1a; 左连接&#xff08;LEFT JOIN 或 LEFT OUTER JOIN&#xff09;&#xff1a; 右连接&#xff08;RIGHT JOIN 或 RIGHT OUTER JOIN&#xff09;&#xff1a; 全连接&#xff08;FULL…

Sigrity SPEED2000 Power Ground Noise Simulation模式如何查看PDS系统的自阻抗操作指导

Sigrity SPEED2000 Power Ground Noise Simulation模式如何查看PDS系统的自阻抗操作指导 Sigrity Power SI Power Ground Noise Simulation模式可以用于PDS系统自阻抗分析,以下图为例 2D视图

uni-app移动端与PC端兼容预览PDF文件

过程遇到的问题 1、如果用的是最新的版本的pdfjs的话&#xff0c;就会报Promise.withResolvers 不是一个方法的错误&#xff0c;原因是Promise.withResolvers是ES15新特性&#xff0c;想了解可参考链接&#xff0c;这里的解决方案是将插件里的涉及到Promise.withResolvers的地…

「Py」Python基础篇 之 Python都可以做哪些自动化?

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「Py」Python程序设计&#x1f4da;全部专栏「Win」Windows程序设计「IDE」集成开发环境「UG/NX」BlockUI集合「C/C」C/C程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「UG/NX」NX定…

[ 网络安全介绍 5 ] 为什么要学习网络安全?

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

在Java中使用ModelMapper简化Shapefile属性转JavaBean实战

目录 前言 一、原始的处理办法 1、使用Set方法来转换 2、使用构造方法转换 二、基于ModelMapper的动态转换 1、ModelMapper简介 2、集成到项目中 3、Shapefile属性读取 三、总结 前言 在现代软件开发中&#xff0c;尤其是在多层架构中&#xff0c;经常需要将数据从一个…

时间管理的三个痛点

时间管理方面&#xff0c;有三个痛点&#xff1a;不知道、不平衡、不安全。 很多人&#xff0c;忙了一天&#xff0c;感觉很累&#xff0c;但是不知道做了什么。他不知道&#xff0c;这一天工作了几个小时&#xff0c;做了哪些事&#xff0c;分别用了多少时间&#xff0c;只是…

封装el-menu

案例图 数据格式 commonMenu.vue <template><div class"commonMenuStyle"><el-sub-menu v-if"hasChildren" :index"item.MenuId"><template #title><el-icon><location /></el-icon><!-- isColl…