[ 数据结构 -- 手撕排序算法第五篇 ] 堆排序

news2024/9/22 9:46:47

文章目录

  • 前言
  • 一、常见的排序算法
  • 二、堆的概念及结构
  • 三、堆的实现
    • 3.1 堆的插入
    • 3.2 堆的删除
  • 四、堆排序
    • 4.1 向上调整建堆
    • 4.2 向下调整建堆
    • 4.3 建堆的时间复杂度
    • 4.4 堆排序
  • 五、堆排序的特性


前言

手撕排序算法第五篇:堆排序!
从本篇文章开始,我会介绍并分析常见的几种排序,例如像插入排序,冒泡排序,希尔排序,选择排序,快速排序,堆排序,归并排序等等!
这篇文章我先来给大家手撕一下堆排序

大家可以点下面的链接去阅读其他的排序算法:
C语言手撕排序算法


正文开始!

一、常见的排序算法

在这里插入图片描述

二、堆的概念及结构

如果有一个关键码的集合K={k0,k1,k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <=K2*i+2且Ki<=K2*i+2(Ki>=K2*i+1且Ki>=K2*i+2)其中i=0,1,2,3…,则称之为小堆(大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆的性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一颗完全二叉树。

在这里插入图片描述

三、堆的实现

3.1 堆的插入

先插入一个10到数组中,然后进行向上调整算法,直到满足堆的性质。
在这里插入图片描述
针对插入10之后我们调整来进行分析。

在这里插入图片描述

有可能交换到中间满足堆的性质就停止交换了。

void AdjustUp(int* a,size_t child)
{
	size_t parent = (child - 1) / 2;
	while (child>0)
	{
		if (a[child]<a[parent])
		{
			Swap(&a[parent],&a[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

算法逻辑是二叉树,物理上操作的是数组中的数据。

3.2 堆的删除

挪动数据覆盖根的位置的数据删除

  1. 挪动数据是O(n)。
  2. 堆结构破坏了,分子间的关系就全乱了。

所以上面的方法是不可取的。

接下来讲一讲实际操作,如下图所示。
在这里插入图片描述

在这里插入图片描述
代码实现

void AdjustDown(int* a,size_t size,size_t root)
{
	size_t parent = root;
	size_t child = parent * 2+1;
	while (child < size)
	{
		//选出左右孩子中小的哪一个 
		if (child + 1 < size && a[child + 1] > a[child])
		{
			child++;
		}
		//2.如果孩子小于父亲,则交换,并继续向下调整。
		if (a[child] < a[parent])
		{
			Swap(&a[child],&a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
}

四、堆排序

在这里插入图片描述

4.1 向上调整建堆

在这里插入图片描述

	//向下调整建堆
	for (int i = 1; i < n; ++i)
	{
		AdjustUp(a,i);
	}

在这里插入图片描述

4.2 向下调整建堆

在这里插入图片描述

	//向上调整建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a,n,i);
	}

在这里插入图片描述

我们可以发现向上调整建堆和向下调整建堆出来的堆是不一样的。

4.3 建堆的时间复杂度

因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来看就是近似值,多几个节点不影响最终的结果)。

在这里插入图片描述
在这里插入图片描述因此:建堆的时间复杂度为O(N)。

4.4 堆排序

如果升序建小堆,最小的数已经在堆顶,剩下的数关系打乱,需要重新建堆,建堆最好也要O(N),再选出次小的,不断建堆选数,如果这样,还不如直接遍历选数!!因此升序要建大堆!!利用删除的思想来玩。

过程:

  1. 把第一个数和最后一个数交换,由于是大堆,堆顶的数据一定是最大的数据。和最后一个数交换后,最大的数据就到了最后一个。

  2. 再对前N-1个数进行向下调整建立新的大堆,次大的数放在了堆顶,我们再让堆顶的元素和最后一个元素交换(这个最后一个不是数组的最后一个,是堆中的最后一个,使用end进行控制)。

  3. 当end到0的时候,说明已经排完了。

void AdjustUp(int* a,size_t child)
{
	size_t parent = (child - 1) / 2;
	while (child>0)
	{
		if (a[child]>a[parent])
		{
			Swap(&a[parent],&a[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
void AdjustDown(int* a,size_t size,size_t root)
{
	size_t parent = root;
	size_t child = parent * 2+1;
	while (child < size)
	{
		//选出左右孩子中小的哪一个 
		if (child + 1 < size && 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)
{
	向下调整建堆
	//for (int i = 1; i < n; ++i)
	//{
	//	AdjustUp(a,i);
	//}
	
	//向上调整建堆
	for (int i = (n - 1 - 1/*最后一个非叶子节点*/) / 2; i >= 0; --i)
	{
		AdjustDown(a,n,i);
	}
	//升序排列建大堆
	//找出堆顶元素放入最后一个位置,就是把最大值放到最后一个位置。
	//然后循环下去
	size_t end = n - 1;
	while (end>0)
	{
		Swap(&a[0],&a[end]);
		AdjustDown(a,end,0);
		--end;
	}
}
void TestHeapSort()
{
	int a[] = { 4,2,7,8,5,1,0,6 };
	printf("排序前:");
	PrintArray(a, sizeof(a) / sizeof(a[0]));
	HeapSort(a, sizeof(a) / sizeof(a[0]));
	printf("排序后:");
	PrintArray(a, sizeof(a) / sizeof(a[0]));
}
int main()
{
	TestHeapSort();
	return 0;
}

在这里插入图片描述

五、堆排序的特性

堆排序最重要的是升序要建大堆,逆序排列要建小堆。

  1. 时间复杂度O(NlogN)。
  2. 空间复杂度为O(1)。
  3. 稳定性:不稳定。

(本章完!)

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

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

相关文章

Java+JSP超市管理系统(含源码+论文+答辩PPT等)

项目功能简介: 该项目采用的技术后台框架&#xff1a;Servlet、JSP、JDBC、UI界面&#xff1a;BootStrap、jQuery、数据库&#xff1a;MySQL 系统功能 该系统共包含两种角色&#xff1a;员工和管理员。系统的主要功能模块如下&#xff1a; 1.系统管理 系统登陆、系统退出、修改…

《Mysql是怎样运行的》补充

19 第19章 从猫爷被杀说起-事务简介 19.1 事务的起源 19.1.1 原子性&#xff08;Atomicity&#xff09; 19.1.2 隔离性&#xff08;Isolation&#xff09; 其它的状态转换不会影响到本次状态转换&#xff0c;这个规则被称之为 隔离性 19.1.3 一致性&#xff08;Consisten…

[ISITDTU 2019]EasyPHP rce替换字母

<?php highlight_file(__FILE__);$_ $_GET[_]; if ( preg_match(/[\x00- 0-9\"$&.,|[{_defgops\x7F]/i, $_) )die(ros will not do it);if ( strlen(count_chars(strtolower($_), 0x3)) > 0xd )die(you are so close, omg);eval($_); ?> 打开界面有两个i…

Mysql分布式锁(四)乐观锁实现并发

文章目录CAS - Compare And Swap业务改造1. 表结构新增version列2. 修改代码3. 测试问题1. 高并发情况下&#xff0c;性能极低2. ABA问题3. 读写分离情况下导致乐观锁不可靠CAS - Compare And Swap 先比较再交换&#xff0c;一般通过时间戳或者version版本号。 举例&#xff1…

【审计思路】如何快速定位SQLMS注入漏洞?

0x00 前言 MCMS是政府、教育等其他行业常用的CMS&#xff0c;应用广泛&#xff0c;但是底层的代码中仍然遗留不少的问题。这篇文章主要针对SQL注入进行审计并探讨如何快速定位SQL注入漏洞&#xff0c;以及其他工具的应用。 MCMS&#xff0c;是完整开源的Java CMS&#xff01;基…

[ vulhub漏洞复现篇 ] Apache Airflow Celery 消息中间件命令执行漏洞复现 CVE-2020-11981

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

基于asp.net企业网上办公自动化系统-计算机毕业设计

企业网上办公自动化通过对各办公自动化要素的闭环整合&#xff0c;实现了工作流、信息流、知识流和办公自动化系统的整合管理&#xff0c;提供了一个科学、开放、先进的信息化办公平台&#xff0c;实现办公自动化&#xff0c;并进行远程办公或在家办公。企业网上办公自动化将人…

redis开启二级缓存

目录 1. redis集成 2. pom.xml加入redis缓存支持 3. 在项目配置文件中加入cache配置 4. 在启动类开发缓存功能 5. 需要缓存的实体对象实现序列化接口 6. 缓存的使用 7. 测试 今天与大家分享&#xff0c;redis二级缓存实现案例。如有问题&#xff0c;望指教。 1. redis集…

计算机毕业设计springboot+vue基本微信小程序的校园二手物品交易平台系统

项目介绍 目的:设计一个同学们能自由发布和浏览求购或卖出商品信息的校园二手交易小程序,解决信息的不流通以及传统二手商品信息交流方式的笨拙等问题。 意义:在大学校园里,存在着很多的二手商品,但是由于信息资源的不流通以及传统二手商品信息交流方式的笨拙,导致了很多仍然具…

十年阿里测试工程师浅谈UnitTest单元测试框架

一、UnitTest单元测试框架提供了那些功能 1.提供用例组织和执行 如何定义一条“测试用例”? 如何灵活地控制这些“测试用例”的执行? 2.提供丰定的断言方法 当测试用例的执行结果与预期结果不一致时&#xff0c;判定测试用例失败。在自动化测试中&#xff0c;通过“断言”…

2022 软件测试简答题【太原理工大学】

四、简答题 1. 比较自顶向下集成测试方法和自底向上集成测试方法各自的优缺点。 ① 自顶向下集成 优点&#xff1a;较早地验证了主要控制和判断点:按深度优先可以首先实现和验证一个完整的软件功能;功能较早证实&#xff0c;带来信心;只需一个驱动&#xff0c;减少驱动器开发…

python+pyqt5设置窗体图标和任务栏图标及窗体标题的方法

本次设置窗体标题只用了一种方法&#xff0c;在进行窗体实例化后window Window()&#xff0c;使用setWindowTitle(str)命令&#xff0c;在主程序中的设置命令如下所示&#xff1a; if __name__ __main__:QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) #Qt从5.6.0开…

机器学习——05线性回归

机器学习——05线性回归 参考资料 AIlearningMachine-Learning-in-Action庞善民.西安交通大学机器学习导论2022春PPT 使用Jupyter进行练习&#xff0c;python3 具体项目地址&#xff1a;https://github.com/yijunquan-afk/machine-learning/tree/master/basic-learn/05-reg…

ARM S5PV210 X210 刷机教程总结

前言 S5PV210 X210 开发板外观介绍 一、开发板刷系统1 1. 什么是刷系统 刷系统就是利用刷机工具&#xff0c;向开发板中烧录预先编译好的系统镜像&#xff0c;使之在开发板上运行起来。 2. 串口输出的意义&#xff08;做系统控制台&#xff09; 串口是一种硬件通信口&…

【将高光谱、多光谱和全色图像进行融合】

HyperNet: A deep network for hyperspectral, multispectral, and panchromatic image fusion &#xff08;HyperNet&#xff1a;一种用于高光谱、多光谱和全色图像融合的深度网络&#xff09; 传统的方法主要是将高光谱图像&#xff08;hyperspectral image (HSI)&#xff0…

定时红绿灯(C51单片机)

一&#xff0e;项目题目&#xff1a;利用中断处理制作的定时LED红绿灯系统 二&#xff0e;项目器件&#xff1a; 红色LED灯 绿色LED灯 黄色LED灯 100R电阻 电源 电容器 C51单片机 接地线 三&#xff0e;项目原理图 四&#xff0e;项目实现功能&#xff1a; 使用定时器/计数…

【云原生 | Kubernetes 实战】14、K8s 控制器 Statefulset 入门到企业实战应用

目录 一、Statefulset 控制器&#xff1a;概念、原理解读 1.1 什么是有状态服务&#xff1f; 1.2 什么是无状态服务&#xff1f; 二、 Statefulset 资源清单文件编写技巧 三、Statefulset 使用案例&#xff1a;部署 web 站点 3.1 StatefulSet 由以下几个部分组成&#xf…

VMware克隆虚拟机

一、克隆虚拟机 1. 在WMware中&#xff0c;右键虚拟机模板&#xff08;需要克隆的虚拟机原型&#xff09;&#xff0c;选择&#xff1a;管理 ----> 克隆&#xff0c;如下图所示&#xff1a; 2. 然后&#xff0c;如下图进行操作&#xff1a; 二、扩展&#xff1a;移除、删除…

【Python】 14-CVS文件操作

1.CVS文件 值没有类型&#xff0c;所有东西都是字符串&#xff1b; • 没有字体大小或颜色的设置&#xff1b; • 没有多个工作表&#xff1b; • 不能指定单元格的宽度和高度&#xff1b; • 不能合并单元格&#xff1b; • 不能嵌入图像或图表。 CSV 文件中的每个单元格 有逗…

【JavaSE基础:数据类型和变量】

数据类型一、数据类型1.八大基本数据类型二、变量0.字面常量1.变量1&#xff09;数值类型a.整型b.浮点型2&#xff09;字符类型&#xff08;char&#xff09;3&#xff09;布尔类型&#xff08;boolean&#xff09;2.类型转换3.类型提升一、数据类型 Java是一种强类型编程语言…