认识堆
1. 堆是一个完全二叉树
2. 堆有两种, 一种叫小堆(小根堆, 最小堆), 一种叫大堆(大根堆, 最大堆).
3. 以小堆为例, 这个树的根节点是这个树中的最小的元素 对于任意一个子树来说, 子树的根节点, 小于左右孩子节点的值.
4. 以大堆为例, 这个树的根节点是这个树种的最大元素 对于任意一个子树来说, 子树的根节点, 大于左右孩子节点的值.
堆的特点:
如果i=0,结点i是根节点,没有双亲节点;否则结点i的双亲结点为结点(i-1)/2
如果2 * i + 1 <= n - 1,则结点i的左孩子为结点2 * i + 1,否则结点i无左孩子
如果2 * i + 2 <= n - 1,则结点i的右孩子为结点2 * i + 2,否则结点i无右孩子
C语言代码实现堆的基本操作:
Heap.h
#include<stddef.h>
#define HeapMaxSize 1000
typedef int HeapType;
typedef int (*Compare)(HeapType a, HeapType b);
typedef struct Heap {
HeapType data[HeapMaxSize];
size_t size;
Compare cmp; //函数指针的变量
} Heap;
void HeapInit(Heap* heap, Compare compare); //堆的初始化
void HeapInsert(Heap* heap, HeapType value); //往堆中插入元素
// 取堆顶元素
int HeapRoot(Heap* heap, HeapType* value);
// 删除堆顶元素
void HeapErase(Heap* heap);
int HeapEmpty(Heap* heap); //判断堆是否为空
size_t HeapSize(Heap* heap); //求堆的节点个数
void HeapDestroy(Heap* heap); //销毁堆
//利用堆来对数组进行排序
void HeapSort(HeapType array[],size_t size);
Heap.c
#include"heap.h"
#include<stdio.h>
//如果a小于b,就返回1,否则返回0
int Less(HeapType a,HeapType b){
return a<b?1:0;
}
void HeapInit(Heap* heap, Compare compare){
if(heap==NULL||compare==NULL){
return ;
}
heap->size=0;
heap->cmp=compare;
return;
}
void swap(HeapType* a,HeapType* b){
HeapType tmp=*a;
*a=*b;
*b=tmp;
return;
}
void AdjustUp(HeapType data[],size_t size,Compare cmp,size_t index){
if(size<=index){
return;
}
//1.先找到当前节点对应的父节点
size_t child=index;
size_t parent=(child-1)/2;
while(child>0){
//2.比较父节点和子节点的大小关系,如果子节点的值比父节点的值小,交换父子节点的值,如果子节点的值比父节点大>,说明调整完成
if(cmp(data[child],data[parent])){
swap(&data[child],&data[parent]);
}else{
break;
}
//3.将当前的父节点作为新的子节点,再去找子节点的父节点,循环进行比较和交换
child=parent;
parent=(child-1)/2;
}
//4.子节点下标等于0,循环结束
}
void HeapInsert(Heap* heap, HeapType value){
if(heap==NULL){
return ;
}
if(heap->size>=HeapMaxSize){
return;
}
heap->data[heap->size++]=value;
AdjustUp(heap->data,heap->size,heap->cmp,heap->size-1);
}
void AdjustDown(HeapType* data,size_t size,Compare cmp,size_t index){
//1.设定parent指向开始位置,找到对应的子树节点
//2.设定一个child指向parent的左子树
//3.判定child和child+1的大小关系。如果child+1的值比child小,就让child=child+1;
//4.判定parent和child的值的大小关系,如果parent比child的值大,就需要进行交换,
//否则,说明调整完成5.parent赋值成child,child再重新赋值成parent的左孩子节点
//5.parent赋值成child,child再重新赋值成parent的左孩子节点
size_t parent=index;
size_t child=2*parent+1;
while(child<size){
if(child+1<size&&cmp(data[child+1],data[child])){
child=child+1;
}
if(cmp(data[child],data[parent])){
swap(&data[child],&data[parent]);
}else{
break;
}
parent=child;
child=parent*2+1;
}
return;
}
int HeapRoot(Heap* heap, HeapType* value){
if(heap==NULL){
return 0;
}
*value=heap->data[0];
return 1;
}
void HeapErase(Heap* heap){
if(heap==NULL){
return;
}
swap(&heap->data[0],&heap->data[heap->size-1]) ;
--heap->size;
AdjustDown(heap->data,heap->size,heap->cmp,0);
return;
}
int HeapEmpty(Heap* heap){
if(heap==NULL){
return 0;
}
return heap->size==0?1:0;
}
size_t HeapSize(Heap* heap){
if(heap==NULL){
return 0;
}
return heap->size;
}
void HeapDestroy(Heap* heap){
if(heap==NULL){
return ;
}
heap->size=0;
}
void HeapSort(HeapType array[],size_t size){
Heap heap;
HeapInit(&heap,Less);
//1.先将数组中的所有元素插入到堆中
//2.一次取堆顶元素,放回原数组,并删除堆顶元素
size_t i=0;
for(i;i<size;i++){
HeapInsert(&heap,array[i]);
}
size_t index=0;
while(!(HeapEmpty(&heap))){
HeapType root;
HeapRoot(&heap,&root);
array[index++]=root;
HeapErase(&heap);
}
return;
}
测试代码
#define HeaderPrint printf("\n==================%s==============\n",__FUNCTION__)
void TestInit(){
HeaderPrint;
Heap heap;
HeapInit(&heap,Less);
printf("heap.size expect 0.actual %lu\n",heap.size);
printf("heap.cmp expect %p,actual %p\n",Less,heap.cmp);
}
void heapprintchar(Heap* heap,const char* msg){
printf("[%s]\n",msg);
size_t i=0;
for(i;i<heap->size;i++){
printf("[%lu]:%d ",i,heap->data[i]);
}
printf("\n");
}
void TestInsert(){
HeaderPrint;
Heap heap;
HeapInit(&heap,Less);
HeapInsert(&heap,20);
HeapInsert(&heap,34);
HeapInsert(&heap,56);
HeapInsert(&heap,6);
HeapInsert(&heap,10);
heapprintchar(&heap,"往堆里插入五个元素");
}
void Testroot(){
HeaderPrint;
Heap heap;
HeapInit(&heap,Less);
HeapInsert(&heap,20);
HeapInsert(&heap,34);
HeapInsert(&heap,56);
HeapInsert(&heap,6);
HeapInsert(&heap,10);
HeapType value;
int ret=HeapRoot(&heap,&value);
printf("ret expect 1,actual %d\n",ret);
printf("root expect 6,actual %lu\n",value);
}
void TestErase(){
HeaderPrint;
Heap heap;
HeapInit(&heap,Less);
HeapInsert(&heap,20);
HeapInsert(&heap,34);
HeapInsert(&heap,56);
HeapInsert(&heap,6);
HeapInsert(&heap,10);
HeapErase(&heap);
heapprintchar(&heap,"删除一次堆顶元素");
}
void TestSort(){
HeaderPrint;
HeapType array[]={1,7,3,12,45,30,2};
HeapSort(array,sizeof(array)/sizeof(array[0]));
size_t i=0;
for(i;i<sizeof(array)/sizeof(array[0]);i++){
printf("%d ",array[i]);
}
}
int main(){
TestInit();
TestInsert();
Testroot();
TestErase();
TestSort();
return 0;
}