二叉堆的Deletemin

本文讨论删除二叉堆的堆顶元素并重构二叉堆,以最小堆为例
(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;





}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值