排序算法:选择排序(直接选择排序、堆排序)

news2024/11/25 22:28:40

朋友们、伙计们,我们又见面了,本期来给大家解读一下有关排序算法的相关知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!

C 语 言 专 栏:C语言:从入门到精通

数据结构专栏:数据结构

个  人  主  页 :stackY、

 

目录

前言:

1.选择排序 

1.1基本思想

1.2直接选择排序

::算法思路 

::直接排序算法完整代码

1.3直接选择排序算法特性 

 2.堆排序

::堆排序算法完整代码

 2.1堆排序算法特性

 3.算法效率比较


前言:

承接这一篇文章:排序算法:插入排序(直接插入排序、希尔排序)在这篇文章中我们了解过了排序算法的种类以及如何实现插入排序,那么在这一期的文章中,我们再来学习一下新的排序算法:选择排序。

1.选择排序 

1.1基本思想

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

1.2直接选择排序

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

②若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换

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

 简而言之(排升序)就是在全部的数据中选择出最小的依次放在前面的位置,来完成排序。

 这样的排序方式一次只可以选择一个数据,我们可以再次基础上进行改良,我们可以一次选择排序两个数据:设置两个下标,前面的下标从前往后找最小的数,后面的下标从后往前找最大的数,依次进行排序,这种方法明显是比前面的方法更优,那么我们就来入手这个算法:

::算法思路 

首先呢,我们需要有两个起始的下标,一个下标在数据的开头,一个下标在数据的末尾,然后需要再来两个下标来记录最大值和最小值,将记录最大最小值的下标初始设置为第一个输一局,紧接着开始进行一趟的比较,在数据开头的下标从头开始往后遍历跟最小值进行比较然后找到最小值,在数据末尾的下标从后往前开始遍历于最大值进行比较找到最大值,然后将最小值与开头的第一个值进行交换,将最大值与末尾的值进行交换,这样子就将最小值排到了最前面,将最大值排到了最后面,然后将区间缩小,开头的下标++变为新的开头,末尾的下标--变为新的末尾,然后进行新一轮的比较,当开头和下标和末尾的下标重合即可结束排序。

代码演示:

 

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

//选择排序
//排升序
void SelectSort1(int* a, int n)
{
	int begin = 0, end = n - 1;

	while (begin < end)
	{
		//一趟选择排序
	//先将第一个值设置为最大值和最小值
		int mini = begin, maxi = begin;
		//遍历整个数据
		for (int i = begin; i <= end; i++)
		{
			//找到最小值的下标
			if (a[i] < a[mini])
			{
				mini = i;
			}
			//找到最大值的下标
			if (a[i] > a[maxi])
			{
				maxi = i;
			}
		}
		//将最小值放到开头
		Swap1(&a[begin], &a[mini]);

		//将最大值放到末尾
		Swap1(&a[end], &a[maxi]);
		//缩小区间
		begin++;
		end--;
	}
}

我们可以用一组数据来演示一下:9,8,5,6,3,2,1,4,7,0

 可以发现,本次排序结果并不是我们想要的结果,那这是什么原因呢?我们可以通过调试来发现问题:

所以当为了防止begin和maxi重叠这种特殊情况的发生,在完成第一次交换之后,此时mini的位置就是最大值的位置,所以直接将mini赋给maxi,即可完成正确的交换。

优化代码: 

::直接排序算法完整代码

 

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

//选择排序
//排升序
void SelectSort1(int* a, int n)
{
	int begin = 0, end = n - 1;

	while (begin < end)
	{
		//一趟选择排序
	//先将第一个值设置为最大值和最小值
		int mini = begin, maxi = begin;
		//遍历整个数据
		for (int i = begin; i <= end; i++)
		{
			//找到最小值的下标
			if (a[i] < a[mini])
			{
				mini = i;
			}
			//找到最大值的下标
			if (a[i] > a[maxi])
			{
				maxi = i;
			}
		}
		//将最小值放到开头
		Swap1(&a[begin], &a[mini]);

		//如果begin和maxi重叠,需要进行修正
		if (begin == maxi)
		{
			maxi = mini;
		}

		//将最大值放到末尾
		Swap1(&a[end], &a[maxi]);
		//缩小区间
		begin++;
		end--;
	}
}

1.3直接选择排序算法特性 

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

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

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

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

4. 稳定性:不稳定

 2.堆排序

堆排序在之前的文章都有所介绍,在这里就直接上手,如果有什么不懂的可以去看之前的文章:排序算法:堆排序

我们知道堆排序最优的方法是向下调整建堆,在建堆时要注意的点就是:排降序建小堆,排升序建大堆、向下调整算法使用的前提是向下调整的结点的下面必须是堆。

::堆排序算法完整代码

//交换函数
void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

//向下调整
void AdjustDown(int* a, int n, int parent)
{
	//假设左孩子为左右孩子中最小的节点
	int child = parent * 2 + 1;

	while (child < n)  //当交换到最后一个孩子节点就停止
	{
		if (child + 1 < n  //判断是否存在右孩子
			&& a[child + 1] > a[child]) //判断假设的左孩子是否为最小的孩子
		{
			child++;   //若不符合就转化为右孩子
		}
		//判断孩子和父亲的大小关系
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			//更新父亲和孩子节点
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//O(N * logN)
void HeapSort(int* a, int n)
{
	//建堆--向下调整算法建堆
	//时间复杂度为O(N)
	for (int i = ((n - 1) - 1) / 2; i >= 0; --i)
	{//       这里的n-1表示最后一个叶子节点
		//       最后一个叶子节点的父亲就是:
		//           (n-1)-1/2;
		AdjustDown(a, n, i);
	}

	//O(N * logN)
	int end = n - 1;
	while (end > 0)
	{
		//交换堆顶和最后一个数据的位置
		Swap(&a[0], &a[end]);
		//向下调整,找次小的
		AdjustDown(a, end, 0);
		end--;
	}
}

 2.1堆排序算法特性

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

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

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

4. 稳定性:不稳定

 3.算法效率比较

比较算法的快慢我们依旧使用这样的一段代码来进行检测:

// 测试排序的性能对比
void TestOP()
{
	srand(time(0));
	const int N = 100000;
	int* a1 = (int*)malloc(sizeof(int) * N);
	int* a2 = (int*)malloc(sizeof(int) * N);

	for (int i = 0; i < N; ++i)
	{
		a1[i] = rand();
		a2[i] = a1[i];
	}

	int begin1 = clock();
	SelectSort1(a1, N);
	int end1 = clock();


	int begin2 = clock();
	HeapSort(a2, N);
	int end2 = clock();

	

	printf("SelectSort1:%d\n", end1 - begin1);
	printf("HeapSort:%d\n", end2 - begin2);

	free(a1);
	free(a2);
}

可以看到堆排序比直接选择排序快了不止100倍,所以在平时呢直接选择排序不会经常使用,我们只需要学习它的思想,然而堆排序是比较好的算法,我们需要熟练掌握。

朋友们、伙计们,美好的时光总是短暂的,我们本期的的分享就到此结束,最后看完别忘了留下你们弥足珍贵的三连喔,感谢大家的支持! 

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

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

相关文章

网络安全人才供需严重失衡,预计2027年缺口将扩大到300万人

网络安全法正式实施5年了。 这5年&#xff0c;是网络安全法治化体系化日趋完善的5年&#xff0c;也是我国网络安全产业黄金发展的5年。 赛迪顾问数据显示&#xff0c;2016年&#xff0c;我国网络安全市场规模为336.2亿元&#xff1b;而2021年&#xff0c;市场规模达到900多亿…

java IO流(四) 数据流 序列化流

数据流 再学习一种流&#xff0c;这种流在开发中偶尔也会用到,我们想把数据和数据的类型一并写到文件中去&#xff0c;读取的时候也将数据和数据类型一并读出来。这就可以用到数据流&#xff0c;有两个DataInputStream和DataOutputStream. DataOutputStream类 写入特定类型 D…

JS 方法实现复制粘贴

背景 以前我们一涉及到复制粘贴功能&#xff0c;实现思路一般都是&#xff1a; 创建一个 textarea 标签 让这个 textarea 不可见&#xff08;定位&#xff09; 给这个 textarea 赋值 把这个 textarea 塞到页面中 调用 textarea 的 select 方法 调用 document.execCommand…

Java逻辑控制

目录 一、顺序结构 二、分支结构 1、if语句 &#xff08;1&#xff09; 语法格式1​编辑 &#xff08;2&#xff09;语法格式2​编辑 &#xff08;3&#xff09;语法格式3 2、switch 语句 三、循环结构 1、while循环 2、break 3、continue 4、for 循环 5、do whil…

Pycharm通用设置个性化设置

Pycharm通用设置&个性化设置 通用设置取消打开Pycharm自动进入项目开启【Ctrl鼠标滑轮】放大缩小字体 个性化设置设置彩虹括号 通用设置 取消打开Pycharm自动进入项目 选择选择菜单【File】>【Settings】进入设置页面选择【Appearance & Behavior】>【System S…

dantax参数调优

dantax参数调优 1.speed调优 可能会导致数据倾斜 处理的速度不同&#xff0c;可能会导致job非常慢 举例子&#xff0c;比如总限速是每秒100条record&#xff0c;其中第一个channel速度是每秒99条record&#xff0c;第二个channel是每秒1条record&#xff0c;加起来是每条100条…

Helm Deploy Online Rancher Demo

文章目录 简介预备条件在线安装 Rancher Helm Chart选择 SSL 配置安装 cert-managerHelm 安装 Rancher验证 Rancher Server 是否部署成功 简介 Rancher 是一个开源的企业级全栈化容器部署及管理平台。已有超过 1900 万次下载&#xff0c;4000 生产环境的应用。 简单的说&…

医院如何选择跨网文件交换产品,提升业务效率?

我国医院根据国家信息安全相关法规要求&#xff0c;大多都采用网闸等隔离手段&#xff0c;将网络隔离为内网和外网&#xff0c;但网络隔离后&#xff0c;医院仍需要进行内外网间的文件交换&#xff0c;如患者的检测报告、学术研究等资料。而医院内的不同科室都存在内外网文件交…

被动元件库存“见底”,或迎涨价潮? | 百能云芯

近日&#xff0c;有消息称被动元件可能会涨价&#xff0c;这促使了被动元件相关股票的全面上涨。国内相关供应链表示&#xff0c;虽然目前没有涨价的条件&#xff0c;但经过长时间的库存消化&#xff0c;各种应用的库存几乎已经清空&#xff0c;只等待终端需求的回升。 自2021年…

软件测试/测试开发丨测试用例自动录入 学习笔记

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27139 测试用例自动录入 测试用例自动录入的价值 省略人工同步的步骤&#xff0c;节省时间 兼容代码版本的自动化测试用例 用例的执行与调度统一化管理…

STM32--蓝牙

本文主要介绍基于STM32F103C8T6和蓝牙模块实现的交互控制 简介 蓝牙&#xff08;Bluetooth&#xff09;是一种用于无线通信的技术标准&#xff0c;允许设备在短距离内进行数据交换和通信。它是由爱立信&#xff08;Ericsson&#xff09;公司在1994年推出的&#xff0c;以取代…

【前端打怪升级日志之CSS篇】position定位

学习链接&#xff1a;阮一峰CSS定位详解 学习总结&#xff1a; 学习应用&#xff1a;待补充。。。

阿里云再推视频生成大模型,2分钟生成高清电影级效果视频

近日&#xff0c;阿里云推出全新视频生成大模型I2VGen-XL&#xff0c;并在魔搭社区开放体验&#xff0c;用户上传一张图片后2分钟左右即可生成一段1280*720的高分辨率视频&#xff0c;该模型研发负责人表示&#xff0c;未来将进一步实现2K超清效果&#xff0c;可应用于短视频内…

懂点心理学 - 踢猫效应

懂点心理学&#xff0c;生活工作两不误&#xff5e; 什么是踢猫效应 某公司董事长为了重整公司事务&#xff0c;许诺自己将早到晚归。有一次&#xff0c;他在家看报太入迷以至于忘记了时间&#xff0c;为了不迟到&#xff0c;他在公路上超速驾驶&#xff0c;结果被警察开了罚单…

Vue + Element UI 实现权限管理系统 前端篇(十四):菜单功能实现菜

Vue Element UI 实现权限管理系统 前端篇&#xff08;十四&#xff09;&#xff1a;菜单功能实现 菜单功能实现 菜单接口封装 菜单管理是一个对菜单树结构的增删改查操作。 提供一个菜单查询接口&#xff0c;查询整颗菜单树形结构。 http/modules/menu.js 添加 findMenu…

微信公众号开发:Vue3+Pinia

步骤一&#xff1a;绑定域名 先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。 步骤二&#xff1a;引入JS文件 在需要调用JS接口 &#xff1a;http://res.wx.qq.com/open/js/jweixin-1.6.0.js npm install weixin-js-sdk 这里报错了。 //…

语音识别数据的采集方法:基本流程数据类型

“人工智能是一种模仿人类功能的产品。数据采集的方法需要针对特定的场景需求。”—–Mark Brayan (澳鹏CEO) 我们一直说&#xff0c;对于一个高质量的人工智能产品离不开高质量的训练数据。对于不同的人工智能我们需要不同的数据对其训练。要采集正确的数据去训练特定的模型才…

float浮动布局大战position定位布局

华子目录 布局方式普通文档流布局浮动布局&#xff08;浮动主要针对与black&#xff0c;inline元素&#xff09;float属性浮动用途浮动元素父级高度塌陷 position属性定位篇相对定位&#xff08;relative为属性值&#xff0c;配合left属性&#xff0c;和top属性使用&#xff09…

快速理解DDD领域驱动设计架构思想-基础篇 | 京东物流技术团队

1 前言 本文与大家一起学习并介绍领域驱动设计(Domain Drive Design) 简称DDD&#xff0c;以及为什么我们需要领域驱动设计&#xff0c;它有哪些优缺点&#xff0c;尽量用一些通俗易懂文字来描述讲解领域驱动设计&#xff0c;本篇并不会从深层大论述讲解落地实现&#xff0c;这…

抄底抄在半山腰?散户如何摆脱追涨杀跌的诅咒?【邢不行】

你第一次炒股的经历是不是这样的&#xff1a; 你有一个朋友甚至是群友&#xff0c;他说在XX股票上大赚了一笔&#xff0c;你听后是既羡慕又不服。 于是你下载了炒股软件&#xff0c;看了眼这只股票&#xff0c;有点心动。但是由于没有交易经验&#xff0c;股价又确实涨了不少…