• 9、【堆】二叉堆


    一、堆和二叉堆的介绍

    堆的定义

    堆(heap),这里所说的堆是数据结构中的堆,而不是内存模型中的堆。堆通常是一个可以被看做一棵树,它满足下列性质:
      [性质一] 堆中任意节点的值总是不大于(不小于)其子节点的值;
      [性质二] 堆总是一棵完全树。
    将任意节点不大于其子节点的堆叫做最小堆或小根堆,而将任意节点不小于其子节点的堆叫做最大堆或大根堆。常见的堆有二叉堆、左倾堆、斜堆、二项堆、斐波那契堆等等。

    二叉堆的定义

    二叉堆是完全二元树或者是近似完全二元树,它分为两种:最大堆和最小堆。
    最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。

    二叉堆一般都通过"数组"来实现。数组实现的二叉堆,父节点和子节点的位置存在一定的关系。有时候,我们将"二叉堆的第一个元素"放在数组索引0的位置,有时候放在1的位置。当然,它们的本质一样(都是二叉堆),只是实现上稍微有一丁点区别。
    假设"第一个元素"在数组中的索引为 0 的话,则父节点和子节点的位置关系如下:
      (1) 索引为i的左孩子的索引是 (2*i+1);
      (2) 索引为i的左孩子的索引是 (2*i+2);
      (3) 索引为i的父结点的索引是 floor((i-1)/2);

    假设"第一个元素"在数组中的索引为 1 的话,则父节点和子节点的位置关系如下:
      (1) 索引为i的左孩子的索引是 (2*i);
      (2) 索引为i的左孩子的索引是 (2*i+1);
      (3) 索引为i的父结点的索引是 floor(i/2);

    二、二叉堆的解析

    以"最大堆"来进行介绍的。

    1. 基本定义

     1 template <class T>
     2 class MaxHeap{
     3     private:
     4         T *mHeap;        // 数据
     5         int mCapacity;    // 总的容量
     6         int mSize;        // 实际容量
     7 
     8     private:
     9         // 最大堆的向下调整算法
    10         void filterdown(int start, int end);
    11         // 最大堆的向上调整算法(从start开始向上直到0,调整堆)
    12         void filterup(int start);
    13     public:
    14         MaxHeap();
    15         MaxHeap(int capacity);
    16         ~MaxHeap();
    17 
    18         // 返回data在二叉堆中的索引
    19         int getIndex(T data);
    20         // 删除最大堆中的data
    21         int remove(T data);
    22         // 将data插入到二叉堆中
    23         int insert(T data);
    24         // 打印二叉堆
    25         void print();
    26 };

    2. 添加

     1 /*
     2  * 最大堆的向上调整算法(从start开始向上直到0,调整堆)
     3  *
     4  * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
     5  *
     6  * 参数说明:
     7  *     start -- 被上调节点的起始位置(一般为数组中最后一个元素的索引)
     8  */
     9 template <class T>
    10 void MaxHeap<T>::filterup(int start)
    11 {
    12     int c = start;            // 当前节点(current)的位置
    13     int p = (c-1)/2;        // 父(parent)结点的位置 
    14     T tmp = mHeap[c];        // 当前节点(current)的大小
    15 
    16     while(c > 0)
    17     {
    18         if(mHeap[p] >= tmp)
    19             break;
    20         else
    21         {
    22             mHeap[c] = mHeap[p];
    23             c = p;
    24             p = (p-1)/2;   
    25         }       
    26     }
    27     mHeap[c] = tmp;
    28 }
    29   
    30 /* 
    31  * 将data插入到二叉堆中
    32  *
    33  * 返回值:
    34  *     0,表示成功
    35  *    -1,表示失败
    36  */
    37 template <class T>
    38 int MaxHeap<T>::insert(T data)
    39 {
    40     // 如果"堆"已满,则返回
    41     if(mSize == mCapacity)
    42         return -1;
    43  
    44     mHeap[mSize] = data;        // 将"数组"插在表尾
    45     filterup(mSize);    // 向上调整堆
    46     mSize++;                    // 堆的实际容量+1
    47 
    48     return 0;
    49 }

    insert(data)的作用:将数据data添加到最大堆中。当堆已满的时候,添加失败;否则data添加到最大堆的末尾。然后通过上调算法重新调整数组,使之重新成为最大堆。

    3. 删除

     1 /* 
     2  * 最大堆的向下调整算法
     3  *
     4  * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
     5  *
     6  * 参数说明:
     7  *     start -- 被下调节点的起始位置(一般为0,表示从第1个开始)
     8  *     end   -- 截至范围(一般为数组中最后一个元素的索引)
     9  */
    10 template <class T>
    11 void MaxHeap<T>::filterdown(int start, int end)
    12 {
    13     int c = start;          // 当前(current)节点的位置
    14     int l = 2*c + 1;     // 左(left)孩子的位置
    15     T tmp = mHeap[c];    // 当前(current)节点的大小
    16 
    17     while(l <= end)
    18     {
    19         // "l"是左孩子,"l+1"是右孩子
    20         if(l < end && mHeap[l] < mHeap[l+1])
    21             l++;        // 左右两孩子中选择较大者,即mHeap[l+1]
    22         if(tmp >= mHeap[l])
    23             break;        //调整结束
    24         else
    25         {
    26             mHeap[c] = mHeap[l];
    27             c = l;
    28             l = 2*l + 1;   
    29         }       
    30     }   
    31     mHeap[c] = tmp;
    32 }
    33 
    34 /*
    35  * 删除最大堆中的data
    36  *
    37  * 返回值:
    38  *      0,成功
    39  *     -1,失败
    40  */
    41 template <class T>
    42 int MaxHeap<T>::remove(T data)
    43 {
    44     int index;
    45     // 如果"堆"已空,则返回-1
    46     if(mSize == 0)
    47         return -1;
    48 
    49     // 获取data在数组中的索引
    50     index = getIndex(data); 
    51     if (index==-1)
    52         return -1;
    53 
    54     mHeap[index] = mHeap[--mSize];    // 用最后元素填补
    55     filterdown(index, mSize-1);        // 从index位置开始自上向下调整为最大堆
    56 
    57     return 0;
    58 }
  • 相关阅读:
    检查.net代码中占用高内存函数(翻译)
    DataTable添加行和列
    使用.NET中的Action及Func泛型委托
    基于Emgu cv的图像拼接(转)
    AForge学习笔记(列表)
    标准Dispose实现 (转)
    在WPF程序中使用摄像头兼谈如何使用AForge.NET控件(转)
    NBearV3中文教程总目录
    如何在我们项目中利用开源的图表(js chart)
    1、NameNode启动流程的初始化操作
  • 原文地址:https://www.cnblogs.com/Long-w/p/9786146.html
Copyright © 2020-2023  润新知