堆及其接口实现(图示超详解哦)

news/2024/5/20 9:54:41 标签: 开发语言, 数据结构, 算法, c语言,

全文目录

  • 引言
  • 接口实现
    • 的构建与销毁
    • 中插入数据
    • 中删除数据
    • 访问顶数据
    • 计算中数据个数
    • 判断是否为空
  • 总结

引言

上一篇文章中,介绍了二叉树的相关基础知识。
并且了解到二叉树的表示有两种结构:顺序结构与链式结构。即,使用顺序表或链表来表示二叉树:
戳我看树与二叉树详解哦

在这篇文章中就将介绍这种数据结构。并使用顺序结构来表示
(需要注意的是这里的和操作系统虚拟进程地址空间中的是两个定义:一个是数据结构,一个是操作系统中管理内存的一块区域分段)

如果有一个数据的集合,把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:根结点的值始小于(或大于)子结点的值。
将根结点最大的叫做最大或大根,根结点最小的叫做最小或小根
(需要注意的是,是一种完全二叉树。所以我们在表示时,用顺序表来存储会更方便)
在这里插入图片描述
在上面的是逻辑结构,下面的数组是顺序结构。每一个结点的数据都对应着数组中的一个位置,该位置对应着一个下标。

对于结点数据的下标与结点位置,有着一些规律:
父亲结点的下标 = (孩子结点下标-1)/2;
左孩子结点的下标 = 父亲结点的下标2+1;
右孩子结点的下标 = 父亲结点的下标
2+2。

这些规律使我们在根据逻辑结构访问中的元素时,会很方便。

接下来就可以尝试实现的各种接口:

接口实现

与顺序表类似,在实现之前,我们需要创建一个结构体变量,用来存储数组、容量与数据个数:

typedef int HPDataType;

typedef struct Heap
{
	HPDataType* data;
	int size;
	int capacity;
}Heap;

的构建与销毁

构建时,我们需要为数据开辟出一块物理结构。我们可以动态开辟一块空间来存储数据;并且将元素个数初始化为0;将的容量初始化为10:

// 的构建
void HeapCreate(Heap* php, int n)
{
	assert(php);
	php->data = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (php->data == NULL)
	{
		perror("malloc");
		return;
	}
	php->size = 0;
	php->capacity = n;
}

销毁时,我们直接free释放动态开辟的数组,然后将结构体中的值全部初始化为0即可:

// 的销毁
void HeapDestory(Heap* php)
{
	assert(php);
	free(php->data);
	php->capacity = 0;
	php->size = 0;
}

中插入数据

创建好存储数据的空间后,就可以在这个空间中存储数据了。

前面提到,有大与小之分。这次我们就先实现在大中插入数据:
对于数组而言,显然是尾插更加方便。当然,在插入数据之前,需要判断是否已满:若已满,则需要realloc扩容。然后将下标为size的元素赋值为x,size++即可;

但是在尾插一个数据后,我们需要调整新插入的数据的位置,保证依旧是一个大。为了实现这样的目的,我们需要一个函数,可以实现比较逻辑结构中父子结点的值:若子节点的值小于父亲结点的值,就将父子结点的值交换,直到再次形成一个大。(这个过程称为向上调整建
由子节点访问父亲结点时,根据上面提到的数组中的下标的规律即可:
在这里插入图片描述

当然,为了交换方便,我们可以将交换的操作初始化为一个Swap函数:

//交换
void Swap(Heap* php, int a, int b)
{
	assert(php);
	int temp = php->data[a];
	php->data[a] = php->data[b];
	php->data[b] = temp;
}

//向上调整
void AdjustUp(Heap* php, int child)
{
	assert(php);
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (php->data[child] > php->data[parent])
		{
			Swap(php, child, parent);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
// 的插入
void HeapPush(Heap* php, HPDataType x)//尾插,大者为爹,尾向上交换
{
	assert(php);
	if (php->size == php->capacity)
	{
		HPDataType* tempptr = (HPDataType*)realloc(php->data, sizeof(HPDataType) * php->capacity * 2);
		if (tempptr == NULL)
		{
			perror("realloc");
			return;
		}
		else
		{
			php->data = tempptr;
			php->capacity *= 2;
		}
	}
	php->data[php->size] = x;
	php->size++;
	AdjustUp(php, php->size - 1);
}

中删除数据

我们发现,对于大而言,顶的元素永远是最大的那个元素,而下面的元素的大小顺序就不确定了;对于小而言顶的元素是最小的。所以我们在删除中数据时,删除顶的元素是有意义的。

在删除顶元素时,如果直接用后面的元素覆盖前面的元素,就会导致的结构完全乱序,调整起来就会很麻烦。这里提供一种先交换后调整的思路(对于大):
首先将顶的元素与尾的元素交换,然后size–,将原顶的元素删除。这样可以保证除顶元素外,其他位置的结构都是完好的;
然后从顶开始,比较父亲结点与较大的子结点的值,若父亲结点小于较大的子节点,则交换它们的值。直到再次形成大:(这个过程称为向下调整建
由父亲节点访问子结点时,根据上面提到的数组中的下标的规律即可:
在这里插入图片描述

//向下调整
void AdjustDown(Heap* php, int parent)//交换爹与大儿子
{
	assert(php);
	int child = parent * 2 + 1;//默认大儿子为左儿子
	while (child < HeapSize(php))
	{
		if (child + 1 < HeapSize(php) && php->data[child + 1] > php->data[child])
		{
			child += 1;
		}
		if (php->data[parent] < php->data[child])
		{
			Swap(php, parent, child);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

// 的删除
void HeapPop(Heap* php)//首尾交换,去尾,头向下交换
{
	assert(php);
	Swap(php, 0, php->size - 1);//交换
	php->size--;//去尾
	AdjustDown(php, 0);//由根开始向下调整
}

访问顶数据

访问顶数据时,即访问数组中的第一个元素:

// 取顶的数据
HPDataType HeapTop(Heap* php)
{
	assert(php);
	return php->data[0];
}

计算中数据个数

计算中数据个数时,即结构体变量中的size变量的值:

// 的数据个数
int HeapSize(Heap* php)
{
	assert(php);
	return php->size;
}

判断是否为空

判断是否为空时,当size为0时,返回真;否则返回假:

// 的判空:为空返回真
int HeapEmpty(Heap* php)
{
	assert(php);
	return php->size == 0;
}

总结

到此,关于数据结构的介绍就结束了,也就是二叉树的顺序结构
在下一篇文章中将介绍二叉树的链式结构及一些题目详解,欢迎大家持续关注哦

如果大家认为我对某一部分没有介绍清楚或者某一部分出了问题,欢迎大家在评论区提出

如果本文对你有帮助,希望一键三连哦

希望与大家共同进步哦


http://www.niftyadmin.cn/n/204562.html

相关文章

硬件语言Verilog HDL牛客刷题day05时序逻辑部分(2)

1.VL33 非整数倍数据位宽转换8to12 1.题目&#xff1a; 实现数据位宽转换电路&#xff0c;实现8bit数据输入转换为12bit数据输出。其中&#xff0c;先到的数据应置于输出的高bit位。 电路的接口如下图所示。valid_in用来指示数据输入data_in的有效性&#xff0c;valid_out用…

debian系统应用进程启动失败问题分析

现象描述 设备网络灯显示异常&#xff0c;通过串口登录到设备&#xff0c;启动网络服务时&#xff0c;系统显示信息如下&#xff1a; rootlinux:~# systemctl start network_5g [ OK ] Stopped Emergency Shell. [FAILED] Failed to mount /proc/bus/usb. See systemctl sta…

【python】Jupyter的使用(python代码编辑器)

文章目录一、Jupyter的介绍1、Jupyter是什么&#xff1f;2、Jupyter有什么独特之处&#xff1f;二、Jupyter的安装1、首先要下载python2、用pip命令下载Jupyter三、Jupyter的使用1、运行Jupyter2、简要介绍Jupyter的使用方法3、快捷键的使用四、总结一、Jupyter的介绍 1、Jupy…

8、SpringMVC自动配置概览

文章目录1、SpringMVC自动配置概览【尚硅谷】SpringBoot2零基础入门教程-讲师&#xff1a;雷丰阳 笔记 路还在继续&#xff0c;梦还在期许 1、SpringMVC自动配置概览 Spring Boot provides auto-configuration for Spring MVC that works well with most applications.(大多场…

Java知识点学习(第4天)

Tomcat中为什么使用自定义加载器&#xff1f; Tomcat去部署应用的时候&#xff0c;可能会有两个类的类名完全一样&#xff0c;即使两者的内容完全不一样&#xff0c;但Tocat是通过WebAppClassLoader去加载自己的类的&#xff0c;因为在加载完第一个类之后&#xff0c;想要再去…

创维跨界脑洞大 XR+汽车=睡眠?

4月1日&#xff0c;造车新势力的3月交付/销售成绩单出来了&#xff0c;比亚迪、广汽埃安分别以207080辆和40016辆分列冠亚军&#xff0c;“蔚小理”仍以过万辆或近万辆处于Top10。品牌名单里最突兀的新势力是创维汽车&#xff0c;以1282辆位列第15&#xff0c;上个月的数字是14…

MySQL数据库基础初学者必备知识

目录 1.数据库的基本操作 1.1显示所有数据库 1.2创建数据库 1.3删除数据库 2.数据库的类型 2.1数值类型 2.2字符串类型 2.3日期类型 3.表的简单操作 3.1创建一个表 3.2显示表的结构 3.3显示数据库中的所有表 3.4删除指定表 4.实战练习 1.数据库的基本操作 数据库…

JSch使用教程

JSch使用教程 第 1 章 JSch简介 JSch是ssh2的一个纯Java实现。它允许你连接到一个sshd服务器&#xff0c;使用端口转发、X11转发、文件传输等。 SSH 是专为远程登录会话和其他网络服务提供安全性的协议 Ftp 协议通常是用来在两个服务器之间传输文件的 SFTP 可理解为SSH FTP&…