堆的实现(偷懒版)

news2024/9/24 19:20:16

                           🌹个人主页🌹:喜欢草莓熊的bear

                           🌹专栏🌹:数据结构


目录

前言

一、堆的实现

1.1 堆的向下调整算法

思路:

1.2 堆的向上调整算法

1.3 堆的创建

1.4 堆的复杂度计算

向下调整建堆的复杂度:

  向上调整建堆的复杂度:

1.5 堆的插入

1.6 堆的删除

1.7 堆的代码实现

总结


前言

在上期内容介绍了二叉树、还简单提了一下堆的概念和大堆、小堆。回顾一下堆是首先是完全二叉树,因为是完全二叉树所以使用数组储存比较合理。

一、堆的实现

1.1 堆的向下调整算法

现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。
给上一个例子
int arr[] = {27,15,19,18,28,34,65,49,25,37};

 上面这幅图就是向下调整的算法的过程图

思路:

 假设我们通过向下调整算法建立小堆,我们就需要从根的左右子树开始,比较得出左右子树小的那一个和根比较,谁小谁就是根。我们之前还介绍父亲节点和孩子节点的概念,我们这里就要使用到。根据我们上面的思路,向下调整算法需要通过比较还在节点后进行调整。所以我们需要知道父亲节点然后再找到孩子节点为什么要知道父亲节点呢?我们通过数组储存着堆,下标就可以帮助我们找到孩子节点。

 大致思路就是这样我们来写代码:

void Swap(HPDataType* x, HPDataType* y)//交换数据
{
	HPDataType tmp = *x;
	*x = *y;
	*y = tmp;
}


void ADjustDown(HPDataType* a, int n,int parent)//向下调整
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		//假设法
		if (a[child] > a[child + 1] && child + 1 < n)//比较左右子树,找到较小的子树。
		{
			child++;
		}
		if (a[parent] > a[child])//数据交换
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

 解释一下个别代码,child + 1  < n 防止数组越界。 

1.2 堆的向上调整算法

 向上调整我们需要从最后一层向上调整,所以我们是通过孩子节点得到父亲节点。大致思路和向下调整一样,比较孩子节点的大小后再和父亲节点比较一直比较到根节点。根据child = parent *2+1 反推得到 parent = ( child -1 )/2 。

直接上代码:

void Swap(HPDataType* x, HPDataType* y)//交换数据
{
	HPDataType tmp = *x;
	*x = *y;
	*y = tmp;
}

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;
		}
	}
}

1.3 堆的创建

下面我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。根节点左右子树不是堆,我们怎么调整呢?这里我们从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成堆。
给上一个例子:
int a[] = {1,5,3,8,7,6};

1.4 堆的复杂度计算

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

向下调整建堆的复杂度:

  向上调整建堆的复杂度:

是O(N) = N * logN 得到方法和向下调整一样推导就可以了。

1.5 堆的插入

先插入一个 10 到数组的尾上,再进行向上调整算法,直到满足堆。

 堆的插入需要用的向上调整

1.6 堆的删除

删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。

 

1.7 堆的代码实现

堆的初始化、销毁都是很简单和之前写的栈啊等等都十分相似。剩下一些 获取堆顶元素、堆的个数、堆的判断都比较简单就不讲解了给上了代码。

typedef int HPDataType;

typedef struct Heap//因为堆的定义就是满二叉树与完全二叉树,用数组储存非常好。
{
	HPDataType* a;//数组
	int size;
	int capacity;
}Heap;

//小堆情况下的初始化
void HPInit(Heap* php)
{
	assert(php);
	php->a = NULL;

	php->size = php->capacity = 0;
}

//销毁
void HPDestory(Heap* php)
{
	assert(php);
	free(php->a);

	php->a = NULL;
	php->size = php->capacity = 0;
}

void Swap(HPDataType* x, HPDataType* y)//交换数据
{
	HPDataType tmp = *x;
	*x = *y;
	*y = tmp;
}

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;
		}
	}
}

void ADjustDown(HPDataType* a, int n,int parent)//向下调整
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		//假设法
		if (a[child] > a[child + 1] && child + 1 < n)
		{
			child++;
		}
		if (a[parent] > a[child])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//入堆
void HPPush(Heap* 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("ralloc fail");
			return;
		}
		php->a = tmp;
		php->capacity = Newcapacity;
	}
	php->a[php->size++] = x; 

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

//出堆(消除堆顶数据)
void HPPop(Heap* php)
{
	assert(php);
	assert(php->size > 0);
	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;

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

//取堆顶数据
HPDataType HPTop(Heap* php)
{
	assert(php);
	assert(php->size > 0);

	return php->a[0];
}

//堆的数据个数
int HPSize(Heap* php)
{
	assert(php);

	return php->size;
}

//堆的判空
bool HPEmpty(Heap* php)
{
	assert(php);
	return php->size == 0;
}

总结

本节重点堆的向上、向下调整算法的代码实现 和 复杂度计算。

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

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

相关文章

4款智能ai 写作工具助你探索智能写作的无限可能!

智能 AI 写作已经成为一个十分热门的工具。因为它可以从新闻报道到小说创作&#xff0c;从广告文案到学术论文&#xff0c;各个领域都可以给我们很有效的写作帮助。今天&#xff0c;我就给大家介绍4个在网上非常火的智能AI 写作工具。 1、笔灵写作助手 直通车 :https://ibilin…

基于Java中的SSM框架实现软件bug管理系统项目【项目源码+论文说明】计算机毕业设计

基于Java中的SSM框架实现软件bug管理系统演示 摘要 随着我们的智能生活到来&#xff0c;人们越来越意识到计算机生活在工作中的重要性&#xff0c;职场上大部分职业都是需要我们会熟练运用计算机知识的&#xff0c;所以我们要掌握计算机技能&#xff0c;这样才能在以后的职业生…

【学习笔记】Matlab和python双语言的学习(多目标规划)

文章目录 前言一、多目标规划1.特点2.一般形式3.多目标规划的解4.线性加权法 二、典型示例-----化工厂生产问题三、代码实现----Matlab四、代码实现----python总结 前言 通过模型算法&#xff0c;熟练对Matlab和python的应用。 学习视频链接&#xff1a; https://www.bilibili…

XJTUSE-离散数学-关系

集合的叉积 二元组(a,b) (a,b) (c,d) <> ac,bd m元组 叉积的结合律 关系 R 是 的子集&#xff0c;称为一个二元关系 前域&#xff0c;后域的概念 关系的表示方法 图表示法 矩阵表示法 关系的运算 逆运算: 逆运算的一些定理 复合关系 and 闭包运算 …

如何创建一个Gralde项目

如何创建一个Gralde项目 1. 使用IDEA创建一个Gradle项目&#xff1a; 1.1 打开Idea&#xff0c;新建项目&#xff1a; 选择File-> New -> Project 1.2 在项目类型列表中找到并选择Gradle 1.3 验证Gradle项目 可以通过运行 gradle.tasks 命令来验证项目是否正确创建&a…

【C++ Primer Plus】学习笔记 5

文章目录 前言一、指针和自由存储空间1. 声明和初始化指针2. 指针的危险3. 指针和数字4. 使用 new 来分配内存5. 使用 delete 释放内存6. 使用 new 来创建动态数组1.使用new创建动态数组2.使用动态数组 二、指针、数组和指针算术1. 指针小结1.声明指针2.给指针赋值3.对指针解除…

PCL 曲线4点细分算法

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 四点细分算法(Four-Point Subdivision Scheme)是一种用于生成平滑曲线的细分算法。与 Chaikin 逼近型细分算法不同,四点细分算法通过插入新的控制点来细化曲线,并生成一条逐步逼近的平滑曲线。该算法通常用于生…

Vue组件间传值总结

1.组件可以由内部的Data提供数据展示&#xff0c;也可以由父组件ajax取到数据后通过prop的方式传值进子组件。 样例: 子组件电影组件&#xff0c;展示标题和评分&#xff0c;声明属性props:["title","rating"] <template><div><h1>{{…

8.8作业

LVS 四层结构&#xff08;最多实现到iso第四层&#xff1a;传输层的功能 部署NAT模式集群案例 创建3台主机&#xff0c;分别为&#xff1a;lvs 、 webserver1 、 webserver2&#xff0c;其中lvs有两张网卡分别是net网卡为外网和仅主机内网 主机名网卡IP地址网关 lvsnet和主机…

哪些区块链有利可图?揭秘最赚钱公链背后的数据!

今天&#xff0c;我们将探索按收⼊排名前4位的L1和L2&#xff0c;并探讨这些区块链实际保留了多少收⼊。毕竟&#xff0c;收入能力是判断一条链是否能持续发展的重要之标之一。在此&#xff0c;我们将收益定义为&#xff1a;总收⼊减去代币发⾏量。 Layer 1 以太坊Ethereum 就…

LeeCode Practice Journal | Day37_DP05

完全背包 有N件物品和一个容量为W的背包&#xff0c;第 i 件物品的重量是weight[ i ]&#xff0c;价值为value[ i ]&#xff0c;每件物品都有无限个&#xff0c;求解使用背包物品价值总和达到最大的装包方案 二维 static int CompleteKnapsack2D(int[] weights, int[] value…

第三篇远程连接工具介绍及使用

目录 一、远程连接工具的介绍 1、作用 2、常用的远程连接工具 1) XShell 2) FinalShell 3) PuTTY 4) SecureCRT 5) MobaXterm 6) WinSCP 7) NxShell 3、Xshell 安装使用 1&#xff09;Xshell 安装 2&#xff09;Xshell 使用​编辑 4、Finalshell 安装使用 1&…

C++初学者指南-5.标准库(第二部分)--排序序列操作

C初学者指南-5.标准库(第二部分)–排序序列操作 文章目录 C初学者指南-5.标准库(第二部分)--排序序列操作二分查找binary_searchlower_boundupper_boundequal_rangeincludes 合并mergeinplace_merge 设置操作set_unionset_intersectionset_differenceset_symmetric_difference …

最“抠门”千亿儿媳,一件衣服穿五年!

文&#xff5c;琥珀食酒社 作者 | 积溪 我真是震惊了&#xff01; 刚刚刷奥运会 看解说员介绍称呼 说跳水名将郭晶晶和他的先生 我才知道霍家对郭晶晶的夸奖 绝非随口一说 她跟很多嫁入豪门的人 不一样 因为太“抠门”了 身为霍家儿媳妇 身价千亿的郭晶晶 一个头绳…

C++STL~~string

文章目录 一、string类的发展历史二、string的使用三、string的练习四、总结 一、string类的发展历史 在C 的早期版本中&#xff0c;处理字符串主要依赖于 C 风格的字符数组。但这种方式存在诸多不便&#xff0c;如手动管理内存、容易出现缓冲区溢出等问题。随着 C 标准的不断…

使用Linux实现FTP云盘1

关于FTP服务器 FTP&#xff08;文件传输协议&#xff09;服务器是在互联网上提供文件存储和访问服务的计算机&#xff0c;它们依照FTP 协议提供服务。 FTP是File Transfer Protocol(文件传输协议)。 程序运行&#xff0c;服务端不断接收客户端指令&#xff0c;服务 端可同时处…

一文概叙自制舵机云台

本文主要涉及选择合适的舵机、设计云台结构、编写控制代码以及组装调试等步骤。以下是一个详细的制作流程&#xff1a; 一、材料准备 1、舵机&#xff1a; 通常需要至少两个舵机&#xff0c;一个用于控制云台的左右旋转&#xff0c;另一个用于控制云台的上下倾斜。先以简单的…

渲染引擎实践 - UnrealEngine引擎 GLContext 创建过程

一:概述: 本文分析下 UnrealEngine 启动过程中创建多少个 OpenGL Context,以及这些 Context 的作用。 二:临时Context 1. PreInit -> PreInitPreStartupScreen -> PreloadResolutionSettings, 用于检查图形窗口分辨率 2. PreInit -> PreInitPreStartupScreen -&…

高效清理优化工具 Sonoma Cache Cleaner mac 19.0.6注册激活版

Sonoma Cache Cleaner 是一款专为 Mac 系统设计的强大清理优化工具。它能够深度扫描系统&#xff0c;清理各类缓存文件&#xff0c;释放宝贵的存储空间。不仅如此&#xff0c;还能优化系统性能&#xff0c;让您的 Mac 运行更加流畅快捷。无论是系统日志、临时文件还是浏览器缓存…

ArcGIS基础:以分数形式进行标注字段

分数形式标注在项目或者工作中可能会用到 基于VBScript进行分式标注的通用形式为&#xff1a; "<und>"&""& 分子字段&""&"</und>"&vbNewLine& 分母字段按下述顺序进行操作标注 "<und…