二叉树学习之堆排序

来源:互联网 发布:java高级架构师 编辑:程序博客网 时间:2024/06/14 05:59

认识堆是从堆排序开始的


二叉堆是完全二叉树或者是近似完全二叉树,堆存储在数组中:

根结点下标为0时,下标为n的元素的子结点下标分别为2*n+1,2*n+2,其父结点下标为(n-1)/2


二叉堆的特性:
1、父结点的键值总是>=(<=)任何一个子结点的键值

2、每个结点的左右子树都是二叉堆


当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆

当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆

的操作方法如下定义:

#ifndef _HEAP_CTL_H#define _HEAP_CTL_H#ifdef __cplusplusextern "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/

0 0
原创粉丝点击