选择排序(直接选择排序与堆排序)----数据结构-排序②

news2025/1/21 0:54:22

1、选择排序

1.1 基本思想

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

1.2 直接选择排序

排序思想:

①在元素集合array[i]--array[n-1]中选择数值最大(小)的数据元素。

②若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换,使最大(最小)的元素来到数据的最后(开始)。

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

动图演示:

 动图解释:

①遍历区间 [ 0, n-1 ] 的所有数,选出最小的数放到我们所遍历区间的最左端,第一次遍历区间最左端是0。

②遍历区间 [ 1, n-1 ] 的所有数,选出最小的数放到我们所遍历区间的最左端,第而二次遍历区间最左端是1。

③不断重复上述步骤,直至区间内的元素个数为一个时,停止遍历。

代码实现:

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}


void SelectSort2(int* a, int n)
{
	int begin = 0, end = n - 1;
	// 区间为 [begin , end]
	while (begin < end)  // 当 begin == end 时,表明区间内还剩一个元素,停止遍历
	{
		// 假设最小值都为区间的最左端元素
		int mini = begin;

		for (int i = begin + 1; i <= end; i++)
		{
			// 在区间内遇到更小的数就更新 mini
			if (a[i] < a[mini])
				mini = i;
		}
		// 第一次遍历结束,mini位置的值为该区间的最小值 
		Swap(&a[begin], &a[mini]);// 将最小值放到该区间的最左端

		// 缩小区间的长度
		begin++;
	}
}

代码优化:

        实际上在每一次的遍历中,我们不仅可以选出最小值放到区间的最左端,同时我们还可以选出最大值放到区间的最右端,这样可以减少我们的遍历次数。 

优化代码实现:

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;
	// 区间为 [begin , end]
	while(begin < end)  // 当 begin == end 时,表明区间内还剩一个元素,停止遍历
	{
		// 假设最大值与最小值都为区间最左端元素
		int maxi = begin, mini = begin;
		for (int i = begin + 1; i <= end; i++)
		{
			// 在区间内遇到更大的数就更新 maxi
			if (a[i] > a[maxi])
				maxi = i;

			// 在区间内遇到更小的数就更新 mini
			if (a[i] < a[mini])
				mini = i;
		}
		// 第一次遍历结束,maxi、mini位置的值为该区间的最大值与最小值 
		Swap(&a[begin], &a[mini]);// 将最小值放到该区间的最左端

		// 当我们的区间最大值位于 begin 位置时,即maxi = begin时
		//因为我们上面的交换,导致begin位置的值已经被换到 mini 位置
		//所以现在最大值的下标是 mini

		if (maxi == begin)//当最大的数据在 begin 位置时,
			maxi = mini; 

		Swap(&a[end], &a[maxi]); // 将最大值放到该区间的最右端

		// 缩小区间的长度
		begin++;
		end--;
	}
}

 直接选择排序的特性总结:

1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用

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

3. 空间复杂度:O(1)

4. 稳定性:不稳定

不稳定的原因:当数组已经接近有序或已经完全有序时,每一次还是会进行找大找小,这样就会导致时间上的巨大浪费。

1.3 堆排序

       堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种,但相较于直接选择排序来说提升了许多 。它是通过堆(完全二叉树)来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。(如果还未学习堆的同学,可以移步到我的上一篇文章,里面有堆的详细介绍)

堆排序的排序思想:

如果我们想利用堆排升序:

①首先我们需要建立一个有N个数据的大堆;

②将堆顶的数据(最大)与最后一个数据(下标是N-1)交换,此时我们最大的数据就来到了最后(N-1的位置),这时我们就不用再需要去考虑最后一个元素了,因为最后一个元素已经是最大;

③再对前N-1个数据再次进行堆排序即可。

注意:此刻交换到堆顶的数据并不一定满足大堆的性质,所以还需要对堆顶的数据进行向下调整,使得满足大堆的性质。
 

示意图:


void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
 
void AdjustDown(HPDataType* a, int size,int parent)
{
	int child = 2 * parent + 1;
	while (child < size)
	{
		if ((child + 1) < size && a[child + 1] > a[child])  // 找出左右孩子中较大一个
		{
			child++;
		}
		if (a[parent] < a[child])   // 如果孩子更大就交换,并且更新父节点与孩子节点
		{
			Swap(&a[parent], &a[child]);
			parent = child;
			child = 2 * parent + 1;
		} 
		else     // 如果父节点更大表明不用再交换了 ,跳出循环
		{
			break;
		}
	}
}
 
void HeapSort(int* a, int n)
{
	// 利用向下调整算法建立一个大堆
	for (int i = (n - 1-1) / 2; i >= 0; i--)  // n-1 是最后一个节点,(n-1-1)/2就是第一个非叶子节点
	{
		AdjustDown(a, n,i);
	}
    int end = n-1;  // end 表示最后一个元素的下标
	while(end>0)  //如果数据个数大于1个,才进行排序
	{
		Swap(&a[0], &a[end]);   // 堆顶与最后一个元素进行交换
		AdjustDown(a, end, 0); // 将堆顶的数据向下调整
		end--;           // 每排好一个就不用再考虑最后一个元素,相当与堆的数据减少一个
	}
}

堆排序的特性总结: 

1. 堆排序使用堆来选数,效率就高了很多

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

3. 空间复杂度:O(1)

4. 稳定性:不稳定

不稳定的原因与直接选择排序类似,当数组已经有序或接近有序时,还需要建堆从而导致已经有序或接近有序的数据又会被从新打乱进行排序,同样会造成时间上的浪费。

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

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

相关文章

FM148A,FM146B运行备件

FM148A,FM146B运行备件。电源保险丝仓主控底座的保险丝仓示意图底座上共有两个保险丝&#xff08;800mA&#xff09;&#xff0c;FM148A,FM146B运行备件。&#xff08;10&#xff5e;73&#xff09;30/195主控单元2.K-CUT014槽底座地址接口主控站地址拨开关从上到下为二进制数的…

Day46 代码随想录打卡|二叉树篇---从中序与后序遍历序列构造二叉树

题目&#xff08;leecode T106&#xff09;&#xff1a; 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 方法&#xff1a;本题要通过中序遍历和后…

Windows无法安装到这个硬盘空间。选定的分区上启用了BitLocker驱动器加密。请在控制面板中暂停(也称为禁用)BitLocker,然后重新开始安装。

我们安装操作系统的时候&#xff0c;到了选择安装分区的地方&#xff0c;我们选中的分区提示“无法在驱动器的分区上安装Windows”&#xff0c;然后我们点击显示详细信息&#xff0c;提示如图下所示 分析原因&#xff0c;可能是之前的分区未进行格式化。但是这个时候我们无法格…

基于51单片机水塔水位控制系统

基于51单片机水塔水位控制 &#xff08;仿真&#xff0b;程序&#xff09; 功能介绍 具体功能&#xff1a; 1.用滑动变阻器模拟水位&#xff0c;ADC0809将模拟信号转换为数字信号&#xff1b; 2.LCD1602显示当前水位和水位阈值&#xff1b; 3.当水位超过设定阈值&#xff…

STM32智能小车学习笔记(避障、循迹、跟随)

我们使用的是STM32CubeMX软件和MDK5 芯片使用的是STM32F103C8T6 完成对STM32CubeMX的初始化后开始我们的第一步点亮一个LED灯 一、点亮LED灯 点亮PC13连接的灯 打开STM32CubeMX软件&#xff0c;pc13设置为输出模式 然后按照这样配置&#xff0c;user label 设置成这个IO口代…

Go微服务: 关于消息队列的选择和分类以及使用场景

消息队列概述 在分布式系统和微服务架构中&#xff0c;消息队列&#xff08;Message Queue&#xff09;是一个核心组件&#xff0c;用于在不同的应用程序或服务之间异步传递消息在 Go 语言中&#xff0c;有多种实现消息队列的方式&#xff0c;包括使用开源的消息队列服务&…

2024 年最全的 21 款数据恢复工具软件汇总

使用其中任何一款免费数据恢复工具&#xff0c;您都可以找回那些您认为已经永远消失的文件。我根据这些程序对我而言的易用性和它们提供的功能对这些程序进行了排名。 这些应用程序从您的硬盘、USB 驱动器、媒体卡等恢复文档、视频、图像、音乐等。我建议每个计算机所有者都安装…

附录二-nmap基本用法

参考 黑客工具—Nmap的使用_哔哩哔哩_bilibili nmap是扫描IP和端口的&#xff0c;相当于攻击前的索敌步骤。不止网络安全方面会用到&#xff0c;平时运维的时候也会用到nmap 1 下载nmap nmap官网 https://nmap.org/ 点击下载&#xff0c;然后点你用的平台就行了 往下滚可以…

[职场] 硬件研发是什么职业 #职场发展#其他

硬件研发是什么职业 硬件研发工程师需要具备丰富的电子电路知识、熟练掌握各种电子元器件的性能及应用、具备一定的机械结构设计能力&#xff0c;同时还要具备良好的团队协作和沟通能力。本文会进行详细介绍。 一、硬件研发是什么 硬件研发&#xff0c;全称硬件研发工程师&am…

一文搞懂Python的异常

人生之事,不如意者十之有九。 在编程中亦是如此。异常(Exception),遍布于程序各个角落,开发工作的大部分coding,都是为了应对和解决它。 概念 异常,简而言之,是程序在执行期间发生的非预期的、非正常的事件或情况。 举个实际生活的例子: 你周末出门买大龙虾,但当你…

Vue-App桌面程序列表

Vue-App桌面程序列表 文章说明讲解视频核心代码效果展示项目链接 文章说明 采用Vue实现PC端的桌面程序列表&#xff0c;采用HBuilderX将程序转化为5App&#xff0c;实现移动端的适配&#xff1b;支持桌面打开新应用&#xff0c;底部导航展示当前应用列表&#xff0c;可切换或关…

用你熟悉的语言就能开发智能合约,Vara Network 以 WASM 解锁未来应用创新

Vara Network 自推出以来&#xff0c;凭借其基于 Gear Protocol 的独特架构和强大的开发工具&#xff0c;为开发者提供了一个高效、安全的智能合约构建平台。Vara Network 通过采用先进的 Actor 模型、持久内存概念和 WebAssembly 技术&#xff0c;实现了异步消息处理、并行计算…

在线OJ项目测试(selenium+Junit5)

目录 在线OJ项目测试的思维导图 在线OJ的UI自动化测试 测试一&#xff1a;检查未登录时的页面访问以及一些未登录时的非法操作 测试二&#xff1a;测试注册界面 测试三&#xff1a;测试登录界面 测试四&#xff1a;测试题目列表界面 测试五&#xff1a;测试题目详情界面…

Android Kotlin 异步操作回调转换为挂起函数

异步接口回调是一种通过接口将任务的执行和结果处理分离开来的编程设计模式。通常用于网络请求、数据库查询等耗时操作。 挂起函数是 Kotlin 中的一个特性&#xff0c;用于简化异步编程。挂起函数是可以在协程中暂停执行并恢复的函数&#xff0c;避免了回调地狱问题&#xff0…

php质量工具系列之PHPCPD

PHPCPD 用于检测重复代码&#xff0c;直观的说就是复制粘贴再稍微改改 该工具作者已经 停止维护 安装 composer global require --dev sebastian/phpcpd执行 phpcpd --log-pmd phpcpd_result.xml ./app参数介绍 --log-pmd 将结果保存在phpcpd_result.xml 中 ./app 是phpcpd扫…

linux系统PXE自动装机和无人值守

一、PXE 1.PXE&#xff1a;c/s模式&#xff0c;允许客户端通过网络从远程服务器&#xff08;服务端&#xff09;下载引导镜像&#xff0c;加载安装文件&#xff0c;实现自动化安装操作系统。&#xff08;c/s客户端和服务端都可以是多台&#xff09; 2.PXE优点&#xff1a;规模…

【机器学习基础】Python编程08:五个实用练习题的解析与总结

Python是一种广泛使用的高级编程语言,它在机器学习领域中的重要性主要体现在以下几个方面: 简洁易学:Python语法简洁清晰,易于学习,使得初学者能够快速上手机器学习项目。 丰富的库支持:Python拥有大量的机器学习库,如scikit-learn、TensorFlow、Keras和PyTorch等,这些…

基于STM32开发的智能家居监控系统

目录 引言环境准备智能家居监控系统基础代码实现&#xff1a;实现智能家居监控系统 4.1 传感器数据读取4.2 电器设备控制4.3 实时数据监控与分析4.4 用户界面与数据可视化应用场景&#xff1a;家庭安全监控与管理问题解决方案与优化收尾与总结 1. 引言 随着智能家居技术的发…

AI绘画中的图像格式技术

在数字艺术的广阔天地里&#xff0c;AI绘画作为一种新兴的艺术形式&#xff0c;正在逐渐占据一席之地。不同于传统绘画&#xff0c;AI绘画依赖于复杂的算法和机器学习模型来生成图像&#xff0c;而这一切的背后&#xff0c;图像格式技术发挥着至关重要的作用。图像格式不仅关系…

23 二叉搜索树

本节目标 1.内容安排说明 2.二叉搜索树实现 3.应用分析 4.进阶题 1. 内容安排说明 二叉树在c数据结构已经说过了&#xff0c;本节内容是因为&#xff1a; map和set特性需要先铺垫二叉搜索树&#xff0c;而二叉搜索树也是一种树形结构二叉搜索树的特性了解&#xff0c;有助于…