【数据结构】堆的实现

目录

一、堆的概念

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;
}
相关推荐
Y4090013 分钟前
C语言转Java语言,相同与相异之处
java·c语言·开发语言·笔记
YuTaoShao4 分钟前
【LeetCode 热题 100】994. 腐烂的橘子——BFS
java·linux·算法·leetcode·宽度优先
Wendy14418 小时前
【线性回归(最小二乘法MSE)】——机器学习
算法·机器学习·线性回归
拾光拾趣录8 小时前
括号生成算法
前端·算法
棐木8 小时前
【C语言】动态内存管理
c语言·free·malloc·realloc·calloc·动态内存
渣呵9 小时前
求不重叠区间总和最大值
算法
拾光拾趣录9 小时前
链表合并:双指针与递归
前端·javascript·算法
好易学·数据结构9 小时前
可视化图解算法56:岛屿数量
数据结构·算法·leetcode·力扣·回溯·牛客网
香蕉可乐荷包蛋10 小时前
AI算法之图像识别与分类
人工智能·学习·算法
chuxinweihui10 小时前
stack,queue,priority_queue的模拟实现及常用接口
算法