10.2 Heap

Reference blog: https://blog.csdn.net/weixin_41698717/article/details/107789354

Questions in this chapter

1. What is the heap order of a complete binary heap

Heap sequence: every node outside the top of the heap is not greater than its parent node.

2. How does the filter in a complete binary stack operate?

Filter up the i-th entry to
see
if the parent of the node is less than the node. 1. If it is less than the node, exchange with the parent node, and then filter the position of the parent node.
2. If it is greater than the node, end the filter , And return to the location where the upper filter finally arrived

3. How to find the insertion position in the insertion of a complete binary heap

Insert the entry at the end, and then filter the entry

4. How does the down filter in a complete binary stack operate?

1. When the left child node exists, if the node is greater than the parent, the parent node is exchanged with the left node, and then the right node is judged
. 2. When the right child node exists, if the node is greater than the parent, the parent node is exchanged with the node.
3. Get the larger of the three. If the largest is not for yourself, switch the two and continue to examine the original parent node after the drop

5. How to delete the top node in a complete binary heap

1. Remove the top of the pile (the first entry) and replace it with the last entry
. 2. Implement a filter down on the new top of the pile

6. How does Floyd build a stack

Traverse from the end node to the head node in turn, and filter down the father of each node in turn

7. How PQ_ComplHeap is constructed

Use the copy function to copy elements to the heap in turn, and then build the heap by Floyd.

8. Failed to generate heapsort in the PQ_ComplHeap.h file

After changing the permission of the heap sort interface in vector to public, the test call heap sort is successful, if it is protected, an error will occur

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 interface

Operation interface Function description
percolateDown(n,i ) Perform down-filtering on the i-th among the first n entries of the vector, i <n
percolateUp(i ) Perform an up-filtering operation on the i-th entry in the vector
heapify(n ) Floyd heap building algorithm
PQ_ComplHeap () Default construction
PQ_ComplHeap(A,n ) Batch construction
insert ( T ) Insert entries according to the priority order determined by the comparator
getMax( ) Read the entry with the highest priority
delMax( ) Delete the highest priority entry

10.2.1.2 PQ_ComplHeap class template

#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 stack building

//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 test

#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 
}

Guess you like

Origin blog.csdn.net/ZXG20000/article/details/115027354