目录
[1.用数组定义堆结构struct Heap](#1.用数组定义堆结构struct Heap)
[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函数
现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整 成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。
cppint 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;
}