数据结构之选择排序

目录

直接选择排序

选择排序的时间复杂度

堆排序

向上调整算法

向下调整算法

向上调整算法建立堆

向下调整算法建立堆

堆排序整体代码

堆排序的时间复杂度


直接选择排序

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

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

直接选择排序图示如下:

直接选择排序代码如下:

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.hqwc.cn/news/268333.html

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

相关文章

Linux安装MySQL数据库系统

1、MySQL的编译安装。 1.1、准备工作 &#xff08;1&#xff09;为了避免发生端口冲突、程序冲突等现象&#xff0c;建议先查询MySQL软件的安装情况&#xff0c;确认没有使用以RPM方式安装的mysql-server、mysql软件包&#xff0c;否则建议将其卸载。 [rootlocalhost ~]# rp…

HCIP---RSTP/MSTP

文章目录 目录 文章目录 前言 一.RSTP诞生背景 二.RSTP对比STP的快速收敛机制 端口角色变化 接口状态变化 RSTP-BPDU 指定端口- P/A机制 BPDU发送变化 端口状态快速切换 优化拓扑变更机制 三.MSTP MSTP诞生背景 MSTP相关概念 MSTP配置 总结 前言 STP协议虽然能够解决环…

Weblogic 数据库连接池溢出解决方法

引言 在信息运维工作中发现&#xff0c;由于部分应用系统编写的代码不够健壮&#xff0c;对于数据库连接没有及时进行回收处理&#xff0c;造成Weblogic数据库连接池溢出&#xff0c;影响系统的稳定运行。其实Weblogic提供了数据库连接的回收机制&#xff0c;可以将超过配置时…

企业举办年会,可以邀请哪些媒体进行宣传?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 年关将至&#xff0c;筹办年会成为每个企业必做的事情&#xff0c;也是大家非常期待的年终大会&#xff0c;在我们策划年会时候&#xff0c;也要抓住最后宣传的机会。那么企业举办年会时…

MyBatis-Plus - 论自定义 BaseMapper 方法『逻辑删』失效解决方案

问题描述 在上一篇我们讲过 MyBatis-Plus - 论 1 个实体类被 N 个DAO 类绑定&#xff0c;导致 MP 特性&#xff08;逻辑删&#xff09;失效的解决方案-CSDN博客 所以在这个基础上&#xff0c;我们可以很好定位到源码的分析位置。 但是今天这个问题就更奇怪了&#xff0c;已经…

【Hive】——CLI客户端(bin/beeline,bin/hive)

1 HiveServer、HiveServer2 2 bin/hive 、bin/beeline 区别 3 bin/hive 客户端 hive-site.xml 配置远程 MateStore 地址 XML <?xml version"1.0" encoding"UTF-8" standalone"no"?> <?xml-stylesheet type"text/xsl" hre…

windows如何解决端口冲突(实用篇)

在项目设计中&#xff0c;环境配置成功点击运行瞬间&#xff0c;一大堆红爆出&#xff0c;8080端口占用&#xff0c;这个是很烦人的。。。 解决方式&#xff1a; 笨方法&#xff1a;一、查看所有端口实用情况&#xff08;挨个扫&#xff09; 按住【WINR】快捷键打开运行输入…

Vision Transformer模型架构详解

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

WordPress插件你好多莉( Hello Dolly )可否卸載

什么是你好多莉Hello Dolly WordPress插件 你好多莉是 WordPress插件 简单的预装在 WordPress 上。 如果您激活后者&#xff0c;它将显示出名曲的歌词“ 你好&#xff0c;多莉 “要 路易斯阿姆斯特朗. 您可能已经注意到&#xff0c;在阅读插件说明时&#xff0c;还不够清楚。 …

5G CPE可代替宽带,解决断网问题

最近某运营商就玩起了套餐&#xff0c;断用户的网。 老百姓对宽带半知不解&#xff0c;网络断了没法上网&#xff0c;很着急。因为相信运营商&#xff0c;维修人员怎么说&#xff0c;老百姓就怎么办呗&#xff0c;直到最后才发现自己上当&#xff0c;但钱都给了。 截至2023年9月…

thinkphp 使用array_reduce 处理返回的数据格式

我想要的效果&#xff1a; 不使用array_reduce 的效果 &#xff1a; 代码&#xff1a; public function teamList($userId,$good_id){$nowbuyers $this->order->where(good_id,$good_id)->count();$data GroupTotalOrder::alias(t_order)->where(merchant_Id,$u…

JVM虚拟机系统性学习-运行时数据区(虚拟机栈、本地方法栈)

虚拟机栈 虚拟机栈为每个线程所私有的&#xff0c;如下图&#xff1a; 栈帧是什么&#xff1f; 栈帧存储了方法的局部变量表、操作数栈、动态链接和方法返回地址等信息 栈内存为线程私有的空间&#xff0c;每个方法在执行时都会创建一个栈帧&#xff0c;执行该方法时&…