[算法]——堆排序(C语言实现)

        简单的介绍一下用堆排序的算法对整形数据的数据进行排序。

一、堆的概念

        堆是具有下列性质的完全二叉树每个结点的值都大于或等于其左右孩子节点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。

大顶堆和小顶堆的示意图:

 

二、堆排序的算法

        因为数组具有顺序结构,而我们的完全二叉树可以使用顺序结构来表示,所以我们可以用堆对数组进行排序。

(一)、算法思路

        这里介绍一下排升序的方法,等明白了思路后,排降序自然也会了。

        假设数组的元素个数为n,将待排序的数组构造成一个大顶堆。此时,整个数组的最大值就是堆顶的根节点。将它移走(将其与堆数组的末尾元素进行交换,此时末尾元素就是最大值),这样我们待排序的数组的最大值就排到了正确的位置上。然后我们把剩余的n-1个元素重新构成一个大顶堆,这样堆顶元素就是我们的次大值,将其移走,次大值的元素也就排好了。如此反复执行,就得到了一个升序的数组。如果我们要排降序的数组,则需要建小顶堆。

        于是我们就有了两个问题。一是:如何把一个无序的数组构建成大顶堆?在将堆顶元素移走后要怎么将剩余的数组元素重新调整为堆?

(二)、向上调整和向下调整

        向上调整针对的是当将一个新的元素插入到一个堆中时,将新插入的元素向上进行调整,将其二叉树保持原来的堆的结构。如果是使用堆来对一个数组进行排序的话,使用向下调整就足够了,所以我们先讲向下调整,当我们实现了对数组的堆排序后,再回来看向上调整。

1、向下调整

        向下调整的作用就是,当我们在一个堆的结构中,把堆顶元素给替换成别的值后,其堆顶处极可能已经不满足大顶堆和小顶堆的要求了,这个时候我们就需要把这个堆顶位置的元素向下调整到合适的位置,使其重新满足堆的要求。

例如下面这个例子:

        这是一个大顶堆,当我们用20替换其堆顶元素时,其不再满足大顶堆的结构,这时我们需要对堆顶的20进行向下调整。具体方法如如下:

 

具体代码:

//向下调整为大顶堆
void AdjustDown(int* arr,int left,int right)//传入数组和要向下调整的区间
{
	int pos = left;//记录向下调整的位置
	int temp = arr[pos];//保存向下调整的值
	for (int i = left * 2; i <= right; i *= 2)//遍历其要向下调整的结点的孩子
	{
		//找到其左孩子和右孩子的最大值 如果右孩子不存在,则最大值就算为左孩子
		if (i + 1 <= right && arr[i] < arr[i + 1])
			i++;//此时i指向右孩子

		if (temp < arr[i]) //如果要向下调整的值不如孩子大
			arr[pos] = arr[i];
		else
			break;

		//更新要向下调整的值的下标位置
		pos = i;
	}

	//向下调整完毕,此时pos的位置就是要向下调整的值的最终位置
	arr[pos] = temp;
}

2、向上调整

        向上调整非常简单,只需要将插入的值的结点与其双亲结点相比较,如果比双亲大,那么就交换位置,一直重复该过程。

 

//向上调整为大堆顶
void AdjustUp(int* arr,int index)
{
	int pos = index;//记录向上调整的值的位置
	int temp = arr[index];//保存向上调整的值

	//遍历其双亲节点进行向上调整,如果向上调整的下标为0或比双亲小就结束
	for (int i = pos / 2; pos > 0; i /= 2)
	{
		if (temp > arr[i])
			arr[pos] = arr[i];
		else
			break;

		//更新pos的位置
		pos = i;
	}

	//向上调整完毕,此时pos位置就是向上调整的值的位置
	arr[pos] = temp;
}

 (三)、将无序数组转化为大顶堆

        实现方法:从最后一个叶子结点(就是数组的最后一个元素的下标的位置的结点)处的双亲结点开始,对该结点以及该结点之前的所有结点进行向下调整操作,这样就可以把无序数组转化为了大顶堆的结构。下面是将一个无序数组转化为大顶堆的示意图(标识为蓝色的值就是需要依次进行向下调整的结点。)

        

         就这样,我们就将一个无序的数组转化为了一个具有大顶堆结构的数组了。

        我们也可以从0开始遍历数组,每次执行一次向上调整,这样也可以建堆,但是其消耗比较大。因为需要对每个结点进行向上调整操作,而我们的向下调整建堆是不需要对最后一层的结点进行向下调整的,在一棵满二叉树中,最后一层的结点数就占了整棵树一半的结点数,这意味着向上调整建堆比向下调整建堆多用了很多时间。

(四)、堆排序的最终实现

        我们以一个大顶堆为例,看看将大顶堆转化成一个升序的数组的过程。

        来看下面这个大顶堆,是如何变升序的。

         此时90排好了。

 此时80就排好了。

如此往复...... 

 

具体代码:

//堆排序
void HeapSort(int* arr, int nums)
{
	//先从最后一个节点的双亲结点注逐一往前进行向下调整,将数组调整为大堆
	for (int i = (nums - 1) / 2; i >= 0; i--)
	{
		AdjustDown(arr,i, nums - 1);
	}

	//将最大值放置到末尾然后将其与堆的联系解除,然后再对堆顶元素向下调整
	for (int i = nums - 1; i >= 1; i--)
	{
		swap(arr[0], arr[i]);
		AdjustDown(arr, 0, i - 1);
	}
}

 三、堆排序的时间复杂度

        堆排序不需要额外开辟空间,所以空间复杂度为O(1)。

        时间消耗上主要在初始建堆和在反复重建堆的时间上。而我们对无序数组进行建堆所需要的时间复杂度为O(n),而我们在排序时,每次都需要对堆顶进行向下排序,其时间复杂度为O(nlogn)。所以堆排序的时间复杂度为O(nlogn)

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

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

相关文章

第二十一课,列表的操作函数

一&#xff0c;len(列表):求列表的长度 当你需要知道一个列表中含有多少个元素时&#xff0c;可以使用len()函数&#xff0c;将列表的变量名放入len()函数的括号中&#xff0c;它将告诉你这个列表中有多少个元素&#xff0c;也就是它的长度&#xff01; 需要注意的是&#xf…

安装OpenHarmony编译库和工具集

一、搭建开发环境 1.1、Ubuntu搭建&#xff0c;参考 VMware完美安装Ubuntu20.04-CSDN博客文章浏览阅读286次&#xff0c;点赞5次&#xff0c;收藏3次。详细介绍了VMware下安装Ubuntu20.04https://blog.csdn.net/longyuzi/article/details/139935769 1.2、拉取OpenHarmony源码…

实现自动化:如何利用阿里云OSS上传文件并自动打标签

在当前数字化时代&#xff0c;数据管理变得愈发重要&#xff0c;特别是对于需要大规模存储和管理文件的场景。阿里云对象存储服务&#xff08;OSS&#xff09;作为业界领先的解决方案&#xff0c;不仅提供了稳定可靠的云存储&#xff0c;还支持丰富的扩展功能&#xff0c;如文件…

每日一道算法题 面试题 08.08. 有重复字符串的排列组合

题目 面试题 08.08. 有重复字符串的排列组合 - 力扣&#xff08;LeetCode&#xff09; Python class Solution:def permutation(self, S: str) -> List[str]:# 以索引记录字符是否用过lelen(S)idx[_ for _ in range(le) ]# 组合得到的字符串combine[]*leans[]# 递归def fu…

LLM探索:环境搭建与模型本地部署

前言 最近一直在炼丹&#xff08;搞AIGC这块&#xff09;&#xff0c;突然发现业务代码都索然无味了… 上次发了篇AI画图的文章&#xff0c;ChatGPT虽然没法自己部署&#xff0c;但现在开源的LLM还是不少的&#xff0c;只要有一块差不多的显卡&#xff0c;要搞个LLM本地部署还…

安卓应用开发学习:获取经纬度及地理位置描述信息

前段时间&#xff0c;我在学习鸿蒙应用开发的过程中&#xff0c;在鸿蒙系统的手机上实现了获取经纬度及地理位置描述信息&#xff08;鸿蒙应用开发学习&#xff1a;手机位置信息进阶&#xff0c;从经纬度数据获取地理位置描述信息&#xff09;。反而学习时间更长的安卓应用开发…

基于知识图谱的医药问答系统实战

数据及代码地址见文末 1.项目配置 (1)Neo4j数据库安装 JDK 安装:https://www.oracle.com/java/technologies/javase-downloads.html Neo4j 安装:https://neo4j.com/download-center/ 配置好 JDK 和 Neo4j 的环境变量 启动:neo4j.bat console 第一次启动有默认用户名和密…

《昇思25天学习打卡营第3天|张量 Tensor》

文章目录 前言&#xff1a;今日所学&#xff1a;1. 创建张量2. 张量的属性3.张量索引与运算4. NumPy与Tensor的转换5. 稀疏张量 前言&#xff1a; 张量&#xff1f;张亮&#xff1f;张量是什么&#xff1f; 张量是一个可以用来表示在一些矢量、标量和其他张量之间的线性关系的…

逆风而行:提升逆商,让困难成为你前进的动力

一、引言 生活&#xff0c;总是充满了未知与变数。有时&#xff0c;我们会遇到阳光明媚的日子&#xff0c;享受着宁静与和谐&#xff1b;但更多时候&#xff0c;我们却不得不面对那些突如其来的坏事件&#xff0c;如工作的挫折、人际关系的困扰、健康的挑战等。这些事件如同突…

每日一题——Python实现PAT乙级1059 C语言竞赛(举一反三+思想解读+逐步优化)四千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 时间复杂度分析 空间复杂度分析 代码优化建议 总结 我要更强 优化方法…

秋招突击——第九弹——Redis缓存

文章目录 引言正文缓存基础旁路缓存模式&#xff08;重点&#xff09;读穿透&#xff08;了解&#xff09;写穿透&#xff08;了解&#xff09;异步缓存写入模式面试重点 缓存异常场景缓存穿透缓存击穿缓存雪崩面试重点 缓存一致性怎么保证&#xff1f;缓存一致性问题是什么方案…

使用SpringBoot整合filter

SpringBoot整合filter&#xff0c;和整合servlet类似&#xff0c;也有两种玩儿法 1、创建一个SpringBoot工程&#xff0c;在工程中创建一个filter过滤器&#xff0c;然后用注解WebFilter配置拦截的映射 2、启动类还是使用ServletComponentScan注解来扫描拦截器注解WebFilter 另…

Vue2中管理$bus事件,统一移除事件

1. vue2中使用了,很多bus,在有些地方忘记清理了,导致重复事件bug. 对bus进行改造,实现清除遗留. 下面的简单实现. 1.eventbus.js // eventBus.js import Vue from vue;class EventBusClass extends Vue {constructor() {super();this.listeners [];}on(event, callback, con…

实测备受好评的三款独享IP网站服务商

一、引言 在如今互联网快速发展的时代&#xff0c;网络爬虫、数据抓取等任务对于许多企业和个人来说愈发重要&#xff0c;而在这个过程中&#xff0c;一个稳定、高效且安全的独享IP资源显得尤为重要。作为专业的测评团队&#xff0c;我们深知一款优秀的独享IP服务商需要具备哪…

2-19 基于matlab的薄板弯曲的算例

基于matlab的薄板弯曲的算例&#xff0c;利用有限元方法编制matlab程序。对二维薄板进行单元化&#xff0c;输出薄板结构参数及载荷&#xff0c;输出弯曲情况&#xff0c;并可视化展示。程序已调通&#xff0c;可直接运行。 2-19 薄板弯曲 有限元方法 薄板结构参数 - 小红书 (x…

【MySQL】InnoDB架构

本文MySQL版本是8.X版本 这是官方文档给出来的架构图&#xff1a;MySQL :: MySQL 8.0 Reference Manual :: 17.4 InnoDB Architecture 可以看出&#xff0c;整体上是分成两部分的&#xff1a;内存结构(提高效率)和磁盘结构(数据持久化)&#xff0c;下面将把每个区域都大致做一个…

Java程序员学习Go开发Higress的WASM插件

Java程序员学习Go开发Higress的WASM插件 契机 ⚙ 今年天池大赛有higress相关挑战&#xff0c;研究一下。之前没搞过go&#xff0c;踩了很多坑&#xff0c;最主要的就是tinygo打包&#xff0c;多方寻求解决无果&#xff0c;结论是tinygo0.32go1.19无法在macos arm架构下打包。…

【微服务】Alibaba Cloud Linux环境下Docker以及MySQL安装

部署Docker 1.安装dnf dnf是新一代的rpm软件包管理器 yum -y install dnf2.安装社区版Docker&#xff08;docker-ce&#xff09; 添加docker-ce的dnf源 dnf config-manager --add-repohttps://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo安装Alibaba Cloud…

从灵感到实践:Kimi辅助完成学术论文选题的文艺之旅

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 昨天我们为大家介绍了ChatGPT辅助完成实现设计&#xff08;AI与学术的交响&#xff1a;ChatGPT辅助下的实验设计新篇章&#xff09;。今天我们再来看看Kimi对于论文选题都能提供哪些帮助…

kali/ubuntu安装vulhub

无须更换源&#xff0c;安装docker-compose apt install docker.io docker -vdocker-compose #提示没有&#xff0c;输入y安装mkdir -p /etc/docker vi /etc/docker/daemon.json #更换dockerhub国内源┌──(root㉿kali)-[/home/kali/vulhub-master/tomcat/CVE-2017-12615] …