堆的实现及其应用

news2025/2/26 22:29:31

堆的概念

        堆是完全二叉树,分为大堆和小堆。大堆:任何一个父亲都大于等于孩子,小堆:任何一个父亲都小于等于孩子。

堆的实现

目录

typedef int HPDataType;

typedef struct Heap
{ 
	HPDataType* a;
	int size;
	int capacity;
}HP;

//交换函数
void Swap(HPDataType* p1, HPDataType* p2);
//堆的初始化和销毁
void HPInit(HP* php);
void HPDestroy(HP* php);
//堆的插入和删除
void HPPush(HP* php, HPDataType x);
void HPPop(HP* php);
//取堆数据和判空
HPDataType HPTop(HP* php);
bool HPEmpty(HP* php);
//向上调整和向下调整
void AdJustUp(HPDataType* a, int child);
void AdJustDown(HPDataType* a, int n, int parent);

1.堆的初始化

void HPInit(HP* php)
{
	assert(php);
	php->a = NULL;
	php->size = php->capacity = 0;
}

可以选择在堆的初始化过程直接对空间大小进行赋值,在这里选择不开空间。

2.堆的销毁

void HPDestroy(HP* php)
{
	assert(php);
	free(php->a);
	php->a = NULL;
	php->size = php->capacity = 0;
}

3.交换函数

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

4.向上调整

        堆在数组中存储,所以根节点的小标为孩子节点下标减一再除以二,向上调整即将孩子节点向上调整,直到满足要求的大堆(小堆)建成。

void AdJustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	while (child >= 0)
	{
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;//相当于进行一次递归
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

5.向下调整

void AdJustDown(HPDataType* 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;
		}
	}
	
}

6.堆的插入

void HPPush(HP* php, HPDataType x)
{
	assert(php);
	if (php->size == php->capacity)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->a, newcapacity * sizeof(HPDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			return;
		}
		php->a = tmp;
		php->capacity = newcapacity;
	}
	php->a[php->size] = x;
	php->size++;

	AdJustUp(php->a, php->size - 1);
}

我们选择在堆插入函数中进行空间的开创。

7.堆数据删除

        对于堆中数据的删除,删除叶子结点数据意义不大,我们主要是要删除顶层节点数据,思路将顶部数据进行调整到最后的叶子结点处,在对其进行删除即可。

void HPPop(HP* php)//向下调整算法,可用于topk问题(找最大(最小)的几个值)
{
	assert(php);
	assert(php->size > 0);
	Swap(&php->a[0], &php->a[php->size - 1]);

	php->size--;
	AdJustDown(php->a, php->size, 0);
}

8.取堆顶数据

        对于只有一条语句的函数,我们为了方便调控,仍进行函数调用。

HPDataType HPTop(HP* php)
{
	assert(php);
	assert(php->size > 0);
	return php->a[0];
}

9.堆的判空

bool HPEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}

堆排序

建堆

        通过循环调用向上调整函数,可以将数组调整为堆。代码如下:

void HeapSort(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		AdJustUp(a, i);
	}
}

        另外,若使用向下调整建堆时间复杂度会更低

排序

升序建大堆

如果升序建小堆,将顶层最小数据取出后,导致后面数据顺序全部混乱,所以我们建大堆。

将最大的数往堆最后位置数据交换,再将其放入新数组的最后一位即可。代码如下:

void HeapSort(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		AdJustUp(a, i);
	}
	
	int end = n - 1;
	while (end > 0)
	{	
		Swap(&a[0], &a[end]);
		AdJustDown(a, end, 0);
		--end;
	}
}	

void AdJustDown(HPDataType* 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)
{
	for (int i = 0; i < n; i++)
	{
		AdJustUp(a, i);
	}
	
	int end = n - 1;
	while (end > 0)
	{	
		Swap(&a[0], &a[end]);
		AdJustDown(a, end, 0);
		--end;
	}
}	

void AdJustDown(HPDataType* 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;
		}
	}
	//向上调整同理
}

如果觉得我写得不错的话,请别忘了点赞收藏加评论!!

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

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

相关文章

java写一个验证码

生成验证码 内容&#xff1a;可以是小写字母&#xff0c;也可以是大写字母&#xff0c;还可以是数字 规则 长度为5 内容中是四位字母&#xff0c;1位数字。 其中数字只有1位&#xff0c;但是可以出现在任意的位置。 package User;import java.util.ArrayList; import jav…

MFC动态创建按钮

void CMFCApplication1Dlg::OnBnClickedOk() {for (int i 0; i < 100; i){for (int j 0; j < 100; j){CButton* pButton3 new CButton;pButton[i][j] pButton3;}}CRect rect;GetClientRect(&rect); // 获取对话框客户区的大小rect.top 10; // 设置按钮的位置rec…

【培训】企业档案管理专题(私货)

导读&#xff1a;通过该专题培训&#xff0c;可以系统了解企业档案管理是什么、为什么、怎么做。尤其是对档案的价值认知&#xff0c;如何构建与新质生产力发展相适应的企业档案工作体系将有力支撑企业新质生产力的发展&#xff0c;为企业高质量发展贡献档案力量&#xff0c;提…

02-adb的工作原理和常见命令

一、什么是adb&#xff1f; ADB 是 Android Debug Bridge 的简称&#xff0c;是 Android 平台的调试工具。通过 adb 命令可以去获取安卓设备上的一些信息&#xff0c;也可以直接操作管理 Android 模拟器或者真实的 Android 设备。 ADB 采用客户端-服务端程序架构&#xff0c;简…

12306 火车票价格解析 (PHP 解析)

1. 从接口拿数据 日期 出发站 终点站 都填上 xxx/otn/leftTicketPrice/queryAllPublicPrice?leftTicketDTO.train_date2024-06-15&leftTicketDTO.from_stationBJP&leftTicketDTO.to_stationSJP&purpose_codesADULT 返回的数据是这样的 {"validateMess…

格式工厂转换mp3失败,原因和解决方法来了

在使用格式工厂进行音频转换时&#xff0c;有时候可能会遇到转换为MP3失败的问题。这可能会让人感到困扰&#xff0c;但幸运的是&#xff0c;这样的问题通常有一些常见的原因&#xff0c;而且大多数情况下都能够轻松解决。在本文中&#xff0c;我们将探讨一些可能导致格式工厂转…

【Linux】高级IO——五种IO方式,select,poll,epoll

文章目录 一、简单了解什么是IO及五种IO模式五种IO同步IO和异步IO区别1.阻塞IO&#xff08;张三钓鱼方式&#xff09;2.非阻塞IO非阻塞轮询&#xff08;李四钓鱼方式&#xff09;使用fcntl函数实现SetNonBlock非阻塞 二、IO多路转接——select&#xff08;赵六钓鱼方式&#xf…

HTML静态网页成品作业(HTML+CSS)—— 家乡成都介绍网页(4个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有4个页面。 二、作品演示 三、代…

前端技术回顾系列 11|TS 中一些实用概念

在微信中阅读,关注公众号:CodeFit。 创作不易,如果你觉得这篇文章对您有帮助,请不要忘了 点赞、分享 和 关注 我的公众号:CodeFit,为我的持续创作提供动力。 上文回顾:泛型在类和接口中的应用 上一篇文章我们回顾了 泛型 在 类 和 接口 中的应用。 通过使用泛型,我们…

【NetTopologySuite类库】C#生成带约束(线、面)的Delaunay三角网

介绍 API地址&#xff1a;https://nettopologysuite.github.io/NetTopologySuite/api/NetTopologySuite.Triangulate.ConformingDelaunayTriangulationBuilder.html#NetTopologySuite_Triangulate_ConformingDelaunayTriangulationBuilder_Constraints 约束为线 效果图 红色…

vue代办事件案例实战练习,配有答案解析

代办事件案例 该案例&#xff0c;综合了前面所学的知识&#xff0c;列入点击事件绑定&#xff0c;双向绑定&#xff0c;v-for循环语句&#xff0c;v-model双向绑定&#xff0c;以及input标签的不同type形式。 演示代码如下&#xff1a; <template > <div id"ku…

计算机网络重要知识点

OSI 七层模型 是国际标准化组织提出的一个网络分层模型。 TCP/IP 四层模型 是目前被广泛采用的一种模型,我们可以将 TCP / IP 模型看作是 OSI 七层模型的精简版本&#xff0c;由以下 4 层组成&#xff1a; 应用层传输层网络层网络接口层 复杂的系统需要分层&#xff0c;因为每…

【Pandas】已完美解决:AttributeError: ‘DataFrame‘ object has no attribute ‘ix‘

文章目录 一、问题背景二、可能出错的原因三、错误代码示例四、正确代码示例&#xff08;结合实战场景&#xff09;五、注意事项 一、问题背景 在Pandas的早期版本中&#xff0c;ix 是一个方便的索引器&#xff0c;允许用户通过标签和整数位置来索引DataFrame的行和列。然而&a…

Go基础编程 - 05 - 数组与切片

目录 1. 数组2. 切片2.1. slice 声明、初始化2.2. slice 操作2.3. append() 追加切片、扩容2.4. 字符串和切片 3. Copy4. Array、Slice 内存布局 上一篇&#xff1a;基本类型、常量和变量 下一篇&#xff1a;指针 1. 数组 数组是同一种类型固定长度的序列&#xff08;有长度、…

新版eclipseSpringToolSuite4 get set方法自动生成注释(适用2019-03之后版本)

今天分享一个新版本eclipse 自动生成getter/setter文档注释的方法&#xff0c;看一下效果图 public class Test {//姓名private String name;/** * 获取 姓名 * return name 姓名 */public String getName() {return name;}/** * 设置 姓名 * param name 姓名 */public void …

frp55版本如何配置泛域名

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。 前言 之前配置的好好的frp&#xff0c;结果到用的时候不能用了&#xff0c;直接影响了我早上的一堆rss订阅源不能用&#xff0c;群里的新闻简报也没有正常推送&#xff0c;今天又翻出来捋…

SpringCloud总结(springcloud alibaba)

目录 版本说明&#xff08;很重要&#xff09; springcloud alibaba对应组件版本说明 简述 spring cloud albaba 几大模块 周会讨论 - spring cloud alibaba每周都会有周会讨论,社区活跃 spring cloud alibaba官网 注册配置中心 简单介绍 nacos 步骤 示例代码 依赖…

C# WinForm —— 35 StatusStrip 介绍

1. 简介 状态栏 StatusStrip&#xff0c;默认在软件的最下方&#xff0c;用于显示系统时间、版本、进度条、账号、角色信息、操作位置信息等 可以在状态栏中添加的控件类型有&#xff1a;StatusLabel、ProgressBar、DropDownButton、SplitButton 2. 属性 属性解释(Name)控…

端午后的第一单cisa

需要的老板快来联系

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第41课-动态添加3D对象

【WEB前端2024】3D智体编程&#xff1a;乔布斯3D纪念馆-第41课-动态添加3D对象 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界引擎…