堆——二项队列

二项队列由一系列二项树组成,每个高度只允许一棵二项树。每棵树Bk由一个根和Bk-1…B0组成。删除最小值操作是先找到最小根值的树,然后删掉树根,得到新的一组二项队列Bk-1…B0。将两个队列合并,便完成了删除最小值操作。

#include <vector>

template <typename Comparable>
class BinomialQueue
{
public:
    BinomialQueue();
    BinomialQueue(const Comparable & item);
    BinomialQueue(const BinomialQueue & rhs);
    BinomialQueue(BinomialQueue && rhs);

    ~BinomialQueue();

    BinomialQueue & operator=(const BinomialQueue & rhs);
    BinomialQueue & operator=(BinomialQueue && rhs);

    bool isEmpty()const;
    const Comparable & findMin()const;

    void insert(const Comparable & x);
    void insert(Comparable && x);
    void deleteMin();
    void deleteMin(Comparable & minItem);

    void makeEmpty();
    void merge(BinomialQueue & rhs);

private:
    struct BinomialNode
    {
        Comparable   element;
        BinomialNode *leftChild;
        BinomialNode *nextSibling;

        BinomialNode(const Comparable & e,BinomialNode * lt,BinomialNode *rt)
        :element(e),leftChild(lt),nextSibling(rt){}

        BinomialNode(Comparable && e,BinomialNode * lt,BinomialNode *rt)
        :element(std::move(e)),leftChild(lt),nextSibling(rt){}

    };

    const static int DEFAULT_TREES=1;
    std::vector<BinomialNode *> theTrees;
    int currentSize;                        //优先队列中的项数

    int findMinIndex()const;
    int capacity()const                     //数组最多能存储的项数
    {
        int Num=0;
        int s=1;
        for(int i=0;i<theTrees.size();++i)
        {
            Num+=s;
            s*=2;
        }
        return Num;
    }
    BinomialNode * combineTrees(BinomialNode *t1,BinomialNode *t2);
    void makeEmpty(BinomialNode * & t);
    BinomialNode * clone(BinomialNode * t)const;
};

//合并同样大小的二项树
template <typename Comparable>
typename BinomialQueue<Comparable>::BinomialNode *
BinomialQueue<Comparable>::combineTrees(BinomialNode *t1, BinomialNode *t2)
{
    if(t2->element<t1->element)
        return combineTrees(t2, t1);

    t2->nextSibling=t1->leftChild;
    t1->leftChild=t2;
    return t1;

}

template <typename Comparable>
void BinomialQueue<Comparable>::merge(BinomialQueue & rhs)
{
    if(this==&rhs)
        return;

    currentSize+=rhs.currentSize;

    if(currentSize>capacity())  //capacity代表当前数组能容纳的最多项数
    {
        int oldNumTrees=theTrees.size();
        int newNumTrees=max(theTrees.size(),rhs.theTrees.size())+1;
        theTrees.resize(newNumTrees);
        for(int i=oldNumTrees;i<newNumTrees;++i)
            theTrees[i]=nullptr;
    }

    BinomialNode *carry=nullptr;    //由上一位合并而来的

    for(int i=0,j=1;j<=currentSize;++i,j*=2)
    {
        BinomialNode *t1=theTrees[i];
        BinomialNode *t2=i<rhs.theTrees.size()?rhs.theTrees[i]:nullptr;

        int whichcase=t1==nullptr?0:1;
        whichcase+=t2==nullptr?0:2;
        whichcase+=carry==nullptr?0:4;  //类似加法,carry代表进位

        switch (whichcase) {
            case 0:                     //都是空
            case 1:                     //只有this
                break;
            case 2:                     //只有rhs
                theTrees[i]=t2;
                rhs.theTrees[i]=nullptr;
                break;
            case 4:                     //只有carry
                theTrees[i]=carry;
                carry=nullptr;
                break;
            case 3:                     //this和rhs
                carry=combineTrees(t1, t2);
                theTrees[i]=rhs.theTrees[i]=nullptr;
                break;
            case 5:                     //this和carry
                carry=combineTrees(t1, carry);
                theTrees[i]=nullptr;
                break;
            case 6:                     //carry和rhs
                carry=combineTrees(carry, t2);
                rhs.theTrees[i]=nullptr;
                break;
            case 7:                     //三者都有
                theTrees[i]=carry;
                carry=combineTrees(carry, t2);
                rhs.theTrees[i]=nullptr;
                break;
            default:
                break;
        }
    }

    for(auto & root:rhs.theTrees)
        root=nullptr;
    rhs.currentSize=0;

}

template <typename Comparable>
int BinomialQueue<Comparable>::findMinIndex()const
{
    int minIndex;
    int i;
    for(int i=0;theTrees[i]==nullptr;++i)
        ;
    for(minIndex=i;i<theTrees.size();++i)
        if(theTrees[i]!=nullptr&&theTrees[i]->element<theTrees[minIndex]->element)
        {
            minIndex=i;
        }
    return minIndex;
}


template <typename Comparable>
void BinomialQueue<Comparable>::deleteMin(Comparable & minItem)
{
    //if(isEmpty())
        //throw UnderflowException{};

    int minIndex=findMinIndex();
    minItem=theTrees[minIndex]->element;

    BinomialNode *oldRoot=theTrees[minIndex];
    BinomialNode *deletedTree=oldRoot->leftChild;
    delete oldRoot;

    BinomialQueue deletedQueue;
    deletedQueue.theTrees.resize(minIndex+1);   //应该有minIndex个二项树

    //将1左移minIndex位得到minIndex处项数然后减去1(根节点)
    deletedQueue.currentSize=(1<<minIndex)-1;

    for(int j=minIndex-1;j>=0;--j)
    {
        deletedQueue.theTrees[j]=deletedTree;
        deletedTree=deletedTree->nextSibling;
        deletedQueue.theTrees[j]->nextSibling=nullptr;
    }

    theTrees[minIndex]=nullptr;

    //因为将minIndex处删除掉了,所以currentSize要减去它的项数
    currentSize-=deletedQueue.currentSize+1;

    merge(deletedQueue);

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值