一、堆的概念
堆数据结构是一种数据对象,它可以被视为一棵完全二叉树结构。
堆的二叉树存储是:
最大堆:每个父节点都大于其孩子结点;
最小堆:每个父节点都小于其孩子结点。
二、堆的实现
1.堆的结构体
typedef struct Heap {
HeapType data[HeapMaxSize];
size_t size;
Compare cmp;
} Heap;
2.堆的初始化
堆的初始化就是对结构体中的 size 和 cmp函数指针进行初始化,size =0,cmp有俩种选项可供选择:大堆(Greater)和小堆(Less)。
int Less(HeapType a,HeapType b){
return a<b?1:0;
}
int Greater(HeapType a,HeapType b){
return a>b?1:0;
}
//堆的初始化
void HeapInit(Heap* heap, Compare cmp){
if(heap == NULL){
//非法输入
return;
}
heap->size = 0;
heap->cmp = cmp;
return;
}
3.打印堆与元素的交换
堆的打印:为了清晰的对堆元素进行查看;
元素的交换:每次对堆操作,会影响堆的排列顺序,所以应该调用交换元素的函数的方式对堆进行调整,使其满足对于堆的结构(调用元素交换函数时,应该传入 元素的地址(传置))。
//层序遍历堆
void print_Heap(Heap heap,char* msg){
printf("\n*******%s***********\n",msg);
int i = 0;
for(;i<heap.size;++i){
printf("%d ",heap.data[i]);
}
printf("\n");
return;
}
//,交换函数
void swap(int * a,int * b){
int tmp = *a;
*a = *b;
*b = tmp;
return;
}
4.堆的插入实现
对堆进行插入操作可由以下步骤实现:
i>判断堆是否为空堆
ii>堆为空,直接插入,,堆不为空,将带插入值先插至结构体数组的size处,并将size进行++操作
iii>将size-1视为cur,(cur-1)/2视为parent,并进入 while(cur>=0)循环,若cur处的值与parent处的值满足堆结构,直接退出,否则进行交换,然后使cur = parent, parent = (cur-1)/2;
iv>循环结束,变换后的堆又满足了堆的结构
//往堆里插入元素
void HeapInsert(Heap* heap, HeapType value){
//1.判断是否为非法输入
if(heap == NULL){
//非法输入
return ;
}
//2.判断堆是否为空
if(heap->size == 0){
//堆位空
heap->data[heap->size] = value;
}else{
//堆不为空
heap->data[heap->size] = value;
int cur = heap->size;
int parent = ( cur - 1 )/2;
while(parent >= 0){
if ( heap->cmp(heap->data[cur], heap->data[parent]) ){
swap(&heap->data[cur],&heap->data[parent]);
cur = parent;
parent = (cur - 1)/2;
}else{
break;
}
}
}
++heap->size;
return;
}
5.取堆顶元素
//取堆顶元素
int HeapRoot(Heap* heap, HeapType* value){
//1.判断是否为非法输入
if(heap == NULL){
//非法输入
return 0;
}
//2.判断堆是否为空,空堆返回0,否则返回1
if(heap->size == 0){
//空堆
return 0;
}else{
//非空
*value = heap->data[0];
return 1;
}
}
6.删除堆顶元素
首先判断是否为空堆,如果为空堆直接返回,否则将堆首元素与堆末元素进行交换,对size进行--操作,然后调整堆的结构,使变化后的堆重新满足堆的结构。
//删除堆顶元素
void HeapErase(Heap* heap){
//1.判断是否为非法输入
if(heap == NULL){
//非法输入
return;
}
//2.判断堆是否为空
if(heap->size == 0){
//堆为空
return;
}else{
//非空
swap(&heap->data[0],&heap->data[heap->size-1]);
--heap->size;
int cur = 0;
int child = 2*cur +1;
while(child < heap->size){
//当前结点右子树,,
//判断该结点是否具有右子树
if(child+1<heap->size){
//带结点具有右子树
//进行左右子树判断,挑选满足规定的值
if(heap->cmp(heap->data[child],heap->data[child+1]) == 0){
//child不满足规定
++child;
if(heap->cmp(heap->data[cur],heap->data[child])== 0){
swap(&heap->data[cur],&heap->data[child]);
cur = child;
child = ( cur-1 ) /2;
}else{
return;
}
}else{
//child满足规定
if(heap->cmp(heap->data[cur],heap->data[child])== 0){
swap(&heap->data[cur],&heap->data[child]);
cur = child;
child = 2*cur+1;
}else{
return;
}
}
}else{
//cur无右子树
if(heap->cmp(heap->data[cur],heap->data[child])== 0){
swap(&heap->data[cur],&heap->data[child]);
cur = child;
child = ( cur-1 ) /2;
}else{
return;
}
}
}
}
return;
}
7.堆的销毁
堆的销毁,可以直接将堆结构体中的size置为0就好,此处进行了大规模的处理,是为了方便使用堆对数组进行排序。
//堆的销毁
void HeapDestroy(Heap* heap){
//1.判断是否为非法输入
if(heap == NULL){
//非法输入
return;
}
//2.判断是否为空堆
if(heap->size == 0){
//为空
return;
}else{
//非空
while(heap->size){
HeapErase(heap);
}
return;
}
}
8.堆排序
堆排序实质上是为了解决数组的排序,如果要将数组进行升序排列,就采用大堆实现,如果要将数组进行降序排列,就采用小堆实现。
//堆排序函数
void HeapSort(HeapType array[], size_t size){
int i = 0;
Heap heap ;
HeapInit(&heap,Greater);
for(;i<size;i++){
HeapInsert(&heap,array[i]);
}
HeapDestroy(&heap);
Heap new_heap = heap;
new_heap.size = size;
print_Heap(new_heap,"HeapSord");
return;
}
9.以上函数的检测代码
//堆排序的检测函数
void textHeapSort(){
int array[] = {1,2,3,4};
HeapSort(array,sizeof(array)/sizeof(array[0]));
return;
}
//堆销毁的检测函数
void textHeapDestroy(){
Heap heap ;
HeapInit(&heap,Greater);
HeapInsert(&heap,1);
HeapInsert(&heap,2);
HeapInsert(&heap,3);
HeapInsert(&heap,4);
int size = heap.size;
HeapDestroy(&heap);
print_Heap(heap,"堆删除");
return;
}
//删除堆顶元素的检测函数
void textHeapErase(){
Heap heap ;
HeapInit(&heap,Greater);
HeapInsert(&heap,1);
HeapInsert(&heap,2);
HeapInsert(&heap,3);
HeapInsert(&heap,4);
HeapErase(&heap);
print_Heap(heap,"删除堆顶元素");
return;
}
//取堆顶元素的检测函数
void textHeapRoot(){
Heap heap ;
HeapInit(&heap,Greater);
HeapInsert(&heap,1);
HeapInsert(&heap,2);
HeapInsert(&heap,3);
HeapInsert(&heap,4);
HeapType value;
int ret = HeapRoot(&heap,&value);
printf("\n*******取堆顶元素***********\n");
printf("ret except:1 actual:%d\n",ret);
printf("value except:4 actual:%d\n",value);
}
//堆插入的检测函数
void textHeapInsert(){
Heap heap ;
HeapInit(&heap,Greater);
HeapInsert(&heap,1);
HeapInsert(&heap,2);
HeapInsert(&heap,3);
HeapInsert(&heap,4);
print_Heap(heap,"堆插入四个元素");
return;
}
//堆初始化的检测函数
void textHeapInit(){
Heap heap ;
HeapInit(&heap ,Greater);
print_Heap(heap,"对堆进行初始化");
return;
}
10.主函数
//主函数
int main(){
textHeapInit();//堆初始化的检测函数
textHeapInsert();//堆插入一个元素
textHeapRoot();//取堆顶元素的检测函数
textHeapErase();//删除堆顶元素的检测函数
textHeapDestroy();//堆删除的检测函数
textHeapSort();//
return 0;
}
11.检测结果
*******对堆进行初始化***********
*******堆插入四个元素***********
4 3 2 1
*******取堆顶元素***********
ret except:1 actual:1
value except:4 actual:4
*******删除堆顶元素***********
3 1 2
*******堆删除***********
*******HeapSord***********
1 2 3 4