一.堆的概念
如果有一个关键码的集合K={k0,k1,k2,.......kn-1},把他所有元素按照完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2*i+1 且 Ki<= K2*i+2 (Ki >= K2*i+1 且 Ki >= K2*i+2) i = 0,1,2…,则称为小堆(或大堆)。
小堆:从上图可以看出小堆的特点是:任意一节点的数值都要大于堆顶的结点数据(孩子结点大于根节点,左右孩子可以不分大小排序)。堆顶元素最小。从根节点到每个结点的路径上数组元素组成的序列是递增的。
大堆:从上图可以看出大堆的特点是:任意一节点的数据都要小于堆顶的结点数据(孩子结点小于根节点,左右孩子可以不分大小排序)。堆顶元素最大。从根节点到每个结点的路径上数组元素组成的序列是递减的。
堆存储在下标为0开始的数组中,因此在堆中给定下标为i的结点时:
(1) 如果i=0,结点i是根节点,没有双亲节点;否则结点i的双亲结点为 结点(i-1)/2
(2) 如果2 * i + 1 <= n - 1,则结点i的左孩子为结点2 * i + 1,否则结 点i无左孩子
(3)如果2 * i + 2 <= n - 1,则结点i的右孩子为结点2 * i + 2,否则结 点i无右孩
二.堆的基本操作(一下操作都是建立小堆)
1.堆的创建
2.堆的插入和删除
堆的插入:在已经建成的最小堆的后面插入新元素,插入之后,当树 中结点不满足堆的性质时,就需要对堆进行重新调整
堆的删除:删除时每次删除堆顶元素
3.堆的销毁
4.打印堆
三.实现代码
heap.h
#pragma once
#include<stdio.h>
#include<malloc.h>
#include<assert.h>
#include<Windows.h>
typedef int DataType;
typedef struct Heap
{
DataType* array;
int capacity;
int size;
}Heap;
//创建堆
void GreateHeap(Heap* hp,int* array,int size);
//向下调整堆
void AdjustHeapDown(Heap* hp,int parent);
//堆中插入元素
void InsertHeap(Heap* hp, DataType data);
//向上调整
void AdjustUp(Heap* hp, int child);
//删除元素
void DeleteHeap(Heap* hp);
//堆中元素的个数
int SizeHeap(Heap* hp);
//判断堆是否为空
int EmptyHeap(Heap* hp);
//销毁堆
void DestoryHeap(Heap* hp);
//打印堆
int PrintHeap(Heap* hp);
heap.c
//创建堆
void GreateHeap(Heap* hp,int* array, int size)
{
//申请空间
hp->array = (DataType*)malloc(sizeof(DataType) * size);
if (hp->array == NULL)
{
printf("申请失败!!!\n");
return;
}
//将容量赋为size
hp->capacity = size;
//放置元素
for (int i = 0; i < size; i++)
{
hp->array[i] = array[i];
}
hp->size = size;
//找到最后一个非叶子节点
int Root = (size - 2) / 2;
//调整堆
for (; Root+1 >0; Root--)
AdjustHeapDown(hp,Root);
}
//交换两个数
void swap(int* array1,int* array2)
{
assert(array1);
assert(array2);
int temp = 0;
temp = (*array1);
(*array1) = (*array2);
(*array2) = temp;
}
//调整堆
void AdjustHeapDown(Heap* hp,int parent)
{
//找到root的左孩子
int child = (parent * 2) + 1;
while (child < hp->size)
{
//默认左孩子为最小的孩子
if (child + 1 < hp->size && hp->array[child] > hp->array[child + 1])
child = child + 1;
if (hp->array[parent]>hp->array[child])
{
swap(&hp->array[child], &hp->array[parent]);
//让parent和child互换
parent = child;
child = (child << 1) + 1;
}
else
return;
}
}
//打印堆
int PrintHeap(Heap* hp)
{
assert(hp);
if (NULL == hp)
{
printf("堆已空!!!\n");
return 0;
}
int i = 0;
for (i; i < hp->size; i++)
{
printf("%d->", hp->array[i]);
}
printf("\n");
return 0;
}
//堆中插入元素
void InsertHeap(Heap* hp, DataType data)
{
assert(hp);
CheakCapacity(hp);
hp->array[hp->size++] = data;
int child = hp->size - 1;
AdjustUp(hp, child);
}
//检查堆是否需要增容
void CheakCapacity(Heap* hp)
{
assert(hp);
if (hp->capacity == hp->size)
{
//申请新空间
int i = 0;
int Newcapacity = hp->capacity * 2;
DataType* Temp = (DataType*)malloc(sizeof(DataType)*Newcapacity);
if (Temp == NULL)
{
printf("申请失败!!!\n");
return;
}
//拷贝元素
for (; i < hp->size; i++)
Temp[i] = hp->array[i] ;
//释放旧空间
free(hp->array);
hp->capacity = Newcapacity;
hp->array = Temp;
}
}
//向上调整
void AdjustUp(Heap* hp, int child)
{
int parent = (child - 1) >> 1;
//只要孩子不为0
while (child)
{
if (hp->array[parent] < hp->array[child])
{
swap(&hp->array[parent], &hp->array[child]);
parent = child;
child = (child - 1) >> 1;
}
else
return;
}
}
//删除元素
void DeleteHeap(Heap* hp)
{
assert(hp);
if (NULL == hp)
return;
swap(&hp->array[0], &hp->array[hp->size - 1]);
hp->size -= 1;
AdjustHeapDown(hp, 0);
}
//堆中元素的个数
int SizeHeap(Heap* hp)
{
assert(hp);
if (NULL == hp)
return 0;
return hp->size;
}
//判断堆是否为空
int EmptyHeap(Heap* hp)
{
assert(hp);
if (hp->size == 0)
return 0;
return 1;
}
//销毁堆
void DestoryHeap(Heap* hp)
{
assert(hp);
if (hp)
{
free(hp->array);
hp->capacity = 0;
hp->size = 0;
hp->array = NULL;
}
}
test.c
void TestHeap()
{
int array[] = { 53, 17, 78, 9, 45, 65, 87, 23, 31 };
int size = sizeof(array) / sizeof(array[0]);
Heap hp;
GreateHeap(&hp,array,size);
PrintHeap(&hp);
InsertHeap(&hp, 33);
PrintHeap(&hp);
DeleteHeap(&hp);
PrintHeap(&hp);
printf("size=%d",SizeHeap(&hp));
printf("\n");
}
int main()
{
TestHeap();
system("pause");
return 0;
}