二项队列由一系列二项树组成,每个高度只允许一棵二项树。每棵树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);
}