zoukankan      html  css  js  c++  java
  • 11、【堆】斜堆

    一、斜堆的介绍

    斜堆(Skew heap)也叫自适应堆(self-adjusting heap),它是左倾堆的一个变种。和左倾堆一样,它通常也用于实现优先队列。它的合并操作的时间复杂度也是O(lg n)。

    相比于左倾堆,斜堆的节点没有"零距离"这个属性。除此之外,它们斜堆的合并操作也不同。斜堆的合并操作算法如下:
      (1) 如果一个空斜堆与一个非空斜堆合并,返回非空斜堆。
      (2) 如果两个斜堆都非空,那么比较两个根节点,取较小堆的根节点为新的根节点。将"较小堆的根节点的右孩子"和"较大堆"进行合并。
      (3) 合并后,交换新堆根节点的左孩子和右孩子。
        第(03)步是斜堆和左倾堆的合并操作差别的关键所在,如果是左倾堆,则合并后要比较左右孩子的零距离大小,若右孩子的零距离 > 左孩子的零距离,则交换左右孩子;最后,在设置根的零距离。

    二、斜堆的解析

    1. 基本定义

     1 template <class T>
     2 class SkewNode{
     3     public:
     4         T key;                // 关键字(键值)
     5         SkewNode *left;        // 左孩子
     6         SkewNode *right;    // 右孩子
     7 
     8         SkewNode(T value, SkewNode *l, SkewNode *r):
     9             key(value), left(l),right(r) {}
    10 };

    SkewNode是斜堆对应的节点类。

     1 template <class T>
     2 class SkewHeap {
     3     private:
     4         SkewNode<T> *mRoot;    // 根结点
     5 
     6     public:
     7         SkewHeap();
     8         ~SkewHeap();
     9 
    10         // 前序遍历"斜堆"
    11         void preOrder();
    12         // 中序遍历"斜堆"
    13         void inOrder();
    14         // 后序遍历"斜堆"
    15         void postOrder();
    16 
    17          // 将other的斜堆合并到this中。
    18         void merge(SkewHeap<T>* other);
    19         // 将结点(key为节点键值)插入到斜堆中
    20         void insert(T key);
    21         // 删除结点(key为节点键值)
    22         void remove();
    23 
    24         // 销毁斜堆
    25         void destroy();
    26 
    27         // 打印斜堆
    28         void print();
    29     private:
    30 
    31         // 前序遍历"斜堆"
    32         void preOrder(SkewNode<T>* heap) const;
    33         // 中序遍历"斜堆"
    34         void inOrder(SkewNode<T>* heap) const;
    35         // 后序遍历"斜堆"
    36         void postOrder(SkewNode<T>* heap) const;
    37 
    38         // 交换节点x和节点y
    39         void swapNode(SkewNode<T> *&x, SkewNode<T> *&y);
    40         // 合并"斜堆x"和"斜堆y"
    41         SkewNode<T>* merge(SkewNode<T>* &x, SkewNode<T>* &y);
    42 
    43         // 销毁斜堆
    44         void destroy(SkewNode<T>* &heap);
    45 
    46         // 打印斜堆
    47         void print(SkewNode<T>* heap, T key, int direction);
    48 };

    SkewHeap是斜堆类,它包含了斜堆的根节点,以及斜堆的操作。

    2. 合并

     1 /*
     2  * 合并"斜堆x"和"斜堆y"
     3  */
     4 template <class T>
     5 SkewNode<T>* SkewHeap<T>::merge(SkewNode<T>* &x, SkewNode<T>* &y)
     6 {
     7     if(x == NULL)
     8         return y;
     9     if(y == NULL)
    10         return x;
    11 
    12     // 合并x和y时,将x作为合并后的树的根;
    13     // 这里的操作是保证: x的key < y的key
    14     if(x->key > y->key)
    15         swapNode(x, y);
    16 
    17     // 将x的右孩子和y合并,
    18     // 合并后直接交换x的左右孩子,而不需要像左倾堆一样考虑它们的npl。
    19     SkewNode<T> *tmp = merge(x->right, y);
    20     x->right = x->left;
    21     x->left  = tmp;
    22 
    23     return x;
    24 }
    25 
    26 /*
    27  * 将other的斜堆合并到this中。
    28  */
    29 template <class T>
    30 void SkewHeap<T>::merge(SkewHeap<T>* other)
    31 {
    32     mRoot = merge(mRoot, other->mRoot);
    33 }

    merge(x, y)是内部接口,作用是合并x和y这两个斜堆,并返回得到的新堆的根节点。
    merge(other)是外部接口,作用是将other合并到当前堆中

    3. 添加

     1 /* 
     2  * 新建键值为key的结点并将其插入到斜堆中
     3  *
     4  * 参数说明:
     5  *     heap 斜堆的根结点
     6  *     key 插入的结点的键值
     7  * 返回值:
     8  *     根节点
     9  */
    10 template <class T>
    11 void SkewHeap<T>::insert(T key)
    12 {
    13     SkewNode<T> *node;    // 新建结点
    14 
    15     // 新建节点
    16     node = new SkewNode<T>(key, NULL, NULL);
    17     if (node==NULL)
    18     {
    19         cout << "ERROR: create node failed!" << endl;
    20         return ;
    21     }
    22 
    23     mRoot = merge(mRoot, node);
    24 }

    insert(key)的作用是新建键值为key的节点,并将其加入到当前斜堆中。

    4. 删除

     1 /* 
     2  * 删除结点
     3  */
     4 template <class T>
     5 void SkewHeap<T>::remove()
     6 {
     7     if (mRoot == NULL)
     8         return NULL;
     9 
    10     SkewNode<T> *l = mRoot->left;
    11     SkewNode<T> *r = mRoot->right;
    12 
    13     // 删除根节点
    14     delete mRoot;
    15     // 左右子树合并后的新树
    16     mRoot = merge(l, r); 
    17 }

    remove()的作用是删除斜堆的最小节点。

  • 相关阅读:
    数学图形(1.12) 螺线
    数学图形(1.11) 玫瑰线
    数学图形(1.10) 双曲线
    数学图形(1.9)悬链线
    数学图形(1.8) 圆外旋轮线
    git 冲突解决
    Nginx配置文件(nginx.conf)配置详解
    【LNMP】提示Nginx PHP “No input file specified”错误的解决办法
    Windows如何压缩tar.gz格式
    LNMP安装目录及配置文件
  • 原文地址:https://www.cnblogs.com/Long-w/p/9786194.html
Copyright © 2011-2022 走看看