二叉堆的实现

文章目录

    • 堆的概念及性质
  • 二叉堆的实现
    • Heap.h
    • Heap.c
      • 堆的初始化
      • 堆的销毁
      • 向堆中插入数据
      • 删除堆中的数据
      • 找堆顶元素
      • 判断堆是否为空
      • Heap.c完整代码
    • test.c

堆的概念及性质

在这里插入图片描述
在这里插入图片描述

二叉堆的实现

Heap.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

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

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

Heap.c

堆的初始化

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

堆的本质是数组,初始化让数组首地址指向空,数组大小(元素个数)和容量赋值为0.

堆的销毁

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

首先断言确保传入的堆存在,再释数组地址并置空,将数组大小和容量重置为0

向堆中插入数据

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");
			exit(-1);
		}
		php->a = tmp;
		php->capacity = newcapacity;
	}
	php->a[php->size] = x;
	php->size++;
	Adjustup(php->a, php->size - 1);
}

前面先判断数组的空间是否足够,不够要先进行扩容,用newcapacity代表新数组的容量,如果初始容量为0则给newcapacity赋值为4,如果一开始有容量就将容量扩大为原来的2倍。(为什么扩容2倍呢?因为如果选更大的倍数扩容容易浪费过多的内存空间,而每次扩容太少又容易造成多次扩容的情况,增加算法是时间复杂度。)扩容完后将a指向新扩容的地址,新的容量赋值给capacity。如果扩容失败程序结束。

	php->a[php->size] = x;
	php->size++;
	Adjustup(php->a, php->size - 1);

之后将要插入的值赋给a的末位,然后根据堆的性质要对新插入的数进行位置调整,这里将向上调整用另一个函数实现。

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

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

这里实现的是大堆(根节点最大)的向上调整,swap函数对要调整的两值进行交换,首先我们要知道在二叉堆中子节点和父节点的关系。
在这里插入图片描述
有图可以看出56和30是70的第一,第二孩子,我们很容易得到他们的下标关系,孩子1的下标是父节点下标的2倍+1,孩子2的下标是父节点下标的2倍+2。由此我们能反推父节点的下标是(子节点下标-1)/2(整数的除法省略小数,故2个孩子这样计算的结果都是父节点的下标)。接下来就是判断大小,子节点的数大就和父节点交换,再和新的父节点比较,直到找到合适的位置或称为根节点就调整完成了。

删除堆中的数据

删除堆中的数据之前我们要先考虑删除数据后的效果,因为我们堆的性质是根节点最大或最小,所以删根节点能让我们找出堆中数据的大小循序。首先我们直接删根节点的数据试试,在上图的大堆中,我们如果直接把70删去,那么重新构成大堆就要下面的数据一一向上调整,很麻烦。所以我们不妨将根节点和尾节点交换位置,交换后将就的根节点删除,新的根节点执行一次向下调整就好了。

void HPPop(HP* php)
{
	assert(php);
	assert(php->size > 0);
	php->a[0] = php->a[php->size - 1];
	php->size--;
	Adjustdown(php->a, php->size, 0);

}

这里同样将向下调整放在另一函数里

void Adjustdown(HPDataType* a, int size,int parent)
{
	int child = parent * 2 + 1;
	while (child < size)
	{
		if (child+1<size&&a[child + 1] >a[child])
		{
			child++;
		}
		if (a[parent] <a[child])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

大堆中向下调整是和子节点中大的值交换,一开始我们不知道哪个子节点是更大的,所以不妨假设第一个子节点最大,如果假设不成立就让子节点++,变成第二子节点

	if (child+1<size&&a[child + 1] >a[child])
		{
			child++;
		}

找堆顶元素


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

判断堆是否为空

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

这里判空的作用便于遍历堆的元素。

Heap.c完整代码

#include"Heap.h"

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


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

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

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

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");
			exit(-1);
		}
		php->a = tmp;
		php->capacity = newcapacity;
	}
	php->a[php->size] = x;
	php->size++;
	Adjustup(php->a, php->size - 1);
}

void Adjustdown(HPDataType* a, int size,int parent)
{
	int child = parent * 2 + 1;
	while (child < size)
	{
		if (child+1<size&&a[child + 1] >a[child])
		{
			child++;
		}
		if (a[parent] <a[child])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}


void HPPop(HP* php)
{
	assert(php);
	assert(php->size > 0);
	php->a[0] = php->a[php->size - 1];
	php->size--;
	Adjustdown(php->a, php->size, 0);

}


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

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

test.c

接下来看看我们实现的大堆的效果,第一行是打印堆的元素,第二是利用堆来排序

#include"Heap.h"

int main()
{
	HP hp;
	HPInit(&hp);
	int a[] = { 2,8,6,49,5,3,11,3,7 };
	for (int i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		HPPush(&hp, a[i]);
	}
	for (int i = 0; i < 9; i++)
	{
		printf("%d ", hp.a[i]);
	}
	printf("\n");
	while (!HPEmpty(&hp))
	{
		printf("%d ", HPTop(&hp));
		HPPop(&hp);
	}
	return 0;

在这里插入图片描述

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

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

相关文章

SSM校园学习助手系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM 校园学习助手系统是一套完善的信息系统&#xff0c;结合springMVC框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模…

HTML—列表、表格、表单

1、列表 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表 1.1 无序列表 作用&#xff1a;布局排列整齐的不需要规定顺序的区域 标签&#xff1a;ul 嵌套 li&#xff0c;ul 是无序列表&#xff0c;li 是列表条目 注意事项&#…

Microsoft Remote Desktop高效、安全、稳定的远程办公解决方案

在今天的数字化时代&#xff0c;Remote Desktop远程办公已成为许多人的日常生活。无论你是因为工作需要&#xff0c;还是因为在家中需要访问公司服务器&#xff0c;微软远程连接软件都是一个理想的选择。 微软远程连接软件Remote Desktop是一款高效、安全、稳定的远程办公解决…

(动手学习深度学习)第13章 实战kaggle竞赛:树叶分类

文章目录 实战kaggle比赛&#xff1a;树叶分类1. 导入相关库2. 查看数据格式3. 制作数据集4. 数据可视化5. 定义网络模型6. 定义超参数7. 训练模型8. 测试并提交文件 竞赛技术总结1. 技术分析2. 数据方面模型方面3. AutoGluon4. 总结 实战kaggle比赛&#xff1a;树叶分类 kagg…

数据库管理-第119期 记一次迁移和性能优化(202301130)

数据库管理-第119期 记一次迁移和性能优化&#xff08;202301130&#xff09; 1 迁移 之前因为DV组件没有迁移成功的那个PDB&#xff0c;后来想着在目标端安装DV组件迁移&#xff0c;结果目标端装不上&#xff0c;而且开了SR也没看出个所以然来。只能换一个方向&#xff0c;尝…

云计算生成式 -给你不一样的音乐推荐新体验

目录 摘要&#xff1a; 正文&#xff1a; 一、亚马逊云与生成式 AI 结合的展望/总结 二、我用亚马逊云科技生成式 AI 产品打造了什么&#xff0c;解决了什么问题 三、未来云端技术发展趋势的见解 四、云端技术未来需要解决的问题 1、如何保护数据安全和隐私&#xff1f; …

虚拟机系列:Oracle VM VirtualBox安装/更新/卸载出现 无法访问你试图使用的功能所在的网络位置

Oracle VM VirtualBox安装/更新/卸载出现 无法访问你试图使用的功能所在的网络位置 Oracle VM VirtualBox安装/更新/卸载出现 无法访问你试图使用的功能所在的网络位置Oracle VM VirtualBox安装/更新/卸载出现 无法访问你试图使用的功能所在的网络位置 在更新Oracle VM Virtua…

STC15-串口通信打印输出数据printf函数与sprintf函数

STC15-串口通信打印输出数据printf函数与sprintf函数 1.打印输出数据有二种printf函数与sprintf函数&#xff0c;不同之处有&#xff1a;&#xff08;1&#xff09;函数的声明不同&#xff08;2&#xff09;函数的功能不同&#xff08;3&#xff09;用法举例 该问题引用百度知道…

【面试HOT200】回溯篇

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于【CodeTopHot300】进行的&#xff0c;每个知识点的修正和深入主要参…

恒驰服务 | 华为云云上运维服务offering

恒驰运维服务主要针对运维要求高或自身运维能力有限的客户&#xff0c;通过服务增购的形式&#xff0c;提供运维服务以协助客户做好云上资源运维管理&#xff0c;规避业务风险&#xff0c;降低运维开销&#xff0c;提升客户业务稳定性。 适用场景&#xff1a; 如何保障业务稳定…

音乐播放器Swinsian mac功能介绍

Swinsian mac是一款音乐播放器&#xff0c;它的特点是轻量级、快速、易用。Swinsian支持多种音频格式&#xff0c;包括MP3、AAC、FLAC、WAV等。它还具有iTunes集成功能&#xff0c;可以自动导入iTunes音乐库中的音乐&#xff0c;并支持智能播放列表、标签编辑、自定义快捷键等功…

ssh连接docker容器处理备忘

1、查看容器ip&#xff0c;记下来之后要用 docker inspect elastic | grep IPAddress 2、使用root进入docker容器 docker exec -it -u root elastic /bin/bash 3、安装openssh #更新apt apt-get update#安装ssh client apt-get install openssh-client#安装ssh server apt-…

Ps:用好钢笔工具

使用钢笔工具时&#xff0c;应随时注意鼠标指针的形状。 ◆ ◆ ◆ 基本操作方法 1、绘制闭合路径 路径绘制结束时回到起点即可创建闭合路径。 2、绘制开放路径 想结束绘制时&#xff0c;按住 Ctrl 键点击画布空白处&#xff0c;或者&#xff0c;直接按 Esc 键&#xff0c;即可…

STM32的看门狗原理和示例代码

看门狗基础&#xff1a; STM32微控制器上的看门狗主要有两种类型&#xff1a;独立看门狗&#xff08;IWDG&#xff09;和窗口看门狗&#xff08;WWDG&#xff09;&#xff0c;这两者都是用于监控系统运行状态的机制&#xff0c;但它们在实现和应用上有一些区别&#xff1a; 独立…

docker buildx跨架构构建笔记(x86_64构建下构建aarch64镜像)

docker buildx跨架构构建(x86_64构建aarch64镜像) 文章目录 docker buildx跨架构构建(x86_64构建aarch64镜像)简介第一步 先交叉编译一个aarch64的HelloWorld程序。准备一个用于跨架构的Dockerfile文件使用docker buildx命令构建aarch64架构的镜像。查看镜像具体详细信息&#…

建堆的时间复杂度和堆排序

文章目录 建堆的时间复杂度向下调整建堆向上调整建堆 堆排序实现 建堆的时间复杂度 下面都以建大堆演示 向下调整建堆 void Adjustdown(HPDataType* a, int size,int parent) {int child parent * 2 1;while (child < size){if (child1<size&&a[child 1] &…

【shell】正则表达式和AWK

一.正则表达式 通配符匹配文件&#xff08;而且是已存在的文件&#xff09; 基本正则表达式扩展正则表达式 可以使用 man 手册帮助 正则表达式&#xff1a;匹配的是文章中的字符 通配符&#xff1a;匹配的是文件名 任意单个字符 1.元字符&#xff08;字符匹配&…

【2023CANN训练营第二季】——Ascend C算子调用及实验演示

自定义算子调用方式 完成自定义算子的开发部署后&#xff0c;可以通过单算子调用的方式来验证单算子的功能。单算子调用有API执行和模型执行两种方式&#xff1a; 单算子API执行&#xff1a;基于C语言的API执行算子&#xff0c;无需提供单算子描述文件进行离线模型的转换&…

IDEA性能优化的相关配置

有时候会发现idea用起来特别卡&#xff0c;你会发现不是整个电脑卡&#xff0c;而是idea用起来卡。这时候就需要对idea做一下性能优化了。 首先我们把idea的内存调出来&#xff1a;可以右击idea底部然后点这个Memory Indicator&#xff0c;然后就能看到idea使用的内存了。 为什…