完全二叉堆

#include "Vector.hpp"

//优先级队列PQ模板类
template <typename T> struct PQ{
    virtual void insert(T) = 0; //按照比较器确定的优先级次序插入词条
    virtual T getMax() = 0; //取出优先级最高的词条
    virtual T delMax() = 0; //删除优先级最高的词条
};



#define InHeap(n, i)            ( ((-1) < (i)) && ( (i)<(n) ) )  //判断PQ[i]是否合法
#define Parent(i)               ( (i-1) >> 1) //PQ[i]的父节点
#define LastInternal(n)         Parent(n-1) //最后一个内部节点(即末节点的父亲)
#define LChild(x)               (1 + ( (i) << 1)) //PQ[i]的左孩子
#define RChild(x)               ( (1 + (i)) << 1)//PQ[i]的右孩子
#define ParentValid(i)          (0 < i) //判断PQ[i]是否有父亲
#define LChildValid(n, i)       InHeap(n, LChild(i)) //判断PQ[i]是否有一个(左)孩子
#define RChildValid(n, i)       InHeap(n, RChild(i)) //判断PQ[i]是否有一个(右)孩子
#define Bigger(PQ, i, j)        ( lt(PQ[i], PQ[j]) ? j : i ) //取大者(等时前者优先)
#define ProperParent(PQ, n, i)  /*父子(至多)三者中的大者*/ \
( RChildValid(n,i) ? Bigger(PQ, Bigger(PQ, i, LChild(i) ),RChild(i) ) : \
( LChildValid(n, i) ? Bigger(PQ, i, LChild(i) ) : i\
)\
) //相等时父节点优先,如此可避免不必要的交换


//完全二叉堆
template <typename T> class PQ_ComplHeap : public PQ<T>, public Vector<T> {
protected:
    Rank percolateDown(Rank n,Rank i); //下滤
    Rank percolateUp(Rank i); //上滤
    void heapify(Rank n); //Floyd建堆算法
    
public:
    PQ_ComplHeap() {}
    
    PQ_ComplHeap(T* A,Rank n) {
        this->copyFrom(A, 0, n);
        heapify(n);
    }
    
    void insert(T); //按照比较器确定的优先级次序,插入词条
    T getMax();//读取优先级最高的词条
    T delMax(); //删除优先级最高的词条
    
};

//优先级最高的词条总是位于堆顶
template <typename T> T PQ_ComplHeap<T>::getMax() {
    return this->_elem[0];
}

//将词条插入完全二叉堆中
template <typename T> void PQ_ComplHeap<T>::insert(T e) {
    Vector<T>::insert(e);  //首先将新词条接至向量末尾
    percolateUp(this->_size - 1);//在对该词条实施上滤调整
}

//对向量中的第i个词条实施上滤操作,i < _size
template <typename T> Rank PQ_ComplHeap<T>::percolateUp(Rank i) {
    while (ParentValid(i)) {
        //只要i有父亲(尚未抵达堆顶),则将i之父记作j
        Rank j = Parent(i);
        
        if ( lt(this->_elem[i], this->_elem[j])) {
            break;  //一旦当前父子不再逆序,上滤旋即完成
        }
        
        //否则,父子交换位置,并继续考察上一层
        std::swap(this->_elem[i], this->_elem[j]);
        i = j;
    }
    
    return i; //返回上滤最终抵达的位置
}

//删除非空完全二叉堆中优先级最高的词条
template <typename T> T PQ_ComplHeap<T>::delMax() {
    //摘除堆顶(首词条),代之以末词条
    T maxElem = this->_elem[0];
    this->_elem[0] = this->_elem[--this->_size];
    
    percolateDown(this->_size, 0); //对新堆顶实施下滤
    return maxElem; //返回此前备份的最大词条
}

//对向量前n个词条中的第i个实施下滤,i < n
template <typename T> Rank PQ_ComplHeap<T>::percolateDown(Rank n, Rank i) {
    Rank j;  //i及其(至多两个)孩子中,勘为父者
    while (i != (j = ProperParent(this->_elem, n, i))) {
        //只要i非j,则二者换位,并继续考察下降后的i
        std::swap(this->_elem[i], this->_elem[j]);
        i = j;
    }
    
    return i; //返回下滤抵达的位置(亦i亦j)
}

//Floyd建堆算法,O(n)时间
template <typename T> void PQ_ComplHeap<T>::heapify(Rank n) {
    for (int i = LastInternal(n); InHeap(n, i); i--) {
        //自底向上,依次下滤各内部节点
        percolateDown(n, i);
    }
}

template <typename T> void Vector<T>::heapSort(Rank lo, Rank hi) {
    //0 <= lo < hi <= size
    PQ_ComplHeap<T> H(this->_elem + lo, hi - lo); //将待排序区间建成一个完全二叉堆
    while (! H.empty()) { //反复地摘除最大元并归入已排序的后缀,直至堆空
        this->_elem[--hi] = H.delMax(); //等效于堆顶与末元素对换后下滤
    }
    
    
}

 

转载于:https://www.cnblogs.com/gkp307/p/9943792.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值