堆的实现(C版)

2023-09-14 14:07:09

        普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

1.堆的概念及结构


堆的性质:

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


2.堆的实现

2.1建堆

        给定一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,这个时候就需要我们通过算法,把它构建成一个堆。根节点左右子树不是堆,我们从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成堆(向下调整)。

建堆时间复杂度

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

根据上图可以推算出:   建堆的时间复杂度为O(N)。

2.2堆的插入与删除

堆插入

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

堆删除

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

2.3堆的向下调整算法

        从堆顶开始,与子级节点进行比较,满足进行交换,一直到最后的叶子结点就结束.(公式:(n*2)+1),这里要注意的+1是找左1子树,+2是找右子树.(用于堆的删除操作)

       

2.4向上调整算法

        拿到子结点的位置,根据子节点的下标索引(公式:(n-1)/2),找到父级,跟父级进行比较,若满足则进行交换,直到交换到根结点. (用于堆的插入操作)

3.堆代码实现

typedef int HeapDataType;

typedef struct Heap
{
	HeapDataType* a;
	int size;  //有效元素
	int cpciti; //容量
}HP;
//初始化
void HeapInit(HP* hp);
//销毁
void HeapDestroy(HP* hp);
// 堆的插入
void HeapPush(HP* hp, HeapDataType x);
// 堆的删除
void HeapPop(HP* hp);
// 取堆顶的数据
HeapDataType HeapTop(HP* hp);
// 堆的数据个数
int HeapSize(HP* hp);
// 堆的判空
int HeapEmpty(HP* hp);
void HeapInit(HP* hp)
{
	assert(hp);
	hp->a = NULL;
	hp->size = hp->cpciti = 0;
}

void HeapDestroy(HP* hp)
{
	assert(hp);
	free(hp->a);
	hp->a = NULL;
	hp->size = hp->cpciti = 0;
}

void HeapPrintf(HP* hp)
{
	assert(hp);
	assert(hp->size > 0);
	for (int i = 0; i < hp->size; i++)
	{
		printf("%d ", hp->a[i]);
	}
	printf("\n");
}

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

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

void HeapPush(HP* hp, HeapDataType x)
{
	assert(hp);
	//
	if (hp->size == hp->cpciti)
	{
		int newCapacity = hp->cpciti == 0 ? 4 : hp->cpciti * 2;
		HeapDataType* tmp = (HeapDataType*)realloc(hp->a, sizeof(HeapDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		hp->a = tmp;
		hp->cpciti = newCapacity;
	}
	hp->a[hp->size] = x;
	hp->size++;
	AdjustUp(hp->a, hp->size-1);
}

void AdjustDown(HeapDataType* 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 HeapPop(HP* hp)
{
	assert(hp);
	assert(hp->size > 0);

	Swap(&hp->a[0], &hp->a[hp->size - 1]);
	hp->size--;

	AdjustDown(hp->a,hp->size,0);
}


HeapDataType HeapTop(HP* hp)
{
	assert(hp);
	assert(hp->size > 0);
	return hp->a[0];
}

int HeapSize(HP* hp)
{
	return hp->size;
}

int HeapEmpty(HP* hp)
{
	assert(hp);
	return hp->size == 0;
}

        本期的内容就是以上这些啦,希望大家动动小手指,给博主一键三连,大家的支持是我前行的最大动力。 

更多推荐

The Rise and Potential of Large Language Model Based Agents: A Survey

本文是LLM系列文章,针对《TheRiseandPotentialofLargeLanguageModelBasedAgents:ASurvey》的翻译。基于大型语言模型的Agent的兴起及其潜力摘要1引言2背景2.1AI代理的起源2.22.33Agent的诞生:基于LLM的Agent构建4实践中的代理:利用人工智能造

河北省2022年职业院校技能大赛高职组“软件测试”赛项竞赛任务书(样卷)

河北省2022年职业院校技能大赛高职组“软件测试”赛项竞赛任务书(样卷)2022年3月一、竞赛时间、内容及成绩组成(一)竞赛时间本次竞赛时间共为5小时,参赛选手自行安排任务进度,休息、饮水、如厕等不设专门用时,统一含在竞赛时间内。(二)竞赛内容本次竞赛考核技能点包括:功能测试计划制定、测试用例设计、测试执行和提交Bug

【ODPS新品发布第1期】DataWorks全新发布:增强分析/数据建模个人版等新能力

阿里云ODPS系列产品以MaxCompute、DataWorks、Hologres为核心,致力于解决用户多元化数据的计算需求问题,实现存储、调度、元数据管理上的一体化架构融合,支撑交通、金融、科研、等多场景数据的高效处理,是目前国内最早自研、应用最为广泛的一体化大数据平台。DataWorks新重点能力介绍新产品-Dat

docker报错Error response from daemon: Container xxx is not running

1.问题在移植了docker后,执行了sudodockerrun--namemyrosort-p80:80-drosort指令运行名为myrosort的容器,通过sudodockerps-a也可以看到确实运行了(base)neousys@neousys-Nuvo-5000:~/wqw/docker/20230915$s

MySQL 索引(一)

1.数据访问方式在MySQL中,通常有两种方式访问数据库表的行数据:顺序访问和索引访问。1.1.顺序访问顺序访问是在表中实行全表扫描,从头到尾逐行遍历,直到在无序的行数据中找到符合条件的目标数据。实现比较简单,但是当表中有大量数据的时候,效率非常低下。1.2.索引访问索引访问是通过遍历索引来直接访问表中记录行的方式。索

简单的手机电脑无线传输方案@固定android生成ftp的IP地址(android@windows)

文章目录abstractwindows浏览android文件环境准备客户端软件无线网络链接步骤其他方法手机浏览电脑文件公网局域网everythingpythonhttp.server高级:固定android设备IP准备检查模块是否生效windows访问ftp服务器快捷方式命令行方式双击启动方式普通快捷方式映射新的网络位

[TI] [Textual Inversion] An image is worth an word

自己的理解:根据几个图像,找出来一个关键字可以代表它们,然后我们可以再用这个关键字去生成新的东西。提出关键字1Introductionword->token->embeddingTextualInversion过程需要:①afixed,pre-trainedtext-to-imagemodel(一个固定的预训练模型)②

网络安全(黑客)自学

前言我是去年8月22日才正式学习网络安全的,因为在国营单位工作了4年,在广东一个月工资只有5000块,而且看不到任何晋升的希望,如果想要往上走,那背后就一定要有关系才行。而且国营单位的气氛是你干的多了,领导觉得你有野心,你干的不多,领导却觉得你这个人不错。我才24周岁,实在的受不了这种工作氛围,情绪已经压制了很多久,一

Java版本spring cloud + spring boot企业电子招投标系统源代码

项目说明随着公司的快速发展,企业人员和经营规模不断壮大,公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境,最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范,以及审计监督要求;通过电子化平台提高招投标工作的公开性和透明性;通过电子化招投标,使得招标采购的质量更高、速度

竞赛选题 基于深度学习的动物识别 - 卷积神经网络 机器视觉 图像识别

文章目录0前言1背景2算法原理2.1动物识别方法概况2.2常用的网络模型2.2.1B-CNN2.2.2SSD3SSD动物目标检测流程4实现效果5部分相关代码5.1数据预处理5.2构建卷积神经网络5.3tensorflow计算图可视化5.4网络模型训练5.5对猫狗图像进行2分类6最后0前言🔥优质竞赛项目系列,今天要分享

close和fclose

在Linux系统中,close函数并不会主动调用fsync接口。close函数只是关闭了文件描述符,而不保证数据被写入到磁盘。如果你想确保数据被写入到磁盘,你需要在close函数之前调用fsync函数。这是因为Linux使用了缓存机制来提高磁盘的读写性能,当你写入数据时,数据首先被写入到缓存中,然后在适当的时候(例如缓

热文推荐