认识堆是从堆排序开始的
根结点下标为0时,下标为n的元素的子结点下标分别为2*n+1,2*n+2,其父结点下标为(n-1)/2
1、父结点的键值总是>=(<=)任何一个子结点的键值
2、每个结点的左右子树都是二叉堆
当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆
堆的操作方法如下定义:
#ifndef _HEAP_CTL_H
#define _HEAP_CTL_H#ifdef __cplusplus
extern "C" {
#endifvoid heapPprint(const char *info, int a[], int nLen);
void swap(int *a, int *b);void buildMaxHeap(int *a, int hLen);
void buildMinHeap(int *a, int hLen);void minHeapAddNumber(int *a, int *nLen, int newNum);
void maxHeapAddNumber(int *a, int *nLen, int newNum);
int minHeapDelNumber(int *a, int *nLen);
int maxHeapDelNumber(int *a, int *nLen);void ascHeapSort(int *iArray,int nLen);
void descHeapSort(int *iArray,int nLen);#ifdef __cplusplus
}
#endif
#endif
函数实现如下:
#include <stdio.h>
#include "heapctl.h"static void __pprint(int a[], int i, int nLen)
{printf("(");if (i < nLen) {printf("%d", a[i]);__pprint(a, i*2+1, nLen);__pprint(a, i*2+2,nLen);}printf(")");
}/***@brief 输出堆用于tree工具来图形化显示**@params info 写在前面的话*@params a 所要打印的数组*@params nLen 数组的长度*/
void heapPprint(const char *info, int a[], int nLen)
{if (info)printf("%s", info);printf("\n\\tree");__pprint(a, 0, nLen);printf("\n");
}/***@brief 交换两个数据**@params a 用以交换的第一个数据*@params b 用以交换的第二个数据*/
void swap(int *a, int *b)
{
#if 0//利用了辅助空间tmpint tmp = *a;*a = *b;*b = tmp;
#endif#if 0//相加可能溢出*a += *b;*b = *a - *b;*a -= *b;
#endif#if 1//异或运算A^B^B=A*a ^= *b;*b ^= *a;*a ^= *b;
#endif
}/***@brief 大顶堆调整**@params A 数组A*@params hLen*@params 需要调整的节点i*/
void maxHeapAdjust(int *a,int i,int size) //调整堆
{int lchild=2*i+1; //i的左孩子节点序号 int rchild=2*i+2; //i的右孩子节点序号 int max=i; //临时变量 if(i <= size/2) //如果i是叶节点就不用进行调整 {if(lchild<size && a[lchild]>a[max]) {max=lchild;} if(rchild<size && a[rchild]>a[max]) {max=rchild;}if(max != i) {swap(&a[i], &a[max]);maxHeapAdjust(a,max,size); //避免调整之后以max为父节点的子树不是堆 }}
}/***@brief 构建大顶堆**@params a 数组a*@params hLen 数组元素的个数*/
void buildMaxHeap(int *a, int hLen)
{int i;//堆类似完全二叉树,nLen 为偶数://深度为2的节点数n2 = nLen>>1 -1, n1 = 1, n0 = nLen>>1;//nLen 为奇数, n2 = nLen/2, n1 = 0, n0 = nLen/2+1; //n0 = n2 + 1//从非叶节点最大序号位置调整, 值为size/2 for(i=hLen/2-1; i>=0; i--){maxHeapAdjust(a,i,hLen); }
} /***@brief 小顶堆调整**@params A 数组A*@params hLen*@params 需要调整的节点i*/
void minHeapAdjust(int *a,int i,int size) //调整堆
{int lchild=2*i+1; //i的左孩子节点序号 int rchild=2*i+2; //i的右孩子节点序号 int max=i; //临时变量 if(lchild<size && a[lchild]<a[max]) {max=lchild;} if(rchild<size && a[rchild]<a[max]) {max=rchild;}if(max != i) {swap(&a[i], &a[max]);minHeapAdjust(a, max, size); //避免调整之后以max为父节点的子树不是堆 }
}/***@brief 构建大顶堆**@params a 数组a*@params hLen 数组元素的个数*/
void buildMinHeap(int *a, int hLen)
{int i;//堆类似完全二叉树,nLen 为偶数://深度为2的节点数n2 = nLen>>1 -1, n1 = 1, n0 = nLen>>1;//nLen 为奇数, n2 = nLen/2, n1 = 0, n0 = nLen/2+1; //n0 = n2 + 1//从非叶节点最大序号位置调整, 值为size/2 for(i=hLen/2-1; i>=0; i--){minHeapAdjust(a,i,hLen); }
} /***@brief 向小顶堆中插入数据**@params a 要插入数据的数组*@params nLen 数组元素长度指针, 插入后会自增*@params newNum 插入的元素值**1、将插入的数据放入数组的末尾*2、根据与其父节点的大小来调整小顶堆*/
void minHeapAddNumber(int *a, int *nLen, int newNum)
{a[*nLen] = newNum; int j, i = *nLen;for (j = (i-1)/2;(j >= 0 && i != 0) && a[i] < a[j];i = j, j = (i-1)/2 )swap(&a[i], &a[j]);++*nLen;
}/***@brief 向大顶堆中插入数据**@params a 要插入数据的数组*@params nLen 数组元素长度指针, 插入后会自增*@params newNum 插入的元素值**1、将插入的数据放入数组的末尾*2、根据与其父节点的大小关系调整大顶堆*/
void maxHeapAddNumber(int *a, int *nLen, int newNum)
{a[*nLen] = newNum; int j, i = *nLen;for (j = (i-1)/2;(j >= 0 && i != 0) && a[i] > a[j];i = j, j = (i-1)/2 )swap(&a[i], &a[j]);++*nLen;
}/***@brief 小顶堆的删除操作,堆中每次都只能删除第0个数据,**@params a 要删除数据的数组*@params nLen 数组元素长度指针, 插入后会自减**1、将插入的数据放入数组的末尾*2、根据与其父节点的大小关系调整大顶堆*/
int minHeapDelNumber(int *a, int *nLen)
{int newLen = *nLen - 1;swap(&a[0], &a[newLen]);minHeapAdjust(a, 0, newLen);*nLen = newLen;return a[newLen];
}int maxHeapDelNumber(int *a, int *nLen)
{int newLen = *nLen - 1;swap(&a[0], &a[newLen]);maxHeapAdjust(a, 0, newLen);*nLen = newLen;return a[newLen];
}/***@brief 利用大顶堆进行升序排列**@params a 所要排序的数组名称*@params nLen 数组中元素的个数*/
void ascHeapSort(int *a,int nLen)
{int i;buildMaxHeap(a,nLen);for(i=nLen-1; i>=1; i--){swap(&a[0], &a[i]); //交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面 maxHeapAdjust(a, 0, i); //重新调整堆顶节点成为大顶堆}
} /***@brief 利用小顶堆进行降序排列**@params a 所要排序的数组名称*@params nLen 数组中元素的个数*/
void descHeapSort(int *iArray,int nLen)
{int i;buildMinHeap(iArray, nLen);for(i=nLen-1; i>=1; i--) {swap(&iArray[0], &iArray[i]);minHeapAdjust(iArray, 0, i);}
}
函数的实现方法与应用请自行参照注释
或以下文档
http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html
http://blog.csdn.net/morewindows/article/details/6709644/