【转】最小堆和最大堆

原文:https://blog.youkuaiyun.com/genios/article/details/8157031 

最大堆和最小堆是二叉堆的两种形式。

最大堆:根结点的键值是所有堆结点键值中最大者,且每个结点的值都比其孩子的值大。

最小堆:根结点的键值是所有堆结点键值中最小者,且每个结点的值都比其孩子的值小。

最小堆和最大堆的增删改相似,其实就是把算法中的大于改为小于,把小于改为大于。

生成最大堆:最大堆通常都是一棵完全二叉树,因此我们使用数组的形式来存储最大堆的值,从1号单元开始存储,因此父结点跟子结点的关系就是两倍的关系。

即:heap[father * 2] = heap[leftChild];  heap[father * 2 + 1] = heap[rightChild];

最大堆的初始化

在生成最大堆时,我们可以采取一次次遍历整棵树找到最大的结点放到相应的位置中。

但是这种方法有个不好的地方,就是每个结点都要重复比较多次。

所以我们可以换一种思考的顺序,从下往上进行比较。先找到最后一个有子结点的结点,先让他的两个子结点进行比较,找到大的值再和父结点的值进行比较。如果父结点的

值小,则子结点和父结点进行交换,交换之后再往下比较。然后一步步递归上去,知道所在结点的位置是0号位置跳出。这样就可以有效地减少比较所用到的时间。

但是每一次交换都要重复三步:heap[i] = temp; heap[i] = heap[j]; heap[j] = temp;

当树的结构比较大的时候,就会浪费很多时间。

所以我们可以先把父结点的值存到temp中跟子结点比较,如果子结点大的话就把子结点的值赋值给父结点,再往下比较,最后才把temp的值存到相应的位置。

    void Initialize(T a[], int size, int ArraySize)
    {
        delete []heap;
        isExist = false;
        heap = a;
        CurrentSize = size;
        MaxSize = ArraySize;
        //产生一个最大堆
        for(int i = CurrentSize / 2; i >= 1; i --)
        {
            T y = heap[i];            //子树的根
            //寻找放置y的位置
            int c = 2 * i; //c的父节点是y的目标位置
            while(c <= CurrentSize)
            {
                //heap[c]应是较大的同胞节点
                if(c < CurrentSize && heap[c] < heap[c + 1])
                    c ++;
                //能把y放入heap[c / 2]吗?
                if(y >= heap[c])
                    break;            //能                
                else            //不能
                {
                    heap[c / 2] = heap[c];        //将孩子上移
                    c *= 2;
                }            //下移一层
            }
            heap[c / 2] = y;
        }
    }


最大堆的插入

最大堆的插入的思想就是先在最后的结点添加一个元素,然后沿着树上升。跟最大堆的初始化大致相同。

MaxHeap<T> &Insert(const T&x)
    {    
        if(CurrentSize == MaxSize)
            exit(1);        //没有足够空间
 
        //为x寻找应插入位置
        //i从新的叶节点开始,并沿着树上升
        int i = ++ CurrentSize;
        while(i != 1 && x > heap[i/2])
        {
            //不把x放进heap[i]
            heap[i] = heap[i/2];        //元素下移
            i /= 2;        //移向父节点
        }
        heap[i] = x;        //这时候才把x放进去
        return *this;
    }

最大堆的删除
最大堆的删除,即删除最大的元素。我们先取最后的元素提到根结点,然后删除最大值,然后再把新的根节点放到合适的位置

MaxHeap<T> &DeleteMax(T &x)
    {
        //检查堆是否为空
        if(CurrentSize == 0)
            exit(1);        //队列空
 
        x = heap[1];        //最大元素
        T y = heap[CurrentSize--];        //最后一个元素
        //从根开始,重构大堆
        int i = 1, ci = 2;        //ci为i的儿子
        while(ci < CurrentSize)
        {
            if(ci < CurrentSize && heap[ci] < heap[ci + 1])            //比较两个子节点大小,取其大
                ci ++;
            //能否放y
            if(heap[ci] > y)        //不能
            {
                heap[i] = heap[ci];        //孩子上移
                i = ci;                    //下移一层
                ci *= 2;
            }
            else            //能
                break;
        }
        heap[i] = y;
        return *this;
    }


--------------------- 
作者:genios 
来源:优快云 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值