DS八大排序之直接选择排序和堆排序

前言

上一期我们已经介绍了,排序、为什么要有排序以及排序在实际生活中的应用。并且介绍并实现了直接插入排序和它的优化即希尔排序~!本期我们再来学习一组排序 ---- "选择排序"即直接选择排序和堆排序~!

本期内容介绍

直接选择排序

堆排序

选择排序的基本思想

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

直接选择排序

在元素集合a[i].....a[n-1]中,选择一个最大最小的数据,如果他不是这个序列中的最后一个第一个,则该序列中的最后一个第一个进行交换,将剩余的元素重复上述操作,直到序列的元素只有一个则结束!

OK,举个栗子画个图(这里是以升序距离的):

OK,直接选择排序的过程就是这样的,下面我们来实现一下:还是和以前一样,先写单趟再来改造整体:

单趟

int left = begin;//当前序列的最左端
int min = begin;//最小的元素的下标
for (int i = begin; i < n; i++)
{
	if (a[min] > a[i])
		min = i;
}

Swap(&a[left], &a[min]);//最左端的元素与当前序列中最小的元素交换

整体

直接选择排序改造整体也很简单,只需要,让每个元素都重复单趟即可~!

void SelectSort(int* a, int n)
{
	for (int begin = 0; begin < n; begin++)
	{
		int left = begin;//当前序列的最左端
		int min = begin;//最小的元素的下标
		for (int i = begin; i < n; i++)
		{
			if (a[min] > a[i])
				min = i;
		}

		Swap(&a[left], &a[min]);//最左端的元素与当前序列中最小的元素交换
	}
}

OK,测试一下:

OK,没有问题。这样写实每次找到当前序列中最小的一个,然后与最左端(升序)交换,我们其实可以对他进行一个小优化的--->每次找到当前序列中的两个元素(一个最小,一个最大),最小的与当前序列的最左端交换,最大与当前序列的最右端交换~!

OK,还是先写单趟,在改造多趟:

单趟

int min = begin, max = begin;
for (int i = begin + 1; i <= right; i++)
{
	if (a[min] > a[i])
		min = i;//选出最小

	if (a[max] < a[i])
		max = i;//选出最大
}

Swap(&a[begin], &a[min]);//最小与左端交换
Swap(&a[right], &a[max]);//最大与右端交换

整体

void SelectSort(int* a, int n)
{
	int begin = 0, right = n - 1;
	while (begin < right)
	{
		int min = begin, max = begin;
		for (int i = begin + 1; i <= right; i++)
		{
			if (a[min] > a[i])
				min = i;

			if (a[max] < a[i])
				max = i;
		}

		Swap(&a[begin], &a[min]);
		Swap(&a[right], &a[max]);
		++begin;
		--right;
	}
}

这就是一次选出两个的整体。OK,我们来个栗子测试一下:

怎么没有实现排序呢?是我们的思想有问题???OK,遇事不慌,调试走起:

这是调试找到的第一次最大和最小的元素的下标~!然后下来就是最小与左端交换,最大与右端交换,但此时最大恰好在最左端,一执行最小与最左端交换后在在执行在最大与最右交换时发现最大的已经不在原来的位置了~!这就导致了上述的乱序!

解决方案:在交换完最小与最左端后,判断一下最大的位置,如果最大的是在最左端,则此时最大值应该被换到了最小值的位置,因此,我们只需要调整一下最大值是在最小值的位置即可,即max = min~!

void SelectSort(int* a, int n)
{
	int left = 0, right = n - 1;
	while (left < right)
	{
		int min = left, max = left;
		for (int i = left + 1; i <= right; i++)
		{
			if (a[min] > a[i])
				min = i;

			if (a[max] < a[i])
				max = i;
		}

		Swap(&a[left], &a[min]);
		if (max == left)
			max = min;
		Swap(&a[right], &a[max]);
		++left;
		--right;
	}
}

再来测试一下:

OK,没有问题了~!

复杂度分析

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

单趟无论选择一个还是选择两个,都得遍历一遍,复杂度为O(N),整体还得遍历一遍O(N)

空间复杂度:O(1)

堆排序

堆排序其实在前面的二叉树堆那里已经介绍并实现过了,这来就等于回顾式的再过一遍~!如果想了解堆这种他是具体咋搞的请点击:二叉树的实现

堆排序(Heapsort)是指利用堆,这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据进行实现排序的。

他既然是借助堆来实现的那得有堆,即要建堆。这里有两种建堆的方式:向上调整建堆+向下调整排序,向下调整建堆+向下调整排序!

他排序是采用删除的思想把最大或最小的换到最后,然后对前N-i(i=1,2,3...n)个进行向下调整!
注意:升序建大堆,降序建小堆

OK,举个排序的例子:

向上调整建堆

void HeapSort(HPDataType* a, int n)
{
	//向上调整建堆
	//O(N*lgN)
	for (int i = 1; i < n; i++)
	{
		AdjustUp(a, i);
	}
 
	//向下调整排序
	//O(N*lgN)
	int end = n - 1;
	while (end)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		--end;
	}
}

这里的向上调整建堆和上面堆的插入是一个思路!时间复杂度是O(lgN*N),向下调整排序的时间复杂度是:O(N*lgN)---->有n个元素,每排好一个一下下标,也就是上面的删除的思路!

向下调整建堆

void HeapSort(HPDataType* a, int n)
{
	//向下调整建堆
	//O(N)
	for (int i = (n - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}
 
	//向下调整排序
	//O(N*lgN)
	int end = n - 1;
	while (end)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		--end;
	}
}

向下调整建堆,就是从倒数第一个元素的父节点开始向下调整为堆!这样越往上层节点的左右子树必定是堆!

OK,测试一下:

没问题~!

复杂度分析

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

向下调整和向上调整的时间复杂度都是O(logN)即最多调整高度次,但向上调整建堆是O(N*log)而向下调整建堆的O(N)如下图~!删除排序的时间复杂度是O(N*logN),所以综合下来就是O(N*logN)

空间复杂度:O(1)

向下调整建堆时间复杂度推导

向上调整建堆时间复杂度推导

OK,本期分享就到这里,好兄弟,下期交换排序不见不散~!

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

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

相关文章

【linux防火墙】设置开启路由转发,SNAT和DNAT转换原理及应用实操,添加自定义链归类iptables规则

目录 一、关于iptables规则的保存 1.1持久保存规则 1.2加载规则 1.3开机自动加载规则 1.4使用iptables-service软件来进行规则的保存和加载&#xff08;不建议使用&#xff09; 二、SNAT和DNAT的原理和应用 SNAT的原理与应用&#xff1a; DNAT的原理和应用&#xff1a; …

透彻理解二叉树中序遍历的应用

关卡名 二分搜索树 我会了✔️ 内容 1.有序数组转为二叉搜索树 ✔️ 2.寻找两个正序数组的中位数 ✔️ 1 有序数组转为二叉搜索树 LeetCode108 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 高度平衡 二叉搜索树。 高度…

深入理解Zookeeper系列-2.Zookeeper基本使用和分布式锁原理

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理、分布式技术原理&#x1f525;如果感觉博主的文章还不错的话&#xff…

全志XR806基于FreeRTOS下部署竞技机器人先进模糊控制器

前言 很荣幸参与到由“极术社区和全志在线联合组织”举办的XR806开发板试用活动。本人热衷于各种的开发板的开发&#xff0c;同时更愿意将其实现到具体项目中。秉承以上原则&#xff0c;发现大家的重心都放在开发中的环境构建过程&#xff0c;缺少了不少实际应用场景的运用&am…

【小布_ORACLE笔记】Part11-5 RMAN Backups

【小布_ORACLE笔记】Part11-5 RMAN Backups 文章目录 【小布_ORACLE笔记】Part11-5 RMAN Backups1. 增量备份&#xff08;Incremental Backups)1.1差异增量备份&#xff08;Differential Incremental Backup&#xff09;1.2累积增量备份&#xff08;Cumulative Incremental Bac…

记RocketMQ本地开发环境搭建始末

前言 最近工作中涉及到了RocketMQ的应用&#xff0c;为方便开发决定本地搭建一套RocketMQ的使用环境。 果然实践是个好东西... VMware虚拟环境搭建 这个网上有很多教程&#xff0c;只会比我写的详细有条理&#xff0c;这里就不在赘述了。 虚拟机搭建好之后每次重启电脑都无…

【投稿优惠、可EI检索】2024年机器人学习与自动化算法国际学术会议(IACRLAA 2024)

2024年机器人学习与自动化算法国际学术会议(IACRLAA 2024) 2024 International Academic Conference on Intelligent Control Systems and Robot Learning 一、【会议简介】 本届机器人学习与自动化算法国际学术会议(IACRLAA 2024)将于2024年1月23日在北京盛大开幕。这次会议将…

Vue3 Router跳转传参

最近遇到这个问题router跳转传参&#xff0c;真是要了老命了。 根据网上各位大神给出的方法&#xff0c;试了 import { useRouter } from vue-routerconst router useRouter()//1. 无法跳转 router.push(name:,params:{})//2. 可以跳转, 但需要在定义router同时定义占位符&a…

(五)基于高尔夫优化算法GOA求解无人机三维路径规划研究(MATLAB代码)

一、无人机模型简介&#xff1a; 单个无人机三维路径规划问题及其建模_IT猿手的博客-CSDN博客 参考文献&#xff1a; [1]胡观凯,钟建华,李永正,黎万洪.基于IPSO-GA算法的无人机三维路径规划[J].现代电子技术,2023,46(07):115-120 二、高尔夫优化算法GOA简介 高尔夫优化算法…

react-flip-move结合array-move实现前端列表置顶效果

你有没有遇到这样的需求&#xff1f;点击左侧列表项&#xff0c;则像聊天会话窗口一样将被点击的列表项置顶。 如果只是单纯的置顶的话&#xff0c;直接使用array-move就可以实现了&#xff0c;但置顶效果多少有点突兀~ 先上代码&#xff0c;直接使用array-move的情况&#xf…

用于缓存一些固定名称的小组件

项目中&#xff0c;用于缓存姓名、地名、单位名称等一些较固定名称的id-name小组件。用于减少一些表的关连操作和冗余字段。优化代码结构。扩展也方便&#xff0c;写不同的枚举就行了。 具体用法&#xff1a; {NameCacheUser.USER.getName(userId);NameCacheUser.ACCOUNT.getN…

文心一言 VS 讯飞星火 VS chatgpt (146)-- 算法导论12.2 1题

一、用go语言&#xff0c;假设一棵二叉搜索树中的结点在1到 1000 之间&#xff0c;现在想要查找数值为 363 的结点。下面序列中哪个不是查找过的序列? a.2&#xff0c;252&#xff0c;401&#xff0c;398&#xff0c;330&#xff0c;344&#xff0c;397&#xff0c;363。 b.9…

vtk中二次曲面的显示

官方示例地址&#xff1a; https://examples.vtk.org/site/Cxx/Visualization/DisplayQuadricSurfaces/ 显示效果&#xff1a; 源码&#xff1a; import vtk import vtkmodules.vtkInteractionStyle import vtkmodules.vtkRenderingOpenGL2 from vtkmodules.vtkCommonColor i…

SAP SD 创建交货单 报错 VL461 VL248

因为生产环境已经被改好了&#xff0c;无法跟踪 所以换到测试环境重现一把&#xff0c;如何追根究底 对比正常订单发现 计划行 VBEP-LMENG,VBEP-BMENG这两个字段上的值跟 订单数量不一致。 尝试修改2者的数据跟订单数据一致&#xff0c;则可以正常创建交货单 实际原因是&a…

Neo4j 数据库管理 数据备份与恢复(头歌)

文章目录 第1关&#xff1a;数据备份与恢复任务描述相关知识数据备份数据导入 编程要求测试说明答案测试前准备Cypher 代码数据备份与导入 第1关&#xff1a;数据备份与恢复 任务描述 本关任务&#xff1a;熟练掌握数据备份与恢复。 相关知识 为了完成本关任务&#xff0c;…

INFINI Easysearch 与华为鲲鹏完成产品兼容互认证

何为华为鲲鹏认证 华为鲲鹏认证是华为云围绕鲲鹏云服务&#xff08;含公有云、私有云、混合云、桌面云&#xff09;推出的一项合作伙伴计划&#xff0c;旨在为构建持续发展、合作共赢的鲲鹏生态圈&#xff0c;通过整合华为的技术、品牌资源&#xff0c;与合作伙伴共享商机和利…

基于单片机的排队叫号系统设计

1&#xff0e;设计任务 利用AT89C51单片机为核心控制元件,设计一个节日彩灯门&#xff0c;设计的系统实用性强、操作简单&#xff0c;实现了智能化、数字化。 基本要求&#xff1a;利用单片机AT89C51设计排队叫号机&#xff0c;能实现叫号功能。 创新&#xff1a;能显示叫号…

算法通关村第一关—链表高频面试题(白银)

链表高频面试题 一、五种方法解决两个链表的第一个公共子节点的问题 面试 02.07.链表相交1.首先想到的是暴力解&#xff0c;将第一个链表中的每一个结点依次与第二个链表的进行比较&#xff0c;当出现相等的结点指针时&#xff0c;即为相交结点。虽然简单&#xff0c;但是时间…

sso单点登录

一&#xff1a;业务需求 客户要求在门户网站上实现一次登录能访问所以信任的系统 二&#xff1a; 处理方式 实现sso单点登录需要前后端配合处理 1. 通过网页授权登录获取当前用户的openid&#xff0c;userid 2.设置单点登录过滤器并进行参数配置 3.另外写一个登录接口&…

制造企业建设数字工厂管理系统的难点主要有哪些

随着科技的飞速发展&#xff0c;制造企业正面临着从传统生产模式向数字化、智能化转型的挑战。其中&#xff0c;建设数字工厂管理系统是实现这一目标的重要途径。然而&#xff0c;在实际操作过程中&#xff0c;制造企业往往会遇到一系列难点。本文将对这些难点进行详细的分析。…