本文讨论删除二叉堆的堆顶元素并重构二叉堆,以最小堆为例
(1)删除堆顶元素会产生一个位于堆顶的空穴和一个多余的元素lastelement(最后一个元素),我们需要在空穴的两个孩子以及lastelement之间进行比较
将三者中的最小者填入空穴,并产生新的空穴,直至lastelement填入某个空穴中,这种算法对于每个空穴要进行两次比较,而空穴最多产生log N个,故需要2*log N次比较。这便是我们最常见的算法,代码如下:
template<typename T>
void binaryheap<T>::Deletemin()
{
int i,child;
T lastelement;
if(size==0){
cout<<"Empty Heap!"<<endl;
return;
}
lastelement=elements[size--];
for(i=1;i*2<=size;i=child){
child = i*2;
//判断节点是否有两个儿子
if(child!=size&&elements[child+1]<elements[child])
child++;
if(lastelement>elements[child])
elements[i]=elements[child];
else break;
}
elements[i]=lastelement;
}
(2)我们引入一个新的概念chain,chain中的每一个元素都是其父亲的两个孩子中较小的一个,通过log N次比较可以自上而下地构建一个堆的chain,通过lastelement对chain执行二分查找并插入到chain。之后我们删除堆顶元素,chain中小于lastelement的项高度加一,大于lastelement的项高度不变,这样我们通过log N+log log N+O(1)比较就完成了Deletemin
template<typename T>
void binaryheap<T>::Deletemin()
{
int i,child;
T lastelement;
vector<T> chain;
vector<int> number;
if(size==0){
cout<<"Empty Heap!"<<endl;
return;
}
lastelement=elements[size--];
number.push_back(1);
for(i=1;i*2<=size;i=child){
child = i*2;
//判断节点是否有两个儿子
if(child!=size&&elements[child+1]<elements[child])
child++;
chain.push_back(elements[child]);
number.push_back(child);
}
int k=findposition(chain,lastelement);
for(i=0;i<k;i++)
elements[number[i]]=chain[i];
elements[number[k]]=lastelement;
}
(3)在(2)的基础上我们进行扩展,既然问题转化成在chain中删除最小元并插入lastelement,那我们可以将chain构建成一个堆,这样就是一个对新堆的Deletemin,如此嵌套下去,我们显然可以得出一个比较次数为log N+log log……log N + O(1)的算法,但切记需要在最后对插入元素的位置进行适当调整
template<typename T>
int binaryheap<T>::DeleteminAndInsert(T x)
{
int i,child;
vector<T> chain;
vector<int> number;
if(size==0){
cout<<"Empty Heap!"<<endl;
return 0;
}
chain.push_back(elements[1]);
number.push_back(1);
for(i=1;i*2<=size;i=child){
child = i*2;
//判断节点是否有两个儿子
if(child!=size&&elements[child+1]<elements[child])
child++;
chain.push_back(elements[child]);
number.push_back(child);
}
int k=po_chain(chain,x);
for(i=0;i<k;i++)
elements[number[i]]=chain[i+1];
elements[number[k]]=x;
return number[k];
}
//先找出一条chain,再把chain组建成堆,执行deletemin
template<typename T>
void binaryheap<T>::DeleteminC()
{
T lastelement;
lastelement=elements[size--];
DeleteminAndInsert(lastelement);
}
template<typename T>
int binaryheap<T>::po_chain(vector<T> chain,T x)
{
if(chain.size()==2){
if(chain[0]<=x)
return 1;
else if(chain[0]>x)
return 0;
}
binaryheap<T> H(chain);
H.print();
int position = H.DeleteminAndInsert(x);
H.print();
int i;
for(i=position;i<position*2&&i<H.size;i++){
if(x>H.elements[i+1])
H.elements[i]=H.elements[i+1];
else {
break;
}
}
H.elements[i] = x;
H.print();
return i-1;
}