认识堆是从堆排序开始的
二叉堆是完全二叉树或者是近似完全二叉树,堆存储在数组中:
根结点下标为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" { #endif void 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//利用了辅助空间tmp int 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/
时间: 2024-10-13 02:22:32