摘抄:http://www.2cto.com/kf/201110/108060.html

要说最大堆和最小堆,就得先知道最大树和最小树。

每个结点的值都大于(小于)或等于其子节点(如果有的话)值的树,就叫最大(最小)树。

最大堆(最小堆)是最大(最小)完全树。

由于堆是完全二叉树,所以可以用公式化描述,用一维数组来有效的描述堆结构。

利用二叉树的性质:

如果对一棵有n个结点的完全二叉树的结点按层序编号(从第1层到第[log2n]向下取整+1层,每层从左到右),则对任一结点i(1≤i≤n),有:

(1)如果i=1,则结点i无双亲,是二叉树的根;如果i>1,则其双亲是结点[i/2]向下取整。

(2)如果2i>n,则结点i为叶子结点,无左孩子;否则,其左孩子是结点2i。

(3)如果2i+1>n,则结点i无右孩子;否则,其右孩子是结点2i+1。

这样就就可以将堆中结点移到它的父节点或者其中一个子节点处。

堆中进行的操作主要是:插入,删除,以及初始化。

下面只讨论最大堆。

在最大堆中进行插入操作,例如在下图所示的左边的最大堆中进行插入,插入后结构应该是和右边的图一样的。

插入时,现将新元素从新堆的父节点开始比较,也就是先从2所在结点开始比较,如果小于父节点的值,那么就直接作为孩子结点插入,如果大于,那么就要现将父节点下移,然后再和父节点的父节点比较,一直比较到根节点为止,所以插入过程,是从叶节点到根的一条路径。

最大堆的删除,从最大堆的删除时,该元素从根部移出。删除后,此时堆需要重新构造,以便于仍然为完全二叉树。例如下图:

先将根节点的值20取出后,为了结构仍然是二叉树,所以直接将最后一个结点,也就是保存2的结点去掉,然后将2的值保存下来,然后呢,就从根节点的两个孩子开始比较,看看2 根的左右孩子,这三个元素中,谁最大,那么根节点的值就是谁,然后就将2和空出来的结点的左右孩子(如果有的话)比较,确认子树的根节点的值,这样一步一步确认下去。

用数组初始化堆,数组元素显示按照下面的顺序,一个一个放在结点中

然后就从最后一个父节点开始,就是第五个结点,10所在的位置啦,从那里开始构造以该节点为根的最大堆。构造好后就移到下一个结点,15所在结点,以此类推,一直到根节点。

下面是代码:

文件"maxheap.h"

#include <iostream> 
using namespace std; 
 
template <class T> 
class MaxHeap 

private: 
    T *heap; 
    int CurSize; 
    int MaxSize; 
public: 
    MaxHeap(int maxsize=10) 
    { 
        MaxSize=maxsize; 
        CurSize=0; 
        heap=new T[MaxSize+1]; 
    } 
 
    ~MaxHeap() 
    { 
        delete[]heap; 
    } 
 
    int Get_Size() const 
    { 
        return CurSize; 
    } 
 
    T Get_Max() 
    { 
        if(CurSize==0) 
        { 
            cout<<"堆为空"<<endl; 
            return -9999; 
        } 
        else 
        { 
            return heap[1]; 
        } 
    } 
 
    MaxHeap<T> &Insert(const T& x) 
    { 
        if(CurSize==MaxSize) 
        { 
            cout<<"堆满,"<<x<<" 插入失败"<<endl; 
            return *this; 
        } 
        //为x寻找应插入位置 
        //i从新的叶子结点开始,沿着树向上 
        int i=++CurSize; 
        while(i!=1 && x>heap[i/2]) 
        { 
            heap[i]=heap[i/2]; //将元素下移 
            i/=2; //移向父节点 
        } 
         
        heap[i]=x; 
        cout<<x<<" 插入成功"<<endl; 
        return *this; 
    } 
 
    MaxHeap<T> &DeleteMax(T& x) 
    { 
        //将最大元素放入x,并从堆中删除它 
        if(CurSize==0) 
        { 
            x=-9999; 
            return *this; 
        } 
         
        x=heap[1]; 
 
        //重构堆 
        heap[0]=heap[CurSize--]; //0号位置存放最后一个元素值,然后将该位置删除 
 
        //从根开始,为heap[0]寻找合适位置 
        int i=1; 
        int ci=2; 
 
        while(ci<=CurSize) 
        { 
            //ci是较大的孩子的位置 
            if(ci<CurSize && heap[ci]<heap[ci+1]) 
                ci++; 
 
            //判断是否可以放入heap[i]位置 
            if(heap[0]>heap[ci]) 
                break; 
             
            //不能 
            heap[i]=heap[ci]; 
            i=ci; // 下移一层 
            ci*=2; 
        } 
 
        heap[i]=heap[0]; 
        return *this; 
    } 
 
    void Init_heap(T a[],int size,int maxsize) 
    { 
        delete[]heap; 
        heap=new T[maxsize+1]; 
        CurSize=size; 
        MaxSize=maxsize; 
 
        for(int j=1;j<size+1;j++) 
            heap[j]=a[j]; 
 
        //产生一个最大堆 
        for(int i=CurSize/2;i>=1;i--) 
        { 
            T y=heap[i]; //子树的根 
 
            //寻找放置y的位置 
            int c=2*i; 
            while(c<=CurSize) 
            { 
                if(c<CurSize && heap[c]<heap[c+1]) 
                    c++; 
 
                if(y>=heap[c]) 
                    break; 
 
                heap[c/2]=heap[c]; 
                c*=2; 
            } 
            heap[c/2]=y; 
        } 
    } 
}; 
测试文件"main.cpp"

#include "maxheap.h" 
 
#include <iostream> 
using namespace std; 
 
int main() 

    MaxHeap<int> hp; 
    int a[11]={-111,5,2,12,3,55,21,7,9,11,9}; 
     
    cout<<"用数组a来初始化堆:"<<endl; 
    for(int i=1;i<11;i++) 
        cout<<a[i]<<"  "; 
    cout<<endl; 
 
    hp.Init_heap(a,10,15); 
 
    int max; 
    cout<<"目前堆中最大值为:"<<hp.Get_Max()<<endl; 
 
    hp.DeleteMax(max); 
    cout<<"删除的堆中最大的元素为:"<<max<<endl; 
    cout<<"删除后,现在堆中最大的元素为:"<<hp.Get_Max()<<endl; 
 
    cout<<"现在堆的大小为:"<<hp.Get_Size()<<endl; 
 
    cout<<"向堆中插入新元素"<<endl; 
 
    hp.Insert(22); 
    hp.Insert(45); 
    hp.Insert(214); 
    hp.Insert(16); 
    hp.Insert(21); 
    hp.Insert(121); 
    hp.Insert(111); 
 
    cout<<"插入后现在堆的大小为:"<<hp.Get_Size()<<endl; 
 
    cout<<"现在由大到小输出堆中元素"<<endl; 
 
    do 
    { 
        hp.DeleteMax(max); 
        if(max== -9999) 
            break; 
        cout<<max<<"  "; 
    }while(1); 
 
    cout<<endl; 
 
    return 0; 

测试结果:

在只是需要使用一个优先队列的时候,这种结构是十分有效率的,空间利用率也很高。但是并不适用于所有优先队列的使用,尤其是需要合并两个优先队列或多个长度不相等的队列的时候。

C++ 堆结构(数组实现)相关推荐

  1. 集合框架源码分析六之堆结构的实现(PriorityQueue)

    /** * * 优先队列是用了一种叫做堆的高效的数据结构, * 堆是用二叉树来描述的,对任意元素n,索引从0开始,如果有子节点的话,则左子树为 * 2*n+1,右子树为2*(n+1). * 以堆实现的 ...

  2. java二叉堆_为什么二叉堆利用数组存储?

    堆 逻辑结构最大的优势就在于,通过数组,目标index 能推算出 父子指针的定位. 所以在上下heaptify的时候可以直接找到对应位置进行交换等操作. 现有语言里比如Java,C,C+:以java为 ...

  3. Heap(堆结构/优先队列)-Swift实现

    特性 堆结构很像二叉树,堆也是一个近似树形结构,堆的每个节点也最多有左.右两个孩子,但是堆实质是存储在数组中的结构,所以他和二叉树只是近似的有某些共同的特性. 第一特性,堆结构是存储在数组中的. 堆通 ...

  4. Bailian4078 实现堆结构【模拟+优先队列】

    4078:实现堆结构 总时间限制: 3000ms 单个测试点时间限制: 1000ms 内存限制: 65536kB 描述 定义一个数组,初始化为空.在数组上执行两种操作: 1.增添1个元素,把1个新的元 ...

  5. 【数据结构】 实现 堆 结构 ---超细致解析

    目录 二叉树的性质: 二叉树的存储结构: 顺序存储: 链式存储: 堆的概念和性质: 堆的实现: 堆的初始化: 堆的插入: 向上调整函数: 堆的删除: 向下调整函数: 向上建堆: 向下建堆: TopK问 ...

  6. c语言中堆,栈,数组的增长方向

    c语言中堆,栈,数组的增长方向这个问题在C语言中是个重点问题,也是个难点问题,接下来我们谈谈他们在内存中的增长问题: 如何判断栈的增长方向? 对于一个用惯了i386系列机器的人来说,这似乎是一个无聊的 ...

  7. 堆结构 - 大根堆、小根堆

    在开发语言中,heap在使用层次的名字叫PriorityQueue(优先级队列),PriorityQueue数据结构的名字就叫做堆,底层就是用堆结构实现的. 完全二叉树 空树也算是完全二叉树 每一层都 ...

  8. 树-堆结构练习——合并果子之哈夫曼树 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Discuss Problem Descrip

    树-堆结构练习--合并果子之哈夫曼树 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Discuss Problem Descrip ...

  9. JavaScript实现堆结构

    说在前面 计算机领域里,到处都是算法,算法的运用是如此常见,如此自然,如此平凡,乃至像空气一样,会被绝大多数人,甚至是计算机专业的人忽视.从我们打开计算机(或者手机,平板电脑)开始,一系列算法就开始运 ...

最新文章

  1. windows启动mysql8服务_MySQL8.0服务启动(windows10)
  2. JavaScript中数组的增删改查以及应用方式
  3. 17 | 案例篇:如何利用系统缓存优化程序的运行效率?
  4. 手把手教你python实现量价形态选股知乎_【手把手教你】Python实现基于事件驱动的量化回测...
  5. VTK:libvtkGUISupportQt-6.3.so.1: cannot open shared object
  6. Eclipse : Unresolved inclusion
  7. 泡泡提示加强版 完美支持XHTML(JavaScript)--zhuan
  8. stm32单片机OLED取字模软件使用 PCtoLCD2002
  9. 程序员面试金典——5.5整数转化
  10. Q新闻丨吃鸡外挂被开源;Dubbo 3.0来了;工信部约谈百度、支付宝、今日头条;内地iCloud服务将转由云上贵州运营...
  11. Python优化算法01——差分进化算法
  12. PCAN-Explorer5安装教程
  13. Android Wifi控制方法总结
  14. 【转】区块链:胖协议
  15. 【网络实验箱02】-odl-neutron北向抓包分析
  16. 火红色枫叶背景《你好秋天》秋分节气 PPT模板
  17. 两组数据的偏差率_GWT测试报告 篇七十五:隐患难忽视,RIVAL 3 WIRELESS精准度LOD测试...
  18. github.io网页无法打开(连接不是私密连接)
  19. 欧拉函数和莫比乌斯反演(Mobius)
  20. 计算机不能通讯,S7-200与电脑不能通讯问题

热门文章

  1. Python中DataFrame转换成ndarray
  2. 目标检测算法总结(2)——Fast RCNN
  3. 研究lRP大佬提供的EHP虚拟机的时候的一点门道
  4. 【论文】:NEZHA(哪吒)
  5. cocos 禁掉快速点击_如何用PAM2500叶绿素荧光仪测量快速光曲线
  6. php记住用户名功能,php利用cookie实现网页记住用户名和密码的功能
  7. WebRTC Opus编码器的创建与参数细节分析( sdp -> native )
  8. IOS网络开发(一)
  9. NGK独创匿名P2P通信网络可以保护使用者的隐私
  10. gg修改服务器钻石,六号特工GG修改金钱、钻石和基因等教程+免广告版本