选择排序(二)——堆排序(性能)与直接选择排序

fe594ea5bf754ddbb223a54d8fb1e7bc.gif

目录

一.前言

二.选择排序

2.1 堆排序

2.2选择排序

2.2.1 基本思想

2.2.2直接选择排序

三.结语


8fb442646f144d8daecdd2b61ec78ecd.png一.前言

本文给大家带来的是选择排序,其中选择排序中的堆排序在之前我们已经有过详解所以本次主要是对比排序性能,感兴趣的友友可移步观看堆排:https://mp.csdn.net/mp_blog/creation/editor/133394741

码字不易,希望大家多多支持我呀!(三连+关注,你是我滴神!)

二.选择排序

2.1 堆排序

堆排序是值利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序要建小堆。

堆排序具体详解可以参考这篇文章:https://mp.csdn.net/mp_blog/creation/editor/133394741

们这里就先来测试一下堆排序与希尔的效率比较。

堆排序代码:

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;
		}
	}
}

void HeapSort(int* a, int n)
{
	// 向下调整建堆
	// O(N)
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}

	// O(N*logN)
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		--end;
	}
}

 这是通过生成100000个随机值测试用的代码片段。

void TestOP()
{
	srand(time(0));
	const int N = 100000;
	int* a1 = (int*)malloc(sizeof(int) * N);
	int* a2 = (int*)malloc(sizeof(int) * N);
	int* a3 = (int*)malloc(sizeof(int) * N);
	int* a4 = (int*)malloc(sizeof(int) * N);
	int* a5 = (int*)malloc(sizeof(int) * N);
	int* a6 = (int*)malloc(sizeof(int) * N);
	int* a7 = (int*)malloc(sizeof(int) * N);

	for (int i = 0; i <N; i++)
	{
		a1[i] = rand();
		a2[i] = a1[i];
		a3[i] = a1[i];
		a4[i] = a1[i];
		a5[i] = a1[i];
		a6[i] = a1[i];
		a7[i] = a1[i];
	}

	int begin1 = clock();
	//InsertSort(a1, N);
	int end1 = clock();

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

	int begin7 = clock();
	//BubbleSort(a7, N);
	int end7 = clock();

	int begin3 = clock();
	//SelectSort(a3, N);
	int end3 = clock();

	int begin4 = clock();
	HeapSort(a4, N);
	int end4 = clock();

	int begin5 = clock();
	//QuickSort(a5, 0, N - 1);
	int end5 = clock();

	int begin6 = clock();
	//MergeSort(a6, N);
	int end6 = clock();

	printf("InsertSort:%d\n", end1 - begin1);
	printf("ShellSort:%d\n", end2 - begin2);
	printf("BubbleSort:%d\n", end7 - begin7);

	printf("SelectSort:%d\n", end3 - begin3);
	printf("HeapSort:%d\n", end4 - begin4);
	printf("QuickSort:%d\n", end5 - begin5);
	printf("MergeSort:%d\n", end6 - begin6);

	free(a1);
	free(a2);
	free(a3);
	free(a4);
	free(a5);
	free(a6);
	free(a7);
}

int main()
{
	TestOP();
	//TestBubbleSort();
	//TestHeapSort();
	//TestSelectSort();

	return 0;
}

测试完发现两者算法效率差不多

但是这里面是有一个前提的,就是里面很多数都是重复的,rand函数最多只能产生3万个不同的随机数。当我们追加数字到1亿个时:

堆排序还是会占有优势的。

而在逆序或顺序的情况下,希尔的效率会更高

for (int i = N-1; i >= 0; --i)
	{
		a1[i] = i;
		a2[i] = a1[i];
		a3[i] = a1[i];
		a4[i] = a1[i];
		a5[i] = a1[i];
		a6[i] = a1[i];
		a7[i] = a1[i];
	}

2.2选择排序

2.2.1 基本思想

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

2.2.2直接选择排序

  • 在元素集合arr[i]--arr[n-1] 中选择关键码最大(小)的数据元素
  • 若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
  • 在剩余的arr[i]--arr[n-2](arr[i+1]--arr[n-1])集合中,重复上述步骤,直到集合剩余1个元素

这是正常版本,下面我们来搞一个优化版,遍历一次来选出最小和最大的。把最小放在左边,最大放在右边。

老规矩先实现单趟代码:走完一遍后标记好最大和最小

void SelectSort(int* a, int n)
{
	//单趟排序
	int maxi = 0;
	int mini = 0;
	for (int i = 1; i < n; i++)
	{
		//在单趟里找出最大最小两个数
		if (a[i] > a[maxi])
		{
			maxi = i;
		}
		if (a[i] < a[mini])
		{
			mini = i;
		}
	}

}

void SelectSort(int* a, int n)
{
	//整体排序与交换
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		//单趟排序
		int maxi = begin;
		int mini = begin;
		for (int i = begin+1; i <=end; i++)
		{
			//在单趟里找出最大最小两个数
			if (a[i] > a[maxi])
			{
				maxi = i;
			}
			if (a[i] < a[mini])
			{
				mini = i;
			}
		}
		Swap(&a[begin], &a[mini]);
		Swap(&a[end], &a[maxi]);

		begin++;
		end--;
	}
}

走完单趟找出最大值与最小值的时候就开始进行交换,按最小值放右边,最大值放左边的原则。

这里我们统一把最左边设成begin,最右边设置成end。

而整体排序的核心就在于begin与end的变化,在我们的for循环里i的范围是由begin与end来控制的,这代表我们从[begin,end]里寻找最大与最小值

当把该趟的最大最小放置在两侧后,对排序范围进行缩减通过begin++与end--的方式圈定排序范围,那么我们的下一次单趟范围就在[begin+1,end-1]之间寻找最大与最小,再放置在两侧(最小在begin+1处,最大在end-1处)。

就这样以此类推,两侧就会开始形成序列达到排序的效果。

但这样还不够完整,经过调试我们发现还无法排序,因为还有一个小bug

最开始我们是mini与begin交换即9与1交换,后面按理应该是end与maxi交换,但此时因为9与1交换导致原本指向最大9的maxi不再指向9,而是交换过来的1,导致最后一步是3与1进行交换,所以才会无法排序。

void SelectSort(int* a, int n)
{
	//整体排序与交换
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		//单趟排序
		int maxi = begin;
		int mini = begin;
		for (int i = begin+1; i <=end; i++)
		{
			//在单趟里找出最大最小两个数
			if (a[i] > a[maxi])
			{
				maxi = i;
			}
			if (a[i] < a[mini])
			{
				mini = i;
			}
		}
		Swap(&a[begin], &a[mini]);
		if (maxi == begin)
		{
			maxi = mini;
		}
		Swap(&a[end], &a[maxi]);

		begin++;
		end--;
	}
}

所以我们添加一步判断,如果maxi与begin是重合的情况下,在mini与begin交换后重新把指向最大值的mini赋值给maxi即可。

时间复杂度:

第一次是n个数中找2个数,后面是n-2,n-4.....1等差数列,所以时间复杂度为O(N^2)

下面我们来看一下选择与各个排序之间效率高低

在1万个数据中选择排序甚至比不上冒泡排序

那我们再试试有大量重复数据的情况

在重复数据多的情况下,选择还是优于冒泡的。

4b12323f94834afd9ec146a3c10df229.jpeg三.结语

本文的选择排序中也许直接选择排序并没有其他排序那么惊艳甚至会有时被冒泡压上一筹,但它还是有自己的闪光点的,其次是堆排序,在排序效率上与希尔差不多,个别情况也会比希尔高效,这是目前学习过程不容小觑的一类排序算法。因为本文只给了堆排的效率演示具体详解还请友友们移步我之前的文章重新认识一下堆排序~最后感谢大家的观看,友友们能够学习到新的知识是额滴荣幸,期待我们下次相见~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录二刷 | 回溯| 电话号码的字母组合

代码随想录二刷 &#xff5c; 回溯&#xff5c; 电话号码的字母组合 题目描述解题思路数字和字母如何映射回溯法来解决n个for循环的问题 代码实现 题目描述 17&#xff0c;电话号码的字母组合 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。 给出…

蓝桥杯官网填空题(奇怪的分式)

题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 上小学的时候&#xff0c;小明经常自己发明新算法。一次&#xff0c;老师出的题目是&#xff1a;1/4乘以8/5 小明居然把分子拼接在一起&#xff0c;分母拼接在一起&…

mybatis的缓存机制

视频教程_免费高速下载|百度网盘-分享无限制 (baidu.com) MyBatis 有一套灵活而强大的缓存机制&#xff0c;主要分为两级缓存&#xff1a;一级缓存&#xff08;本地缓存&#xff09;和二级缓存&#xff08;全局缓存&#xff09;。 一级缓存&#xff08;本地缓存&#xff09;&a…

赛氪受邀参加安徽省翻译协会2023年年会

安徽省翻译协会于近日在合肥成功举办2023年年会暨学术研讨会。本次会议旨在服务党和国家工作大局&#xff0c;广泛汇聚翻译界力量&#xff0c;推动翻译行业高质量发展&#xff0c;同时总结一年来我省翻译界成果&#xff0c;谋划明年工作。 安徽省翻译协会2023年年会暨学术研讨会…

学会一些品酒词汇显得有文化

日常聚会饮用葡萄酒或者参加品鉴酒会时&#xff0c;我们经常可以听到人们使用非常专业的词汇如“单宁顺滑”、“紧涩”或者“酸度活泼”等等。品酒词不仅可以帮助我们更好地去认识了解一款葡萄酒&#xff0c;也能更好地表达我们对一款葡萄酒的感受和看法。学会一些专业品酒词汇…

deepin20.9设置root登录

首先设置root 账户密码 sudo passwd root创建 /etc/lightdm/lightdm-deepin-greeter.conf&#xff0c;输入以下内容 sudo touch /etc/lightdm/lightdm-deepin-greeter.conf sudo deepin-editor /etc/lightdm/lightdm-deepin-greeter.conf [General] loginPromptInputtrue别忘…

unity 单例模式(实例详解)

文章目录 在Unity中&#xff0c;单例模式是一种常用的编程设计模式&#xff0c;用于确保在整个应用程序生命周期中&#xff0c;只有一个类的实例存在。这样可以保证数据的全局唯一性和共享性&#xff0c;例如游戏场景中的资源管理器、游戏控制器、事件管理器等。 以下是一个简单…

海外抖音TikTok、正在内测 AI 生成歌曲功能,依靠大语言模型 Bloom 进行文本生成歌曲

近日&#xff0c;据外媒The Verge报道&#xff0c;TikTok正在测试一项新功能&#xff0c;利用大语言模型Bloom的AI能力&#xff0c;允许用户上传歌词文本&#xff0c;并使用AI为其添加声音。这一创新旨在为用户提供更多创作音乐的工具和选项。 Bloom 是由AI初创公司Hugging Fac…

vue3相比vue2的效率提升

1、静态提升 2、预字符串化 3、缓存事件处理函数 4、Block Tree 5、PatchFlag 一、静态提升 在vue3中的app.vue文件如下&#xff1a; 在服务器中&#xff0c;template中的内容会变异成render渲染函数。 最终编译后的文件&#xff1a; 1.静态节点优化 那么这里为什么是两部分…

2024年图像处理与大数据信息应用国际会议(ICIPCDIA 2024)

2024年图像处理与大数据信息应用国际会议(ICIPCDIA 2024) 2024 International Conference on Image Processing and Big Data Information Applications(ICIPCDIA 2024) 数据库&#xff1a;EI,CPCI,CNKI,Google Scholar等检索 一、【会议简介】 ​2024年图像处理与大数据信息应…

Qt网络通信

1. UDP通信 1.1 udp通信的基本流程 创建套接字 绑定套接字 进行通信 关闭套接字 涉及到的类和信号 QUdpSocket&#xff1a;Udp套接字类&#xff0c;类对象就是一个udp套接字对象 QHostAddress&#xff1a;ip地址类 void readyRead()&#xff1a;信号&#xff0c;当有数据到达可…

曲线生成 | 图解三次样条曲线生成原理(附ROS C++/Python/Matlab仿真)

目录 0 专栏介绍1 什么是样条&#xff1f;2 三次样条曲线原理2.1 曲线插值2.2 边界条件2.3 系数反解 3 算法仿真3.1 ROS C仿真3.2 Python仿真3.3 Matlab仿真 0 专栏介绍 &#x1f525;附C/Python/Matlab全套代码&#x1f525;课程设计、毕业设计、创新竞赛必备&#xff01;详细…

vue3-图片懒加载指令实现

图片懒加载&#xff1a;有些网站页面比较长&#xff0c;用户不一定访问到页面靠下面的图片&#xff0c;这类图片通过懒加载优化手段可以做到只有进入视口区域才发送图片请求 指令用法 //在图片img身上绑定指令&#xff0c;该图片只有正式进入到视口区域时才会发送图片网络请求…

腾讯云tsf平台-部署微服务项目

腾讯云tsf平台-部署微服务项目 一、腾讯云tsf平台简介二、部署准备0&#xff08;数据库、中间件等部署&#xff09;三、部署准备1&#xff08;创建集群和命名空间&#xff09;1、准备部署资源--集群2、使用容器部署微服务步骤 1&#xff1a;创建容器集群步骤 2&#xff1a;创建…

Linux服务部署,遇到的各种问题之一(测试篇)

最近服务器需要搬迁&#xff0c;所有的服务都需要迁移&#xff0c;从初始化数据盘&#xff0c;到服务部署的各种细节&#xff0c;下面我们一一来说 初始化数据盘就不用说了&#xff0c;大概率&#xff0c;作为测试接触不到。 今天来说是ubuntu显示的中文文件乱码问题如何解决…

Spring 事务原理一

从本篇博客开始&#xff0c;我们将梳理Spring事务相关的知识点。在开始前&#xff0c;想先给自己定一个目标&#xff1a;通过此次梳理要完全理解事务的基本概念及Spring实现事务的基本原理。为实现这个目标我想按以下几个步骤进行&#xff1a; 讲解事务中的一些基本概念使用Sp…

NTFS 磁盘管理器---NTFS Disk by Omi NTFS中文

NTFS Disk by Omi NTFS是一款专为Mac用户设计的NTFS磁盘管理工具。它可以帮助用户方便地访问和管理NTFS格式的硬盘、U盘、移动硬盘以及其他存储设备&#xff0c;并提供高效稳定的NTFS卷管理功能。该软件具有简单的用户界面&#xff0c;使用户能够快速访问和管理NTFS磁盘上的文件…

1.2 数据模型

数据模型是对现实世界数据特征的抽象&#xff0c;是现实世界的模拟 数据模型是用来描述数据、组织数据和对数据进行操作的 数据模型应满足三方面要求&#xff1a; 1 能比较真实地模拟现实世界 2 容易为人所理解 3 便于在计算机上实现 数据模型…

python算法与数据结构(搜索算法和拓扑排序算法)---深度优先搜索

课程目标 了解树/图的深度遍历&#xff0c;宽度遍历基本原理&#xff1b;会使用python语言编写深度遍历&#xff0c;广度遍历代码&#xff1b;掌握拓扑排序算法 搜索算法的意义和作用 搜索引擎 提到搜索两个子&#xff0c;大家都应该会想到搜索引擎&#xff0c;搜索引擎的基…

决策树的分类

概念 决策树是一种树形结构 树中每个内部节点表示一个特征上的判断&#xff0c;每个分支代表一个判断结果的输出&#xff0c;每个叶子节点代表一种分类结果 决策树的建立过程 1.特征选择&#xff1a;选取有较强分类能力的特征。 2.决策树生成&#xff1a;根据选择的特征生…