概要

上一章介绍了斜堆的基本概念,并通过C语言实现了斜堆。本章是斜堆的C++实现。

目录
1. 斜堆的介绍
2. 斜堆的基本操作
3. 斜堆的C++实现(完整源码)
4. 斜堆的C++测试程序

转载请注明出处:http://www.cnblogs.com/skywang12345/p/3638524.html


更多内容:数据结构与算法系列 目录

 

斜堆的介绍

斜堆(Skew heap)也叫自适应堆(self-adjusting heap),它是左倾堆的一个变种。和左倾堆一样,它通常也用于实现优先队列;作为一种自适应的左倾堆,它的合并操作的时间复杂度也是O(lg n)。
它与左倾堆的差别是:
(01) 斜堆的节点没有"零距离"这个属性,而左倾堆则有。
(02) 斜堆的合并操作和左倾堆的合并操作算法不同。

斜堆的合并操作
(01) 如果一个空斜堆与一个非空斜堆合并,返回非空斜堆。
(02) 如果两个斜堆都非空,那么比较两个根节点,取较小堆的根节点为新的根节点。将"较小堆的根节点的右孩子"和"较大堆"进行合并。
(03) 合并后,交换新堆根节点的左孩子和右孩子。
       第(03)步是斜堆和左倾堆的合并操作差别的关键所在,如果是左倾堆,则合并后要比较左右孩子的零距离大小,若右孩子的零距离 > 左孩子的零距离,则交换左右孩子;最后,在设置根的零距离。

 

斜堆的基本操作

1. 基本定义

template <class T>
class SkewNode{
    public:
        T key;                // 关键字(键值)
        SkewNode *left;        // 左孩子
        SkewNode *right;    // 右孩子

        SkewNode(T value, SkewNode *l, SkewNode *r):
            key(value), left(l),right(r) {}
};

SkewNode是斜堆对应的节点类。

template <class T>
class SkewHeap {
    private:
        SkewNode<T> *mRoot;    // 根结点

    public:
        SkewHeap();
        ~SkewHeap();

        // 前序遍历"斜堆"
        void preOrder();
        // 中序遍历"斜堆"
        void inOrder();
        // 后序遍历"斜堆"
        void postOrder();

         // 将other的斜堆合并到this中。
        void merge(SkewHeap<T>* other);
        // 将结点(key为节点键值)插入到斜堆中
        void insert(T key);
        // 删除结点(key为节点键值)
        void remove();

        // 销毁斜堆
        void destroy();

        // 打印斜堆
        void print();
    private:

        // 前序遍历"斜堆"
        void preOrder(SkewNode<T>* heap) const;
        // 中序遍历"斜堆"
        void inOrder(SkewNode<T>* heap) const;
        // 后序遍历"斜堆"
        void postOrder(SkewNode<T>* heap) const;

        // 交换节点x和节点y
        void swapNode(SkewNode<T> *&x, SkewNode<T> *&y);
        // 合并"斜堆x"和"斜堆y"
        SkewNode<T>* merge(SkewNode<T>* &x, SkewNode<T>* &y);

        // 销毁斜堆
        void destroy(SkewNode<T>* &heap);

        // 打印斜堆
        void print(SkewNode<T>* heap, T key, int direction);
};

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

 

2. 合并

/*
 * 合并"斜堆x"和"斜堆y"
 */
template <class T>
SkewNode<T>* SkewHeap<T>::merge(SkewNode<T>* &x, SkewNode<T>* &y)
{
    if(x == NULL)
        return y;
    if(y == NULL)
        return x;

    // 合并x和y时,将x作为合并后的树的根;
    // 这里的操作是保证: x的key < y的key
    if(x->key > y->key)
        swapNode(x, y);

    // 将x的右孩子和y合并,
    // 合并后直接交换x的左右孩子,而不需要像左倾堆一样考虑它们的npl。
    SkewNode<T> *tmp = merge(x->right, y);
    x->right = x->left;
    x->left  = tmp;

    return x;
}

/*
 * 将other的斜堆合并到this中。
 */
template <class T>
void SkewHeap<T>::merge(SkewHeap<T>* other)
{
    mRoot = merge(mRoot, other->mRoot);
}

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


3. 添加

/* 
 * 新建键值为key的结点并将其插入到斜堆中
 *
 * 参数说明:
 *     heap 斜堆的根结点
 *     key 插入的结点的键值
 * 返回值:
 *     根节点
 */
template <class T>
void SkewHeap<T>::insert(T key)
{
    SkewNode<T> *node;    // 新建结点

    // 新建节点
    node = new SkewNode<T>(key, NULL, NULL);
    if (node==NULL)
    {
        cout << "ERROR: create node failed!" << endl;
        return ;
    }

    mRoot = merge(mRoot, node);
}

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

 

4. 删除

/* 
 * 删除结点
 */
template <class T>
void SkewHeap<T>::remove()
{
    if (mRoot == NULL)
        return NULL;

    SkewNode<T> *l = mRoot->left;
    SkewNode<T> *r = mRoot->right;

    // 删除根节点
    delete mRoot;
    // 左右子树合并后的新树
    mRoot = merge(l, r); 
}

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

 

注意关于斜堆的"前序遍历"、"中序遍历"、"后序遍历"、"打印"、"销毁"等接口就不再单独介绍了。后文的源码中有给出它们的实现代码,Please RTFSC(Read The Fucking Source Code)!

 

斜堆的C++实现(完整源码)

斜堆的实现文件(SkewHeap.h)

  1 /**
  2  * C++: 斜堆
  3  *
  4  * @author skywang
  5  * @date 2014/03/31
  6  */
  7 
  8 #ifndef _SKEW_HEAP_HPP_
  9 #define _SKEW_HEAP_HPP_
 10 
 11 #include <iomanip>
 12 #include <iostream>
 13 using namespace std;
 14 
 15 template <class T>
 16 class SkewNode{
 17     public:
 18         T key;                // 关键字(键值)
 19         SkewNode *left;        // 左孩子
 20         SkewNode *right;    // 右孩子
 21 
 22         SkewNode(T value, SkewNode *l, SkewNode *r):
 23             key(value), left(l),right(r) {}
 24 };
 25 
 26 template <class T>
 27 class SkewHeap {
 28     private:
 29         SkewNode<T> *mRoot;    // 根结点
 30 
 31     public:
 32         SkewHeap();
 33         ~SkewHeap();
 34 
 35         // 前序遍历"斜堆"
 36         void preOrder();
 37         // 中序遍历"斜堆"
 38         void inOrder();
 39         // 后序遍历"斜堆"
 40         void postOrder();
 41 
 42          // 将other的斜堆合并到this中。
 43         void merge(SkewHeap<T>* other);
 44         // 将结点(key为节点键值)插入到斜堆中
 45         void insert(T key);
 46         // 删除结点(key为节点键值)
 47         void remove();
 48 
 49         // 销毁斜堆
 50         void destroy();
 51 
 52         // 打印斜堆
 53         void print();
 54     private:
 55 
 56         // 前序遍历"斜堆"
 57         void preOrder(SkewNode<T>* heap) const;
 58         // 中序遍历"斜堆"
 59         void inOrder(SkewNode<T>* heap) const;
 60         // 后序遍历"斜堆"
 61         void postOrder(SkewNode<T>* heap) const;
 62 
 63         // 交换节点x和节点y
 64         void swapNode(SkewNode<T> *&x, SkewNode<T> *&y);
 65         // 合并"斜堆x"和"斜堆y"
 66         SkewNode<T>* merge(SkewNode<T>* &x, SkewNode<T>* &y);
 67 
 68         // 销毁斜堆
 69         void destroy(SkewNode<T>* &heap);
 70 
 71         // 打印斜堆
 72         void print(SkewNode<T>* heap, T key, int direction);
 73 };
 74 
 75 /* 
 76  * 构造函数
 77  */
 78 template <class T>
 79 SkewHeap<T>::SkewHeap():mRoot(NULL)
 80 {
 81 }
 82 
 83 /* 
 84  * 析构函数
 85  */
 86 template <class T>
 87 SkewHeap<T>::~SkewHeap() 
 88 {
 89     destroy(mRoot);
 90 }
 91 
 92 /*
 93  * 前序遍历"斜堆"
 94  */
 95 template <class T>
 96 void SkewHeap<T>::preOrder(SkewNode<T>* heap) const
 97 {
 98     if(heap != NULL)
 99     {
100         cout<< heap->key << " " ;
101         preOrder(heap->left);
102         preOrder(heap->right);
103     }
104 }
105 
106 template <class T>
107 void SkewHeap<T>::preOrder() 
108 {
109     preOrder(mRoot);
110 }
111 
112 /*
113  * 中序遍历"斜堆"
114  */
115 template <class T>
116 void SkewHeap<T>::inOrder(SkewNode<T>* heap) const
117 {
118     if(heap != NULL)
119     {
120         inOrder(heap->left);
121         cout<< heap->key << " " ;
122         inOrder(heap->right);
123     }
124 }
125 
126 template <class T>
127 void SkewHeap<T>::inOrder() 
128 {
129     inOrder(mRoot);
130 }
131 
132 /*
133  * 后序遍历"斜堆"
134  */
135 template <class T>
136 void SkewHeap<T>::postOrder(SkewNode<T>* heap) const
137 {
138     if(heap != NULL)
139     {
140         postOrder(heap->left);
141         postOrder(heap->right);
142         cout<< heap->key << " " ;
143     }
144 }
145 
146 template <class T>
147 void SkewHeap<T>::postOrder() 
148 {
149     postOrder(mRoot);
150 }
151 
152 /*
153  * 交换两个节点的内容
154  */
155 template <class T>
156 void SkewHeap<T>::swapNode(SkewNode<T> *&x, SkewNode<T> *&y)
157 {
158     SkewNode<T> *tmp = x;
159     x = y;
160     y = tmp;
161 }
162 
163 
164 /*
165  * 合并"斜堆x"和"斜堆y"
166  */
167 template <class T>
168 SkewNode<T>* SkewHeap<T>::merge(SkewNode<T>* &x, SkewNode<T>* &y)
169 {
170     if(x == NULL)
171         return y;
172     if(y == NULL)
173         return x;
174 
175     // 合并x和y时,将x作为合并后的树的根;
176     // 这里的操作是保证: x的key < y的key
177     if(x->key > y->key)
178         swapNode(x, y);
179 
180     // 将x的右孩子和y合并,
181     // 合并后直接交换x的左右孩子,而不需要像左倾堆一样考虑它们的npl。
182     SkewNode<T> *tmp = merge(x->right, y);
183     x->right = x->left;
184     x->left  = tmp;
185 
186     return x;
187 }
188 
189 /*
190  * 将other的斜堆合并到this中。
191  */
192 template <class T>
193 void SkewHeap<T>::merge(SkewHeap<T>* other)
194 {
195     mRoot = merge(mRoot, other->mRoot);
196 }
197 
198 /* 
199  * 新建键值为key的结点并将其插入到斜堆中
200  *
201  * 参数说明:
202  *     heap 斜堆的根结点
203  *     key 插入的结点的键值
204  * 返回值:
205  *     根节点
206  */
207 template <class T>
208 void SkewHeap<T>::insert(T key)
209 {
210     SkewNode<T> *node;    // 新建结点
211 
212     // 新建节点
213     node = new SkewNode<T>(key, NULL, NULL);
214     if (node==NULL)
215     {
216         cout << "ERROR: create node failed!" << endl;
217         return ;
218     }
219 
220     mRoot = merge(mRoot, node);
221 }
222 
223 /* 
224  * 删除结点
225  */
226 template <class T>
227 void SkewHeap<T>::remove()
228 {
229     if (mRoot == NULL)
230         return NULL;
231 
232     SkewNode<T> *l = mRoot->left;
233     SkewNode<T> *r = mRoot->right;
234 
235     // 删除根节点
236     delete mRoot;
237     // 左右子树合并后的新树
238     mRoot = merge(l, r); 
239 }
240 
241 /* 
242  * 销毁斜堆
243  */
244 template <class T>
245 void SkewHeap<T>::destroy(SkewNode<T>* &heap)
246 {
247     if (heap==NULL)
248         return ;
249 
250     if (heap->left != NULL)
251         destroy(heap->left);
252     if (heap->right != NULL)
253         destroy(heap->right);
254 
255     delete heap;
256 }
257 
258 template <class T>
259 void SkewHeap<T>::destroy()
260 {
261     destroy(mRoot);
262 }
263 
264 /*
265  * 打印"斜堆"
266  *
267  * key        -- 节点的键值 
268  * direction  --  0,表示该节点是根节点;
269  *               -1,表示该节点是它的父结点的左孩子;
270  *                1,表示该节点是它的父结点的右孩子。
271  */
272 template <class T>
273 void SkewHeap<T>::print(SkewNode<T>* heap, T key, int direction)
274 {
275     if(heap != NULL)
276     {
277         if(direction==0)    // heap是根节点
278             cout << setw(2) << heap->key << " is root" << endl;
279         else                // heap是分支节点
280             cout << setw(2) << heap->key << " is " << setw(2) << key << "'s "  << setw(12) << (direction==1?"right child" : "left child") << endl;
281 
282         print(heap->left, heap->key, -1);
283         print(heap->right,heap->key,  1);
284     }
285 }
286 
287 template <class T>
288 void SkewHeap<T>::print()
289 {
290     if (mRoot != NULL)
291         print(mRoot, mRoot->key, 0);
292 }
293 #endif
View Code

相关文章:

  • 2021-08-29
  • 2021-05-23
  • 2022-12-23
  • 2021-09-07
  • 2021-09-08
猜你喜欢
  • 2021-10-24
  • 2021-12-15
  • 2021-10-04
  • 2021-11-12
  • 2021-04-13
相关资源
相似解决方案