数据结构之堆
堆的概念:
如果有一个关键码的集合K = {k0 ,k1 ,k2 ,k3,…, kn-1},把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足:Ki <= K2*i+1且 Ki<=K2*i+2 (Ki >=K2*i+1 且 Ki>= K2*i+2) i = 0,1, 2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
1.堆的性质
- 堆中的某个节点的值总是不大于或者不小于父节点的值(大堆或者小堆)
- 堆总是一颗完全二叉树
堆的难点
堆的逻辑结构和堆的物理存储结构是完全不一样的!操作的是数组,但是表示出来的却是二叉树!
2.堆的结构
typedef int HPdataType;
typedef struct Heap
{
HPdataType* data;//堆的存储结构本质就是一个数组
int size;//用来表示数组内的元素的多少
int capacity;//用来表示数组的内存大小!
}//堆的结构与顺序表相同,但是因为操作方式的不同导致了堆与顺序表完全不同的性质!
堆的创建后面进行阐述,因为堆的创建有两种方式一种是将一个非堆的数组通过调整变成堆,另一种是通过数组插入的方式获得一个堆,两种的本质其实都是相同的!
3.堆的初始化
void HeapIint(Heap* php)//堆刚创建的堆进行初始化!
{
php->data = NULL;
php->size = php->capacity = 0;
}
4.堆的插入
//堆插入的重点在于在插入后仍要保持堆的基本结构!保持大堆或者小堆!
//思路是先插入到最后面,然后进行向上调整算法
typedef int HPdataType;
void AdjustUp(HPdataType* a,int child);
typedef struct Heap
{
HPdataType* data;
int size;
int capacity;
}
void HeapPush(Heap* php,HPdataType x)
{
assert(php);
if(php->size == php->capacity)//先检查容量是否足够!不够则进行扩容
{
int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
HPdataType temp* = (HpdataType*)realloc(php->data,
sizeof(HPdataType)*newcapacity);
if(temp == NULL)//检查是否扩容成功!
{
perror("realloc fail!");
return;
}
php->data = temp;
php->capacity = newcapacity;
}
php->data[php->size++] = x;
AdjustUp(php->a,php->size-1);
//插入尾部,现在开始进行向上调整!将其调整为堆!
//传过去最后一个插入的数据的位置和数组
}
void swap(HPdataType* x,HPdataType* y)
{
HPdataType temp = *x;
*x = *y;
*y = temp;
}
void AdjustUp(HPdataType* a,int child)
{
int parent = (child-1) / 2;//找到父节点
while(child > 0)//child不用等于0因为,到0这个位置上面也就没有父节点了
{
if(a[child] > a[parent])//这里以大堆为例!
{
swap(&a[child],&a[parent]);
child = parent;
parent = (child -1)/2;
}
else
{
break;//遇到比child大的那么久跳出循环
}
}
//这里如果使用parent>0,那么因为子节点还在下一个位置,则无法调整根节点
//如果是parent>=0 因为parent =(0-1)/2 仍然为0,则就会出现死循环!
}
//向上调整算法的核心是对比父节点和子节点,如果是大堆,那么子节点大于父节点那么就进行互换位置
//如果是小堆那么则相反过来
向上调整算法的时间复杂度
为了方便计算我们以h层的满二叉树为例:
总结点数 N = 2h-1;
则 h = log2(N+1) ≈ logN;
所以向上调整算法的时间复杂度为logN。
5.堆的创建
从上面的堆的插入可以看出如果我们将第一个逻辑结构为完全二叉树的数组,一个个进行堆的插入到另一个数组中,这样子就可以创建出一个堆出来!
void HeapCreat(Heap* php,HPdataType* a,int size)
{
for(int i = 0;i < size;i++)
{
HeapPush