【数据结构】堆的实现

目录

一、堆的概念

1.概念:

2.性质

二.堆的实现

[1.用数组定义堆结构struct Heap](#1.用数组定义堆结构struct Heap)

2.交换两个数swap函数

3.向下调整算法AdjustDown函数

4.向上调整算法AdjustUp函数

5.初始化堆HeapInit函数

6.销毁堆HeapDestory函数

7.堆的插入HeapPush函数

8.堆的删除HeapPop函数

[9.取堆顶数据 HeapTop函数](#9.取堆顶数据 HeapTop函数)

[10.取堆数据个数 HeapSize函数](#10.取堆数据个数 HeapSize函数)

[11.堆判空 HeapEmpty函数](#11.堆判空 HeapEmpty函数)


一、堆的概念

1.概念:

堆是将一个完全二叉树以顺序存储方式存储在数组中的一个数据结构,这颗完全二叉树需满足父节点的值大于等于(小于等于)孩子节点的值。
将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆的逻辑结构为完全二叉树,物理结构为一维数组

2.性质

(1)堆中某个节点的值总是不大于或不小于其父节点的值;(整个树所有结点需保持同一个规律,。要大于等于,都大于等于。反之同理)

(2)堆逻辑总是一棵完全二叉树

注:

一个升序(降序)的数组一定是堆

但堆的数组不一定就是升序(降序)

二.堆的实现

1.用数组定义堆结构struct Heap
cpp 复制代码
typedef struct Heap
{
	HPDataType* _a;
	int _size;
	int _capacity;
}Heap;
2.交换两个数swap函数
cpp 复制代码
void swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
3.向下调整算法AdjustDown函数

现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整 成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

cpp 复制代码
int array[] = {27,15,19,18,28,34,65,49,25,37};

向下调整过程如图:

cpp 复制代码
//小堆
void AdjustDown(Heap* hp, int parent)
{
	int child = parent * 2 + 1;
	while (child<hp->_size)
	{
		//判断是否存在右孩子,且值小于左孩子
		if (child + 1 < hp->_size && hp->_a[child + 1] < hp->_a[child])
		{
			child++;
		}

		//判断parent节点和child节点的大小
		if (hp->_a[child] < hp->_a[parent])
		{
			swap(&(hp->_a[child]), &(hp->_a[parent]));
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
4.向上调整算法AdjustUp函数

前提:插入前逻辑上为堆(大堆or小堆)

cpp 复制代码
//按小堆检查
void AdjustUp(Heap* hp, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (hp->_a[parent] > hp->_a[child])
		{
			int tmp = hp->_a[child];
			hp->_a[child] = hp->_a[parent];
			hp->_a[parent] = tmp;
		}
		else
		{
			break;
		}
		child = parent;
		parent = (child - 1) / 2;
	}
}
5.初始化堆HeapInit函数
cpp 复制代码
//初始化堆
void HeapInit(Heap* hp)
{
	assert(hp);
	hp->_a = NULL;
	hp->_capacity = hp->_size = 0;
}
6.销毁堆HeapDestory函数
cpp 复制代码
// 堆的销毁
void HeapDestory(Heap* hp)
{
	free(hp->_a);
	free(hp);
	hp = NULL;
}
7.堆的插入HeapPush函数
cpp 复制代码
// 堆的插入
void HeapPush(Heap* hp, HPDataType x)
{
	assert(hp);
	//判断堆是否已经满
	if (hp->_size == hp->_capacity)
	{
		int newcapacity = hp->_capacity == 0 ? 4 : 2 * hp->_capacity;
		int* tmp = (int*)realloc(hp->_a,sizeof(HPDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		hp->_a = tmp;
		hp->_capacity = newcapacity;
	}
	hp->_a[hp->_size] = x;
	AdjustUp(hp, hp->_size);
	hp->_size++;
}
8.堆的删除HeapPop函数
cpp 复制代码
//默认为删除堆顶
//为了不影响整体结构,将堆顶元素与堆尾交换后,删除。之后需向下调整堆,维持堆的性质
void HeapPop(Heap* hp)
{
	assert(hp);
	assert(!HeapEmpty(hp));
	//交换
	swap(&(hp->_a[0]), &(hp->_a[hp->_size - 1]));

	//删除
	hp->_size--;

	//向下调整
	AdjustDown(hp, 0);
}
9.取堆顶数据 HeapTop函数

因为物理结构是一个数组,所以取下标为0的数就是堆顶数据。

cpp 复制代码
// 取堆顶的数据
HPDataType HeapTop(Heap* hp)
{
	return hp->_a[0];
}
 
10.取堆数据个数 HeapSize函数

直接输出size的大小。

cpp 复制代码
// 堆的数据个数
int HeapSize(Heap* hp)
{
	return hp->_size;
}
11.堆判空 HeapEmpty函数

直接判断堆数据size的大小是否为0。

cpp 复制代码
// 堆的判空
int HeapEmpty(Heap* hp)
{
	return hp->_size == 0;
}
相关推荐
码农开荒路35 分钟前
Redis底层数据结构之字典(Dict)
java·数据结构·数据库·redis
xphjj1 小时前
树形数据模糊搜索
前端·javascript·算法
Once_day1 小时前
代码训练LeetCode(24)数组乘积
算法·leetcode
lyh13442 小时前
【Fiddler抓取手机数据包】
数据结构
int型码农3 小时前
数据结构第八章(二)-交换排序
c语言·数据结构·算法·排序算法
YKPG3 小时前
C++学习-入门到精通【14】标准库算法
c++·学习·算法
CoovallyAIHub4 小时前
AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
深度学习·算法·计算机视觉
码农之王4 小时前
记录一次,利用AI DeepSeek,解决工作中算法和无限级树模型问题
后端·算法
落羽的落羽7 小时前
【C++】二叉搜索树
开发语言·数据结构·c++·学习
编程绿豆侠7 小时前
力扣HOT100之二分查找: 34. 在排序数组中查找元素的第一个和最后一个位置
数据结构·算法·leetcode