数据结构之选择排序

目录

直接选择排序

选择排序的时间复杂度

堆排序

向上调整算法

向下调整算法

向上调整算法建立堆

向下调整算法建立堆

堆排序整体代码

堆排序的时间复杂度


直接选择排序

在之前讲插入排序时,我们讲了这样的一个应用场景,我们在斗地主摸牌时,会一张一张的摸,然后采用插入排序的方法将手中的牌变得有序,但是还有一种摸牌的方式,就是将所有的牌先发到手里,然后在所有牌中找出最大的和最小的放到牌的两端,重复上述步骤,依次挑选最大的和最小的放到两端,直到将手中的牌排好序,这其实就是生活中直接选择排序的应用。在数据结构中,直接选择排序又是怎样实现的呢?

 直接插入排序的思想:先进行单趟的排序,找出最小和最大的两个数,并且将最小的数和最大的数依次交换到数组的头部和尾部,然后重复单趟排序的操作,直到将数组整个排有序。

直接选择排序图示如下:

直接选择排序代码如下:

void Swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}void SelectSort(int* a, int size)
{int begin = 0, end = size - 1;while (begin < end){int max = begin, min = begin;//先进行单趟排序,遍历每个元素,找出最大最小的两个数的位置for (int i = begin+1; i <= end; i++)//这里让begin+1的原因是,自己没有必要和自己比较{if (a[i] < a[min]){min = i;}if (a[i] > a[max]){max = i;}}
//单趟排序找到最大和最小的元素之后,将最小的值与begin位置上的元素交换,将最大的值与end位置上的元素交换Swap(&a[begin], &a[min]);
//当begin位置上的元素就是最大的元素时,将最小的元素和begin位置上的元素交换之后,最大的元素的位置就会发生改变
//max位置上的元素并不是最大的元素,min位置上的元素就是最大的元素,所以我们得把此时的min赋值给max,然后再做交换if (max == begin)max = min;Swap(&a[end], &a[max]);//让begin++,end--,再进行下一趟排序,找出最大的和最小的放置在两端begin++;end--;}
}
int main()
{int arr[] = {100,99,27,92,99,220,28,78,18,8 };SelectSort(arr, sizeof(arr) / sizeof(int));for (int i = 0; i < sizeof(arr) / sizeof(int); i++){printf("%d ", arr[i]);}return 0;
}

 大家有没有注意到这样一段代码:

我们进行了一趟排序,找出了最大的元素和最小的元素,直接将最大的元素和最小的元素分别与end位置和begin位置上的元素交换即可,为什么还要把进行一次判断呢?

因为我们要排除一种极端的情况:

看下图:

其实对于上述情况,我们还有一种解决办法,如果begin位置的元素就是最大的元素,我们可以先让大的元素和end位置上的元素进行交换,然后再让最小的元素和begin位置上的元素进行交换,但是,上述情况只是在先交换最小元素的基础上修正的代码,大家可以根据自己情况进行选择。

选择排序的时间复杂度

时间复杂度:最好最坏都是O(N^2)

因为即使数组已经有序了编译器是无法分辨的,还是得每次找出最大的数和最小的数,第一趟比较每个元素比较2次所以总共比较2*(size-1)次,第二趟比较比较2*(size-3)次,所以其复杂度为等差数列的前n项求和,不管最好最坏,选择排序都是这个执行流程,所以直接选择排序的时间复杂度为O(N^2)。

稳定性:不稳定

堆排序

堆排序其实最重要的就是两个算法,向上调整和向下调整算法,先通过向上调整和向下调整算法建立堆,然后建好堆之后,再次采用向下调整算法调整元素的位置,最终实现排序。 

以下给出具体的代码,对代码不理解的小伙伴可以去看堆那几期的内容。点击这里 and 这里

向上调整算法

void AdjustUp(int* a, int child)
{assert(a);int parent = (child - 1) / 2;while (child > 0){//因为是大堆,所以父亲节点的值大于孩子节点的值,如果父亲节点的值小于孩子节点的值,就需要交换if (a[parent] < a[child]){int tmp = a[parent];a[parent] = a[child];a[child] = tmp;child = parent;parent = (child - 1) / 2;}else{break;}}
}

向下调整算法

void AdjustDown(int* a, int n, int parent)
{int child = parent * 2 + 1;while (child < n){//因为是大堆,向下调整时,为了避免从堆顶继续调整,所以必须选最大的孩子作为childif (child + 1 < n && a[child + 1] > a[child]){++child;}//因为是大堆,所以,如果父亲小于孩子,需要进行交换if (a[parent] < a[child]){int tmp = a[parent];a[parent] = a[child];a[child] = tmp;parent = child;child = parent * 2 + 1;}else{break;}}
}

向上调整算法建立堆

for (int i = 1; i < n; i++){AdjustUp(a, i);}

向上调整算法建堆,这里的i表示的就是向上调整算法里的child,对某个元素采用向上调整算法的前提是这个元素的前面的所有元素必须构成大堆或者小堆,对于一个数组而言,如果数组只有一个元素,我们就可以将这个数组看成大堆或者小堆,所以我们可以单独将第一个元素看成是一个大堆或者小堆,所以就可以从第二个元素要开始进行向上调整算法,然后后面的依此逻辑,直到将整个数组建成堆,与其说是建堆,不如说是调堆。

向下调整算法建立堆

	for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}

向下调整算法建堆,这里的i可以看做向下调整算法里的parent,一个元素要采用向下调整算法,必须保证当前元素所在节点的左右子树都必须为大堆或者小堆。叶子节点没有左右子树,所以不能对叶子节点采用向下调整算法, 但是可以对最后一个叶子节点的父亲节点进行向下调整算法,因为最后一个叶子节点的父亲节点的左右子树都是叶子节点,叶子节点可以看成是一个大堆或者小堆,所以我们要从最后一个叶子节点的父亲节点开始进行向下调整算法。

堆排序整体代码

void HeapSort(int* a,int n)
{for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}for (int end = n - 1; end >= 0; end--){HPDataType tmp = a[0];a[0] = a[end];a[end] = tmp;AdjustDown(a, end, 0);}
}
int main()
{int arr[] = { 1000,999,27,9,99,20,28,78,18,88 };HeapSort(arr, sizeof(arr) / sizeof(int));for (int i = 0; i < sizeof(arr) / sizeof(int); i++){printf("%d ", arr[i]);}return 0;
}

运行截图:

堆排序的时间复杂度

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

稳定性:不稳定

注意:虽然向上调整算法和向下调整算法都可以建立堆,但是我们建议使用向下调整算法建立堆,因为向上调整算法的时间复杂度为O(N*logN),而向下调整算法建立堆的时间复杂度为O(N)。

以上便是选择排序的所有内容。

本期的内容到此结束。^_^

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

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

相关文章

国产智能运维操作系统新选择-浪潮KeyarchOS

1.背景 在CentOS停更&#xff0c;国有企业纷纷摒弃原有的开发与运维工具&#xff0c;全面拥抱国产。我司也顺应号召&#xff0c;更换原有CentOS系统。 在新系统选型上&#xff0c;我司有以下要求&#xff1a; 国产、快速更新迭代、社区活跃&#xff1b;拥有一定知名度&#x…

保障海外业务发展,Coremail提供高效安全的海外通邮服务

11月22日&#xff0c;Coremail举办《全球通邮&#xff1a;如何保障安全、快捷的海外中继服务》直播分享会&#xff0c;直播会上Coremail安全团队和直播嘉宾复旦大学校园信息化办公室徐艺扬老师就海外中继服务进行了深度分享。 ​ 海外通邮困难重重 境外垃圾邮件数量居高不下…

echarts中option个参数的含义

var option {title: {text: ECharts 入门示例},tooltip: {},legend: {data: [数量]},xAxis: {data: [衬衫, 羊毛衫, 雪纺衫, 裤子, 高跟鞋, 袜子]},yAxis: {},series: [{name: 数量,type: bar,data: [5, 20, 36, 10, 10, 20]}] }; title&#xff1a;主要控制图表的标题 legen…

语义分割 LR-ASPP网络学习笔记 (附代码)

论文地址&#xff1a;https://arxiv.org/abs/1905.02244 代码地址&#xff1a;https://github.com/WZMIAOMIAO/deep-learning-for-image-processing/tree/master/pytorch_segmentation/lraspp 1.是什么&#xff1f; LR-ASPP是一个轻量级语义分割网络&#xff0c;它是在Mobil…

【ESP8266】ESP8266集成开发环境对比

当涉及到ESP8266开发环境的选择时&#xff0c;有几个常见的选择可供开发人员使用。在本篇文章中&#xff0c;我们将对比一些目前最流行的ESP8266集成开发环境&#xff08;IDE&#xff09;&#xff0c;以帮助您选择最适合您的需求的开发环境。 总结&#xff1a;Arduino IDE和Pl…

HarmonyOS应用开发——页面

我们将对于多页面以及更多有趣的功能展开叙述&#xff0c;这次我们对于 HarmonyOS 的很多有趣常用组件并引出一些其他概念以及解决方案、页面跳转传值、生命周期、启动模式&#xff08;UiAbility&#xff09;&#xff0c;样式的书写、状态管理以及动画等方面进行探讨 页面之间…

项目进度已经落后了,项目经理该怎么办?

进度管理是项目管理的核心工作之一&#xff0c;通过可续的进度计划与控制管理&#xff0c;最终实现项目按照目标交付。 进度管理的两大核心工作&#xff1a;计划制定、过程管控。 项目管理过程中难免会遇到工作进度和计划不一致的情况&#xff0c;有效管理项目进度&#xff…

Redis安装和使用(基于windows)

Redis是一个使用C语言编写的开源、高性能、非关系型的键值对存储数据库。它支持多种数据结构&#xff0c;包括字符串、列表、集合、有序集合、哈希表等。Redis的内存操作能力极强&#xff0c;其读写性能非常优秀&#xff0c;且支持持久化&#xff0c;可以将数据存储到磁盘上&am…

使用 React 和 ECharts 创建地球模拟扩散和飞线效果

在本博客中&#xff0c;我们将学习如何使用 React 和 ECharts 创建一个酷炫的地球模拟扩散效果。我们将使用 ECharts 作为可视化库&#xff0c;以及 React 来构建我们的应用。地球贴图在文章的结尾。 最终效果 准备工作 首先&#xff0c;确保你已经安装了 React&#xff0c;并…

智能安全芯片ACH512芯片描述及功能

ACH512 芯片是一款基于安全算法的高性能 SOC 芯片&#xff0c; 主要应用于 eMMC/SD/Nandflash 大容量存储设备、加密 U 盘、指纹识别等市场。 芯片采用 32 位内核&#xff0c;片内集成多种安全密码模块&#xff0c;包括SM1、 SM2、 SM3、 SM4、 SSF33 算法以及RSA/ECC、 ECDSA、…

数据结构 | 二叉树的各种遍历

数据结构 | 二叉树的各种遍历 文章目录 数据结构 | 二叉树的各种遍历创建节点 && 创建树二叉树的前中后序遍历二叉树节点个数二叉树叶子节点个数二叉树第k层节点个数二叉树查找值为x的节点二叉树求树的高度二叉树的层序遍历判断二叉树是否是完全二叉树 我们本章来实现二…

同调群的维度 和 同调群的秩

同调群的维度是指同调群中非零元素的最小阶数。与线性代数中对向量空间的维度的理解类似。对同调群&#xff0c;k维同调群的维度是k。 同调群的秩是指同调群中的自由部分的维度。同调群通常包含自由部分和挠部分。同调群的秩是指同调群中自由部分的维度。对同调群&#xff0c;…

SQL SERVER 设置权限和隐藏其他数据库

一、创建用户名&#xff0c;选择默认数据库 二、分配权限 --对用户EAM分配 View_1视图 只有 只读select权限 GRANT select on View_1 to EAM --对用户分配指定表权限&#xff08;读写删&#xff09; GRANT SELECT , INSERT , UPDATE , DELETE ON table1 TO [用户名] --对用户分…

更改 Mac 所使用网络服务的顺序

如果以多种不同的方式&#xff08;例如使用 Wi-Fi 或以太网&#xff09;接入互联网或网络&#xff0c;你可以更改连接时电脑所尝试的网络连接顺序。 如果有多个活跃的连接&#xff0c;电脑会首先尝试列表顶部的连接&#xff0c;然后按降序尝试其他连接。 你不能更改虚拟专用网…

详解Python 迭代器介绍及作用

文章目录 迭代器&#xff1a;初探什么是迭代器&#xff1f;通过迭代器进行迭代迭代器 for 循环的工作构建自定义迭代器Python 无限迭代器Python 迭代器的好处总结关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包…

Linux下安装MySQL 5.6

1、下载二进制安装文件 使用wget下载MySQL 5.6.35二进制安装文件并存放在/root目录下。 wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.6.35-linux-glibc2.5-x86_64.tar.gz ll mysql-5.6.35-linux-glibc2.5-x86_64.tar.gz 2、创建mysql用户 先创建mysql…

【c语言指针详解】复杂数据结构的指针用法

目录 一、动态内存分配 1.1 使用malloc和free函数进行内存的动态分配和释放 1.2 内存泄漏和野指针的概念和解决方法 二、复杂数据结构的指针用法 2.1 结构体指针和成员访问操作符 2.2 指针数组和指向指针的指针 2.2.1 指针数组 2.2.2 指向指针的指针 2.3 动态内存分配与结构体指…

Vue项目解决van-calendar 打开下拉框显示空白(白色),需滑动一下屏幕,才可正常显示

问题描述&#xff0c;如图 ipad(平板&#xff09;或者 H5移动端引入Vant组件的日历组件&#xff08;van-calendar&#xff09;&#xff0c;初始化显示空白&#xff0c;需滚动一下屏幕&#xff0c;才可正常显示 解决方法 需在van-calendar上绑定open"openCalendar"事件…

应用层自定义协议

文章目录 一、前言二、应用层自定义协议三、通用协议格式3.1 xml3.2 josn3.3 protobuffer 后端开发必须掌握的知识点&#xff01; 一、前言 应用层主要是干嘛的呢&#xff1f;&#xff1f; 应用层协议定义了应用程序之间通信的规则和标准。定义了数据的格式、数据交换的标准和…

第74讲:MySQL数据库InnoDB存储引擎事务:Redo Log与Undo Logo的核心概念

文章目录 1.InnoDB引擎中的逻辑存储结构2.事务的基本概念3.Redo log的核心概念3.1.什么是Redo log3.2.如果没有redo log面临的问题3.3.使用redo log之后是怎样的流程 4.Undo log的核心概念 1.InnoDB引擎中的逻辑存储结构 InnoDB存储引擎的逻辑结构分为以下几层&#xff1a; Ta…