数据结构其他章节
前言
上一篇文章中,我们了解到二叉树一般有两种存储方式,一种顺序存储,一种链式存储。在本文中我们将学习堆,也就是二叉树按顺序存储实现的一种结构。
一,堆的概念
1.1概念
如果有一个关键码的集合K = { ,
,
,…,
},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:
<=
且
<=
(
>=
且
>=
) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
简而言之,大/小堆就是一个顺序存储的完全二叉树,在这颗树中任一父亲节点所存储的数据都大于/小于或者等于其两个子节点。
堆的性质如下:
1,堆中某个节点的值总是不大于或不小于其父节点的值;
2,堆总是一棵完全二叉树。
二,堆的结构
堆在逻辑结构上是以完全二叉树的形式呈现,在存储结构,也就是物理结构上是以数组的方式存储。
三,堆的代码实现
堆的存储方式是顺序存储,其代码实现如下:(本文将以大堆为例,带着读者们一步一步进行代码实现,小堆的代码实现只需修改其中少量代码即可,笔者将不再重复实现小堆)
typedef int DataType;
typedef struct Heap {
DataType* a; //存储的数据
int size; //有效数据个数
int capacity;//总容量
}HP;
3.1初始化与销毁
3.1.1初始化
堆的代码实现肯定是从初始化开始
void HeapInit(HP* hp) {
assert(hp); //断言,判断指针是否为空
hp->a = NULL;
hp->size = 0;
hp->capacity = 0;
}
3.1.2销毁
既然有初始化,那肯定少不了销毁操作
void HeapDestory(HP* hp) {
assert(hp);
free(hp->a); //释放空间
hp->a = NULL; //置空,避免出现野指针
hp->capacity = hp->size = 0;
}
这两个函数的实现十分简单,唯一需要注意的就是不要忘记释放指针hp->a所指向的空间。
3.2插入与删除
3.2.1插入
紧接着就是大堆的插入函数的实现;我们知道,大堆中任一父亲节点都大于或等于它的两个子节点,那么我们该如何利用这一性质来实现插入呢?
上一篇文章中我们了解到,如果按根节点为第0个节点排序,那么第i个节点的左孩子节点就是2*i+1,它的右孩子节点是2*i+2;根据大堆的性质,我们只需要保证第i个节点始终大于等于第2*i+1和2*i+2个节点即可。<