程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 斐波那契堆(二)之 C++的實現

斐波那契堆(二)之 C++的實現

編輯:C++入門知識

斐波那契堆的介紹 斐波那契堆(Fibonacci heap)是一種可合並堆,可用於實現合並優先隊列。它比二項堆具有更好的平攤分析性能,它的合並操作的時間復雜度是O(1)。 與二項堆一樣,它也是由一組堆最小有序樹組成,並且是一種可合並堆。 與二項堆不同的是,斐波那契堆中的樹不一定是二項樹;而且二項堆中的樹是有序排列的,但是斐波那契堆中的樹都是有根而無序的。           斐波那契堆的基本操作 1. 基本定義   復制代碼 template <class T> class FibNode {     public:         T key;                // 關鍵字(鍵值)         int degree;            // 度數         FibNode<T> *left;    // 左兄弟         FibNode<T> *right;    // 右兄弟         FibNode<T> *child;    // 第一個孩子節點         FibNode<T> *parent;    // 父節點         bool marked;        // 是否被刪除第一個孩子           FibNode(T value):key(value), degree(0), marked(false),              left(NULL),right(NULL),child(NULL),parent(NULL) {             key    = value;             degree = 0;             marked = false;             left   = this;             right  = this;             parent = NULL;             child  = NULL;         } }; 復制代碼 FibNode是斐波那契堆的節點類,它包含的信息較多。key是用於比較節點大小的,degree是記錄節點的度,left和right分別是指向節點的左右兄弟,child是節點的第一個孩子,parent是節點的父節點,marked是記錄該節點是否被刪除第1個孩子(marked在刪除節點時有用)。   復制代碼 template <class T> class FibHeap {     private:         int keyNum;         // 堆中節點的總數         int maxDegree;      // 最大度         FibNode<T> *min;    // 最小節點(某個最小堆的根節點)         FibNode<T> **cons;    // 最大度的內存區域       public:         FibHeap();         ~FibHeap();           // 新建key對應的節點,並將其插入到斐波那契堆中         void insert(T key);         // 移除斐波那契堆中的最小節點         void removeMin();         // 將other合並到當前堆中         void combine(FibHeap<T> *other);         // 獲取斐波那契堆中最小鍵值,並保存到pkey中;成功返回true,否則返回false。         bool minimum(T *pkey);         // 將斐波那契堆中鍵值oldkey更新為newkey         void update(T oldkey, T newkey);         // 刪除鍵值為key的節點         void remove(T key);         // 斐波那契堆中是否包含鍵值key         bool contains(T key);         // 打印斐波那契堆         void print();         // 銷毀         void destroy();       private:         // 將node從雙鏈表移除         void removeNode(FibNode<T> *node);         // 將node堆結點加入root結點之前(循環鏈表中)         void addNode(FibNode<T> *node, FibNode<T> *root);         // 將雙向鏈表b鏈接到雙向鏈表a的後面         void catList(FibNode<T> *a, FibNode<T> *b);         // 將節點node插入到斐波那契堆中         void insert(FibNode<T> *node);         // 將"堆的最小結點"從根鏈表中移除,         FibNode<T>* extractMin();         // 將node鏈接到root根結點         void link(FibNode<T>* node, FibNode<T>* root);         // 創建consolidate所需空間         void makeCons();         // 合並斐波那契堆的根鏈表中左右相同度數的樹         void consolidate();         // 修改度數         void renewDegree(FibNode<T> *parent, int degree);         // 將node從父節點parent的子鏈接中剝離出來,並使node成為"堆的根鏈表"中的一員。         void cut(FibNode<T> *node, FibNode<T> *parent);         // 對節點node進行"級聯剪切"         void cascadingCut(FibNode<T> *node) ;         // 將斐波那契堆中節點node的值減少為key         void decrease(FibNode<T> *node, T key);         // 將斐波那契堆中節點node的值增加為key         void increase(FibNode<T> *node, T key);         // 更新斐波那契堆的節點node的鍵值為key         void update(FibNode<T> *node, T key);         // 在最小堆root中查找鍵值為key的節點         FibNode<T>* search(FibNode<T> *root, T key);         // 在斐波那契堆中查找鍵值為key的節點         FibNode<T>* search(T key);         // 刪除結點node         void remove(FibNode<T> *node);         // 銷毀斐波那契堆         void destroyNode(FibNode<T> *node);         // 打印"斐波那契堆"         void print(FibNode<T> *node, FibNode<T> *prev, int direction); }; 復制代碼 FibHeap是斐波那契堆對應的類。min是保存當前堆的最小節點,keyNum用於記錄堆中節點的總數,maxDegree用於記錄堆中最大度,而cons在刪除節點時來暫時保存堆數據的臨時空間。下面是斐波那契堆的屬性結構圖和內存結構圖的對比示例。       從中可以看出,斐波那契堆是由一組最小堆組成,這些最小堆的根節點組成了雙向鏈表(後文稱為"根鏈表");斐波那契堆中的最小節點就是"根鏈表中的最小節點"!   PS. 上面這幅圖的結構和測試代碼中的"基本信息"測試函數的結果是一致的;你可以通過測試程序來親自驗證!       2. 插入操作   插入操作非常簡單:插入一個節點到堆中,直接將該節點插入到"根鏈表的min節點"之前即可;若被插入節點比"min節點"小,則更新"min節點"為被插入節點。       上面是插入操作的示意圖。   斐波那契堆的根鏈表是"雙向鏈表",這裡將min節點看作雙向聯表的表頭(後文也是如此)。在插入節點時,每次都是"將節點插入到min節點之前(即插入到雙鏈表末尾)"。此外,對於根鏈表中最小堆都只有一個節點的情況,插入操作就很演化成雙向鏈表的插入操作。   此外,插入操作示意圖與測試程序中的"插入操作"相對應,感興趣的可以親自驗證。       插入操作代碼   復制代碼 /*  * 將node堆結點加入root結點之前(循環鏈表中)  *   a …… root  *   a …… node …… root */ template <class T> void FibHeap<T>::addNode(FibNode<T> *node, FibNode<T> *root) {     node->left        = root->left;     root->left->right = node;     node->right       = root;     root->left        = node; }   /*  * 將節點node插入到斐波那契堆中  */ template <class T> void FibHeap<T>::insert(FibNode<T> *node) {     if (keyNum == 0)         min = node;     else        {         addNode(node, min);         if (node->key < min->key)             min = node;     }     keyNum++; } 復制代碼     3. 合並操作   合並操作和插入操作的原理非常類似:將一個堆的根鏈表插入到另一個堆的根鏈表上即可。簡單來說,就是將兩個雙鏈表拼接成一個雙向鏈表。       上面是合並操作的示意圖。該操作示意圖與測試程序中的"合並操作"相對應!       合並操作代碼   復制代碼 /*  * 將雙向鏈表b鏈接到雙向鏈表a的後面  *  * 注意: 此處a和b都是雙向鏈表  */ template <class T> void FibHeap<T>::catList(FibNode<T> *a, FibNode<T> *b) {     FibNode<T> *tmp;       tmp            = a->right;     a->right       = b->right;     b->right->left = a;     b->right       = tmp;     tmp->left      = b; }      /*  * 將other合並到當前堆中  */ template <class T> void FibHeap<T>::combine(FibHeap<T> *other) {     if (other==NULL)         return ;       if(other->maxDegree > this->maxDegree)         swap(*this, *other);       if((this->min) == NULL)                // this無"最小節點"     {         this->min = other->min;         this->keyNum = other->keyNum;         free(other->cons);         delete other;     }     else if((other->min) == NULL)           // this有"最小節點" && other無"最小節點"     {         free(other->cons);         delete other;     }                                       // this有"最小節點" && other有"最小節點"     else     {         // 將"other中根鏈表"添加到"this"中         catList(this->min, other->min);           if (this->min->key > other->min->key)             this->min = other->min;         this->keyNum += other->keyNum;         free(other->cons);         delete other;     } }

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved