zoukankan      html  css  js  c++  java
  • [BinaryTree] 最大堆的类实现

    堆的定义:

    最大树(最小树):每个结点的值都大于(小于)或等于其子结点(如果有的话)值的树。
    最大堆(最小堆):最大(最小)的完全二叉树。

    最大堆的抽象数据结构:

     1 class MaxHeap
     2 {
     3 private:
     4     T* heapArray;   //存放堆数据的数组
     5     int CurrentSize;//当前堆中元素数目
     6     int MaxSize;    //堆中能容纳的最大元素数目
     7 public:
     8     MaxHeap(T* array,int num,int max);
     9     virtual ~MaxHeap()
    10     {
    11         delete []heapArray;
    12     }
    13     void BuildHeap();
    14     void Swap(int pos_x,int pos_y);     //交换位置x与y的元素
    15     bool IsLeaf(int pos) const;         //如果是叶子结点,返回true
    16     int LeftChild(int pos) const;       //返回左孩子位置
    17     int RightChild(int pos) const;      //返回右孩子位置
    18     int Parent(int pos) const;          //返回父结点位置
    19     bool Remove(int pos,T& node);       //删除给定下标元素
    20     void SiftDown(int left);            //筛选法函数,参数left表示开始处理的数组下标
    21     void SiftUp(int position);          //从position向上开始调整,使序列成为堆
    22     bool Insert(const T& newNode);      //向堆中插入新元素newNode
    23     T& RemoveMax();                     //从堆顶删除最大值
    24     void print();                       //输出函数
    25 };

    下面是一些简单函数的实现:

     1 template<class T>
     2 MaxHeap<T>::MaxHeap(T* array,int num,int max)
     3 {
     4     heapArray = array;
     5     CurrentSize = num;
     6     MaxSize = max;
     7 }
     8 template<class T>
     9 void MaxHeap<T>::Swap(int pos_x,int pos_y)
    10 {
    11     T temp = heapArray[pos_x];
    12     heapArray[pos_x] = heapArray[pos_y];
    13     heapArray[pos_y] = temp;
    14 }
    15 template<class T>
    16 bool MaxHeap<T>::IsLeaf(int pos) const
    17 {
    18     return (pos>=CurrentSize/2)&&(pos<CurrentSize);
    19 }
    20 template<class T>
    21 int MaxHeap<T>::LeftChild(int pos) const
    22 {
    23     return pos*2+1;
    24 }
    25 template<class T>
    26 int MaxHeap<T>::RightChild(int pos) const
    27 {
    28     return pos*2+2;
    29 }
    30 template<class T>
    31 int MaxHeap<T>::Parent(int pos) const
    32 {
    33     if(pos == 0)
    34         return -1;
    35     return (pos-1)/2;
    36 }

    下面来看几个重要的操作的实现:

    ·堆的插入操作

    (1)新元素添加到末尾(保持完全二叉树的性质);
    (2)为了保持堆的性质,沿着其祖先的路径,自下而上依次比较和交换该结点与父结点的位置,直到重新满足堆的性质位置;
    (3)在插入过程中,总是自下而上逐渐上升,最后停留在某个满足堆的性质的位置,故此过程又称为 “筛选”。

     1 template<class T>
     2 bool MaxHeap<T>::Insert(const T& newNode)
     3 {
     4     if(CurrentSize == MaxSize)
     5         return false;
     6     heapArray[CurrentSize] = newNode;
     7     SiftUp(CurrentSize);
     8     CurrentSize++;
     9     return true;
    10 }

    ·建堆过程

    (1)首先将所有关键码放到一维数组中,这时形成的完全二叉树并不具备堆的特性,但是仅包含叶子结点的子树已经是堆 (即在有n个结点的完全二叉树中,当i > [n/2]-1时,以关键码Ki为根的子树已经是堆。
    (2)这时从含有内部结点数最少的子树(这种子树在完全二叉树的倒数第二层,此时i = [n/2]-1开始,从右至左依次调整。
    (3)对这一层调整完成之后,继续对上一层进行同样的工作,直到整个过程到达树根时,整棵完全二叉树就成为一个堆了

    1 template<class T>
    2 void MaxHeap<T>::BuildHeap()
    3 {
    4     for(int i = CurrentSize/2-1; i >= 0; i--)
    5     {
    6         SiftDown(i);
    7     }
    8 }

    ·堆的删除操作

    (1)把最末端结点填入删除产生的空位(保持完全二叉树的性质)
    (2)为了保持堆的性质,比较当前结点和其父节点的大小来决定向上还是向下“筛选”,直到重新满足堆的性质位置

     1 template<class T>
     2 bool MaxHeap<T>::Remove(int pos,T& node)
     3 {
     4     if(pos < 0 || pos >= CurrentSize)
     5         return false;
     6     node = heapArray[pos];
     7     heapArray[pos] = heapArray[--CurrentSize];
     8     if(heapArray[Parent(pos)] < heapArray[pos])
     9     {
    10         SiftUp(pos);
    11     }
    12     else SiftDown(pos);
    13     return true;
    14 }

    下面是删除堆顶元素的代码:

     1 template<class T>
     2 T& MaxHeap<T>::RemoveMax()
     3 {
     4     if(CurrentSize == 0)
     5     {
     6         cout<<"Can't delete"<<endl;
     7         exit(1);
     8     }
     9     else
    10     {
    11         Swap(0,--CurrentSize);
    12         if(CurrentSize>1)
    13         {
    14             SiftDown(0);
    15         }
    16         return heapArray[CurrentSize];
    17     }
    18 }

    下面是该类的核心代码:

    向下筛选:

     1 template<class T>
     2 void MaxHeap<T>::SiftDown(int left)
     3 {
     4     int i = left;           //标识父结点
     5     int j = LeftChild(i);   //标识关键码较小的子结点
     6     T temp = heapArray[i];  //保存父结点
     7     while(j < CurrentSize)  //筛选
     8     {
     9         if((j < CurrentSize-1)&&(heapArray[j] < heapArray[j+1]))
    10         {//若有右结点,且大于左结点
    11             j++;    //则j指向右结点
    12         }
    13         if(temp < heapArray[j])
    14         {//若父结点小于子结点的值则交换位置
    15             heapArray[i] = heapArray[j];
    16             i = j;
    17             j = LeftChild(j);
    18         }
    19         else break;//找到恰当的位置,跳出循环
    20     }
    21     heapArray[i] = temp;
    22 }

    向上筛选:

     1 template<class T>
     2 void MaxHeap<T>::SiftUp(int position)
     3 {   //从position开始向上调整
     4     int tempos = position;
     5     T temp = heapArray[tempos];
     6     while((tempos > 0)&&(temp > heapArray[Parent(tempos)]))
     7     {
     8         heapArray[tempos] = heapArray[Parent(tempos)];
     9         tempos = Parent(tempos);
    10     }
    11     heapArray[tempos] = temp;
    12 }

    测试函数:

     1 int main()
     2 {
     3     int a[10] = {1,2,3,4,5,6,7,8,9,3};
     4     MaxHeap<int> S(a,10,20);
     5     cout<<"构建最大堆:"<<endl;
     6     S.BuildHeap();
     7     S.print();
     8     cout<<"插入元素10:"<<endl;
     9     int newNode = 10;
    10     S.Insert(newNode);
    11     S.print();
    12     cout<<"删除堆顶元素:"<<endl;
    13     S.RemoveMax();
    14     S.print();
    15     cout<<"删除pos = 1的元素:"<<endl;
    16     int x;
    17     S.Remove(1,x);
    18     cout<<"x = "<<x<<endl;
    19     S.print();
    20     return 0;
    21 }

    测试结果:

  • 相关阅读:
    剑指Offer47 不用加减乘除做加法
    剑指Offer46 求1+2+...+n
    剑指Offer45 约瑟夫环
    剑指Offer44 扑克牌的顺子
    剑指Offer43 n个骰子点数概率
    面试题分享
    初识python版本
    redis安装部署
    配置本地yum源
    闭包、装饰器
  • 原文地址:https://www.cnblogs.com/lca1826/p/6590864.html
Copyright © 2011-2022 走看看