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

news2024/11/24 14:50:41

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

一、堆的概念

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

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

 

二、堆排序的算法

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

(一)、算法思路

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

        假设数组的元素个数为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)

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

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

相关文章

ElasticSearch 和 MySQL的区别

MySQLElasticSearch 数据库&#xff08;database&#xff09;索引&#xff08;index&#xff09;数据表&#xff08;table&#xff09; 类型&#xff08;type&#xff09; 记录文档&#xff08;document&#xff0c;json格式&#xff09; 一、ES基础命令 1. ES cat查询命令 2.…

超简单的nodejs使用log4js保存日志到本地(可直接复制使用)

引入依赖 npm install log4js 新建配置文件logUtil.js const log4js require(log4js);// 日志配置 log4js.configure({appenders: {// 控制台输出consoleAppender: { type: console },// 文件输出fileAppender: {type: dateFile,filename: ./logs/default, //日志文件的存…

4 前缀和、双端队列使用:子串

很多方法需要借助数据结构来操作&#xff1b; 1 数组 2 栈 3 队列 4 堆 5 链表 双端队列&#xff08;deque&#xff0c;全称为double-ended queue&#xff09;是一种特殊的线性数据结构&#xff0c;它允许在其两端进行添加和删除操作。在Python中&#xff0c;双端队列由标…

keil软件的一些使用技巧

1.MDK 的 TAB 键支持块操作 也就是可以让一片代码整体右移固定的几个位&#xff0c;也可以通过 SHIFTTAB 键整体左移固定的几个位。 2.快速注释与快速消注释 就是先选中你要注释的代码区&#xff0c;然后右键&#xff0c;选择Advanced→Comment Selection 就可以了。 3.快速打…

FFmpeg教程-三-播放pcm文件-1

目录 一&#xff0c;下载SDL 二&#xff0c;在Qt中测试 1&#xff0c;在pro文件中加入路径 2&#xff0c;在.cpp文件中加入头文件 3&#xff0c;进行测试 4&#xff0c;显示结果 一&#xff0c;下载SDL 通过编程的方式播放音视频&#xff0c;也是需要用到这2个库: FFmpeg…

百度智能云升级:接入33个大模型,Llama 2引领创新,103个Prompt模板上线

大家好&#xff0c;我是herosunly。985院校硕士毕业&#xff0c;现担任算法研究员一职&#xff0c;热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名&#xff0c;CCF比赛第二名&#xff0c;科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的…

Mysql常用SQL:日期转换成周_DAYOFWEEK(date)

有时候需要将查询出来的日期转换成周几&#xff0c;Mysql本身语法就是支持这种转换的&#xff0c;就是DAYOFWEEK()函数 语法格式&#xff1a;DAYOFWEEK(date) &#xff08;date&#xff1a;可以是指定的具体日期&#xff08; 如2024-06-29 &#xff09;&#xff0c;也可以是日期…

pc端制作一个顶部固定的菜单栏

效果 hsl颜色 hsl颜色在css中比较方便 https://www.w3school.com.cn/css/css_colors_hsl.asp 色相&#xff08;hue&#xff09;是色轮上从 0 到 360 的度数。0 是红色&#xff0c;120 是绿色&#xff0c;240 是蓝色。饱和度&#xff08;saturation&#xff09;是一个百分比值…

数据可视化在智慧园区中的重要作用

在现代智慧园区的建设和管理中&#xff0c;数据的作用越来越重要。智慧园区利用物联网、云计算、大数据等技术&#xff0c;实现了园区各类信息的实时采集和处理。数据可视化作为数据处理和展示的重要工具&#xff0c;为智慧园区的各个方面提供了强有力的支持。 首先&#xff0c…

【AI提升】AI利器Tool Call/Function Call(一):langchain+ollama+llama3/qwen2

1、使用AI的一个常用场景就是&#xff0c;接收人类的语言&#xff0c;识别人类的意图&#xff0c;最终进行相关的业务处理&#xff0c;这就是设计Tool Call / Function Call的初衷。 2、现在一般都说Tool Call&#xff0c;以前常叫Function Call&#xff0c;不要纠结。 一、安…

【提交ACM出版 | EIScopus检索稳定 | 高录用】第五届大数据与社会科学国际学术会议(ICBDSS 2024,8月16-18)

第五届大数据与社会科学国际学术会议&#xff08;ICBDSS 2024&#xff09;将于2024年08月16-18日在中国-上海隆重举行。 ICBDSS会议在各专家教授的支持下&#xff0c;去年已成功举办了四届会议。为了让更多的学者有机会参与会议分享交流经验。本次会议主要围绕“大数据”、“社…

在线字节大端序小端序转换器

具体请前往&#xff1a;在线字节大端序小端序转换器

Linux kernel 与 设备树

Linux kernel 与 设备树 1 介绍1.1 概述1.2 发展历程1.3 各版本发布时间及特色1.4 Linux 单内核1.5 Linux 内核网址1.6 NXP 官方镜像与 野火 鲁班猫镜像的区别 2 Linux 内核组成2.1 进程管理2.2 内存管理2.3 文件系统2.4 设备管理2.5 网络功能 3 Linux 内核编译3.1 编译 Kernel…

Linux上使用 git 命令行

在 Github或者 gitee 注册账号 这个比较简单 , 参考着官网提示即可 . 需要进行邮箱校验.以下以创建Github为例。 创建项目 1. 登陆成功后 , 进入个人主页 , 点击下方的 create a new repository 按钮新建项目 2. 在创建好的项目页面中复制项目的链接 , 以备接下来进行下…

pandas数据分析(1)

pandas&#xff0c;即Python数据分析库&#xff08;Python data analysis library&#xff09; DataFrame和Series DataFrame&#xff08;数据帧&#xff09;和Series&#xff08;序列&#xff09;是pandas的核心数据结构。DataFrame的主要组件包含索引、列、数据。DataFrame和…

使用matlab开发stm32总结,stm32-matlab常见的问题处理以及报错合集

1&#xff0c;问题&#xff1a;本来是好的&#xff0c;突然编译运行报错&#xff0c;说是确少包&#xff0c; 解决方案&#xff1a;重启以后好了 2&#xff0c;有完美的马鞍波&#xff0c;为什么不能够转动呢&#xff1f; 原因是我这里模型的问题&#xff0c;我计算出来的是占…

访客(UV)、点击量(PV)、IP、访问量(VV)概念

1、https://www.cnblogs.com/QingPingZm/articles/13855808.htmlhttps://www.cnblogs.com/QingPingZm/articles/13855808.html

不能创建第三个变量,实现两个数的交换

目录 常规实现两个数的交换&#xff08;如&#xff1a;交换变量a和变量b&#xff09; 方法一&#xff1a;加减法 方法二&#xff1a;异或操作符 常规实现两个数的交换&#xff08;如&#xff1a;交换变量a和变量b&#xff09; 创建一个临时变量tmp&#xff0c;先将其中一个…

Java代码基础算法练习-计算被 3 或 5 整除数之和-2024.06.29

任务描述&#xff1a; 计算 1 到 n 之间能够被 3 或者 5 整除的数之和。 解决思路&#xff1a; 输入的数字为 for 循环总次数&#xff0c;每次循环就以当前的 i 进行 3、5 的取余操作&#xff0c;都成立计入总数sum中&#xff0c;循环结束&#xff0c;输出 sum 的值 代码示例&…

MySQL高级-SQL优化- order by 优化(尽量使用覆盖索引、注意联合索引创建的规则、增大排序缓冲区大小)

文章目录 0、order by优化原则1、Using filesort2、Using index3、连接数据库4、查看索引5、删除索引6、按照年龄进行排序7、执行计划 order by age8、执行计划 order by age,phone9、创建联合索引 (age,phone)10、再次执行计划 order by age11、再次执行计划 order by age,pho…