C 算法精解----堆的实现及分析
堆的描述
一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。下面是一个最大堆的图,及堆的遍历顺序(层次遍历,前面提到过)

/*heap.h*/#ifndef HEAP_H#define HEAP_H/*定义一个堆得结构体*/typedef struct Heap_ { /*堆中元素的个数*/ int size; /* 比较节点和插入数值大小的函数指针*/ int (*compare)(const void *key1,const coid *key2); /*当*tree是动态申请空间时,用来释放空间的函数指针*/ void (*destroy)(void *data); /*tree 是堆中存储数据节点指针的数组*/ void **tree;}Heap;/*函数接口*/void heap_init(Heap *heap,int (*compare)(const void *key1,const void *key2),void (*destroy)(void *data));void heap_destroy(Heap *heap);int heap_insert(Heap *heap,const void *data);int heap_extract(Heap *heap,void **data);#define heap_size(heap) ((heap)->size)#endif初始化与销毁
/*heap.c*/#include <stdlib.h>#include <string.h>#include "heap.h"/*当前节点父节点的下标*/#define heap_parent(npos) ((int)(((npos)-1)/2))/*当前节点左子树下标*/#define heap_left(npos) (((npos*2) + 1)/*当前节点右子树的下标*/#define heap_right(npos) (((npos)*2+2)/*初始化*/void heap_init(Heap * heap, int(* compare)(const void * key1, const void * key2), void(* destroy)(void * data)){ heap->size = 0; heap ->compare = compare; heap ->destroy = destroy; heap ->tree = NULL; return ;}/*销毁*/void heap_destroy(Heap * heap){ int i; /*如果数据存放申请空间则删除*/ if (heap -> destroy != NULL){ for (i = 0, i < heap_size(heap), i++){ heap ->destroy(tree[i]); } } /*释放数组空间*/ free (heap->tree); memst(heap,0,sizeof(heap)); return;}数据插入堆先看下面个例子,就很明白函数的实现过程

/*将数据插入到最大值堆中 * 成功0;失败-1 **/int heap_insert(Heap * heap, const void * data){ void *temp; int ipos,ppos; /*插入的数据申请空间*/ if ((temp = (void *)realloc(heap->tree,(heap_size(heap) + 1)*sizeof(void *))) == NULL){ return -1; } else { heap -> tree = temp; } /*插入数据*/ heap->tree[heap_size(heap)] = (void *)data; /* ipos : 保存插入数据节点的下标 * ppos: 保存插入数据父节点的下标 */ ipos = heap_size(heap); ppos = heap_parent(ipos); while (ipos > 0 && heap ->compare(heap ->tree[ppos],heap->tree[ipos]) < 0){ /*交换数据*/ temp = heap ->tree[ppos]; heap ->tree[ppos] = heap ->tree[ipos]; heap ->tree[ipos] = temp; ipos = ppos; ppos = heap_parent(ipos); } heap->size ++; return 0;}
/*释放堆顶部的节点*/int heap_extract(Heap * heap, void * * data){ void *save,*temp; int ipos,lpos,rpos,mpos; /*当堆为空时直接返回-1*/ if (heap_size(heap) == 0) return -1; /*获得根节点的数值*/ *data = heap->tree[0]; /*调整堆得存储空间大小save 指向tree的最后一个数据*/ save = heap->tree[heap_size(heap) - 1]; if (heap_size(heap) - 1 > 0){ if ((temp = (void **)realloc(heap->tree,(heap_size(heap) - 1)*sizeof(void *))) == NULL){ return -1; } else { heap->tree = temp; } heap->size --; } else { /*删除的根节点*/ free(heap ->tree); heap->tree = NULL; heap->size = 0; return 0; } /*将最后一个节点的数值保存的根节点*/ heap->tree[0] = save; ipos = 0; while (1){ lpos = heap_left(ipos); rpos = heap_right(ipos); if (lpos < heap_size(heap) && heap ->compare(heap->tree[lpos],heap->tree[ipos]) > 0){ mpos = lpos; } else { mpos = ipos; } if (lpos < heap_size(heap) && heap ->compare(heap->tree[rpos],heap->tree[ipos]) > 0){ mpos = rpos; } if (mpos == ipos){ break; } else { temp = heap->tree[mpos]; heap->tree[mpos] = heap->tree[ipos]; heap -> tree[ipos] = temp; ipos = mpos; } } return 0;}