10.2 堆

参考博客: https://blog.csdn.net/weixin_41698717/article/details/107789354

本章问题

1.完全二叉堆的堆序性是什么

堆序性:堆顶之外的每个节点都不大于其父节点。

2.完全二叉堆中的上滤是如何操作的

对第i 个词条进行上滤,
查看该节点的父亲是否小于该节点,
1.如果小于该节点,与父节点交换,然后对父节点位置进行上滤
2.如果大于该节点,结束上滤, 并返回上滤最终抵达的位置

3.完全二叉堆的插入中是如何查找插入位置的

将词条插入末尾位置,然后对该词条进行上滤操作

4.完全二叉堆中的下滤是如何操作的

1.当左孩子节点存在时,若节点大于父亲,将父节点与左节点交换,之后判断右节点
2.当右孩子节点存在时,若节点大于父亲,将父节点与节点交换。
3.获取三者中的大者,若最大者若不为自己,二者换位,并继续考查下降后的 原父节点

5.完全二叉堆中的删除顶节点的是如何操作的

1.摘除堆顶(首词条),代之以末词条
2.对新堆顶实施下滤

6.Floyd是如何建堆的

从末节点依次遍历到头结点,对每个节点的父亲,依次进行下滤

7.PQ_ComplHeap是如何进行构造的

使用拷贝函数依次复制元素到堆中,然后进行Floyd建堆。

8.在PQ_ComplHeap.h文件中生成heapsort失败

将vector中堆排序接口权限改为public后,在测试调用堆排序成功,若是protected会出错

10.2.1 PQ_ComplHeap

//"pq.h"
#pragma once

template <typename T> struct PQ {
    
     //优先级队列PQ模板类
   virtual void insert ( T ) = 0; //按照比较器确定的优先级次序插入词条
   virtual T getMax() = 0; //取出优先级最高的词条
   virtual T delMax() = 0; //删除优先级最高的词条
};
//"pq_macro.h"
#pragma once
#define  InHeap(n, i)      ( ( ( -1 ) < ( i ) ) && ( ( i ) < ( n ) ) ) //判断PQ[i]是否合法
#define  Parent(i)         ( ( i - 1 ) >> 1 ) //PQ[i]的父节点(floor((i-1)/2),i无论正负)
#define  LastInternal(n)   Parent( n - 1 ) //最后一个内部节点(即末节点的父亲)
#define  LChild(i)         ( 1 + ( ( i ) << 1 ) ) //PQ[i]的左孩子
#define  RChild(i)         ( ( 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)  (  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 \
            ) \
            ) //相等时父节点优先,如此可避免不必要的交换

10.2.1.1 PQ_ComplHeap ADT接口

操作接口 功能描述
percolateDown(n,i ) 对向量前n个词条中的第i个实施下滤,i < n
percolateUp(i ) 对向量中的第i个词条实施上滤操作
heapify(n ) Floyd建堆算法
PQ_ComplHeap( ) 默认构造
PQ_ComplHeap(A,n ) 批量构造
insert ( T ) 按照比较器确定的优先级次序,插入词条
getMax( ) 读取优先级最高的词条
delMax( ) 删除优先级最高的词条

10.2.1.2 PQ_ComplHeap类模板

#include "vector.h" //借助多重继承机制,基于向量
#include "pq_macro.h"
#include "pq.h" //按照优先级队列ADT实现的
template <typename T> class PQ_ComplHeap : public PQ<T>, public Vector<T> {
    
     //完全二叉堆
//    /*DSA*/friend class UniPrint; //演示输出使用,否则不必设置友类
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(); //删除优先级最高的词条
}; //PQ_ComplHeap

10.2.1.3 getMax

//getMax()
template <typename T> T PQ_ComplHeap<T>::getMax() {
    
      return this->_elem[0];  }

10.2.1.4 insert

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

10.2.1.5 delMax()

//delMax()
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; //返回此前备份的最大词条
}

10.2.1.5 percolateUp()

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

10.2.1.6 percolateDown

//对向量前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,则
      {
    
     swap ( this->_elem[i], this->_elem[j] ); i = j; } //二者换位,并继续考查下降后的i
   return i; //返回下滤抵达的位置(亦i亦j)
}

10.2.1.6 Floyd建堆

//Floyd建堆
template <typename T> void PQ_ComplHeap<T>::heapify ( Rank n ) {
    
     //Floyd建堆算法,O(n)时间
   for ( int i = LastInternal ( n ); InHeap ( n, i ); i-- ) //自底而上,依次
/*DSA*/
      percolateDown ( n, i ); //下滤各内部节点
// /*DSA*/for ( int k = 0; k < n; k++ ) {
    
    
// /*DSA*/  int kk = k; while ( i < kk ) kk = (kk - 1) / 2;
// /*DSA*/  i == kk ? print(_elem[k]) : print("    " );
// /*DSA*/}; printf("\n");
// /*DSA*/}
}

10.2.2 PQ_ComplHeap.h

#include "vector.h" //借助多重继承机制,基于向量
#include "pq_macro.h"
#include "pq.h" //按照优先级队列ADT实现的
template <typename T> class PQ_ComplHeap : public PQ<T>, public Vector<T> {
    
     //完全二叉堆
//    /*DSA*/friend class UniPrint; //演示输出使用,否则不必设置友类
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(); //删除优先级最高的词条
}; //PQ_ComplHeap

//getMax()
template <typename T> T PQ_ComplHeap<T>::getMax() {
    
      return this->_elem[0];  }


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


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

//delMax()
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,则
      {
    
     swap ( this->_elem[i], this->_elem[j] ); i = j; } //二者换位,并继续考查下降后的i
   return i; //返回下滤抵达的位置(亦i亦j)
}

//Floyd建堆
template <typename T> void PQ_ComplHeap<T>::heapify ( Rank n ) {
    
     //Floyd建堆算法,O(n)时间
   for ( int i = LastInternal ( n ); InHeap ( n, i ); i-- ) //自底而上,依次
/*DSA*/
      percolateDown ( n, i ); //下滤各内部节点
// /*DSA*/for ( int k = 0; k < n; k++ ) {
    
    
// /*DSA*/  int kk = k; while ( i < kk ) kk = (kk - 1) / 2;
// /*DSA*/  i == kk ? print(_elem[k]) : print("    " );
// /*DSA*/}; printf("\n");
// /*DSA*/}
}

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

10.2.3 PQ_ComplHeap.h测试

#include "pq_complheap.h"
#include <iostream>
using namespace std;
int main(){
    
    
    int A[] = {
    
     4, 2, 5, 1, 3};
    //测试建堆函数
    PQ_ComplHeap<int> a (A, 5);
    //测试getMax
    cout << a.getMax() << endl;//5
    //测试insert
    a.insert( 6 );
    //测试delMax
    cout << a.delMax() << endl;//6
    cout << a.getMax() << endl;//5

    //测试堆排序
    Vector<int> vec(A, 5);
    vec.heapSort( 0, 5);
    for( int i= 0; i<5; ++i )
        cout << vec[i] << " ";//1 2 3 4 5 
}

猜你喜欢

转载自blog.csdn.net/ZXG20000/article/details/115027354
今日推荐