1. 程式人生 > >11、【堆】斜堆

11、【堆】斜堆

print str template new oid 以及 roo cout 當前

一、斜堆的介紹

斜堆(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()的作用是刪除斜堆的最小節點。

11、【堆】斜堆