1. 使用插入节点构造二项堆的代码如下:
#include <iostream> #include <iomanip> using namespace std; const int MAXVALUE = 10000; // 二项树节点类 class BinoTreeNode { public: BinoTreeNode(int _key = 0, int _degree = 0) : key(_key), degree(_degree), p(NULL), child(NULL), sibling(NULL) { } int key; int degree; BinoTreeNode *p; BinoTreeNode *child; // 对于根节点和非根节点来说,sibling的含义是不同的。 // 如果x为根,则sibling[x]指向根表中的下个根(如果x为根表中的最后一个根,则sibling[x]=NULL) BinoTreeNode *sibling; }; /* * 按照如下格式打印节点数据 * ---p--- * --key-- * --deg-- * chi|sib */ ostream& operator <<(ostream& os, BinoTreeNode *q){ if(q){ // print parent pointer os << "---"; if (q->p){ os << q->p->key ; }else { os << " "; } os << "---" << endl; os << "---" << q->key << "---" << endl; os << "---" << q->degree << "---" << endl; os << "-" ; if (q->child) { os << q->child->key; }else{ os << " "; } os << "-|-"; if (q->sibling){ os << q->sibling->key; }else{ os << " "; } os << "-" << endl; }else { os << "this tree node is nil" << endl; } return os; } // 二项树类 class BinoTree { public: // y and z are B(k-1) tree // construct an B(k), and let z to be the parent of y static void link(BinoTreeNode* y, BinoTreeNode* z) { y->sibling = z->child; y->p = z; z->child = y; z->degree += 1; } static void travers(BinoTreeNode* p){ if(!p){ return; } cout << p << endl; BinoTreeNode* child = p->child; while(p->sibling){ p = p->sibling; travers(p); } travers(child); } }; // 二项堆类 class BinoHeap { public: // 含有n个节点的二项堆,其构成的二项树为Bi,当且仅当 bi=1 BinoHeap() : head(NULL) { } // 寻找最小关键字的节点 BinoTreeNode* minimum(){ return minimum(head); } void insert(BinoTreeNode* x) { BinoHeap *_H = new BinoHeap; _H->setHead(x); unionHeap(_H); } void unionHeap(BinoHeap* that) { //cout << "before union, head is " << (head ? head->key:(-1)) << endl; head = unionHeap(head, that->head); //cout << "after union, head is " << (head ? head->key:(-1)) << endl; } void merge(BinoHeap* that) { head = merge(head, that->head); } void travers() { travers(head); } void setHead(BinoTreeNode* _head) { head = _head; } BinoTreeNode* getHead() { return head; } BinoTreeNode* extractMin() { return extractMin(head); } private: BinoTreeNode *head; BinoTreeNode* unionHeap(BinoTreeNode* h1, BinoTreeNode* h2); BinoTreeNode* merge(BinoTreeNode* h1, BinoTreeNode* h2); BinoTreeNode* minimum(BinoTreeNode* h); BinoTreeNode* extractMin(BinoTreeNode* &h); void travers(BinoTreeNode *p); }; // travers the heap via void BinoHeap::travers(BinoTreeNode *p) { while (p) { BinoTree::travers(p); p = p->sibling; } } BinoTreeNode* BinoHeap::minimum(BinoTreeNode* h) { BinoTreeNode* y= NULL; BinoTreeNode* x = h; int min = MAXVALUE; while (x) { if (x->key < min) { min = x->key; y = x; } x = x->sibling; } return y; } // merge h1 and h2 according to the degree of roots. BinoTreeNode* BinoHeap::merge(BinoTreeNode* h1, BinoTreeNode* h2) { if (!h1) { return h2; } if (!h2) { return h1; } BinoTreeNode *p = (h1->degree < h2->degree) ? h1 : h2; BinoTreeNode *p1 = h1, *p2 = h2, *q1= NULL, *q2= NULL; while (p1 && p2) { while (p1 && p2 && (p1->degree < p2->degree)) { q1 = p1; p1 = p1->sibling; } // insert p2 to p1; if (q1) { q1->sibling = p2; if (!p1) { break; } } while (p1 && p2 && (p2->degree <= p1->degree)) { q2 = p2; p2 = p2->sibling; } if (q2) { q2->sibling = p1; if (!p2) { break; } } } // // print the merged list // BinoTreeNode *xx = p; // // while (xx){ // cout << xx->key << "->"; // xx = xx->sibling; // } return p; } BinoTreeNode* BinoHeap::unionHeap(BinoTreeNode* h1, BinoTreeNode* h2) { BinoTreeNode* h = NULL; h = merge(h1, h2); if (h == NULL) { return h; } BinoTreeNode *prevx= NULL; BinoTreeNode *x = h; BinoTreeNode *nextx = x->sibling; while (nextx) { if ((x->degree != nextx->degree) ||(nextx->sibling && nextx->sibling->degree == x->degree)) { prevx = x; x = nextx; } else if (x->key <= nextx->key) { x->sibling = nextx->sibling; BinoTree::link(nextx, x); } else { if (!prevx) { h = nextx; } else { prevx->sibling = nextx; } BinoTree::link(x, nextx); x = nextx; } nextx = x->sibling; } return h; } /* * Binomial headp extract min */ BinoTreeNode* BinoHeap::extractMin(BinoTreeNode* &h){ // step 1. // find the node with the min key BinoTreeNode* min = minimum(h); if(!min){ return NULL; } // remove the node from the root list BinoTreeNode* pre = NULL, *x = h; while(x && x != min){ pre = x; x = x->sibling; } if (pre == NULL){ // the first node is the min one h = min->sibling; }else{ pre->sibling = min->sibling; } // step 2. BinoHeap* _H = new BinoHeap; BinoTreeNode* _h = min->child; BinoTreeNode* _q = NULL; BinoTreeNode* _x = _h->sibling; _h->p = NULL; _h->sibling = NULL; while(_x){ _x->p = NULL; // insert at the front of the list _q = _x->sibling; _x->sibling = _h; _h = _x; _x = _q; } _H->setHead(_h); unionHeap(_H); return min; } int main() { BinoHeap bt1, bt2; int a[] = { 1, 7, 5, 0 }; int b[] = { 9, 8, 3, 4, 2}; for (int i = 0; i < sizeof(a)/sizeof(int); i++) { bt1.insert(new BinoTreeNode(a[i])); } for (int i = 0; i < sizeof(b)/sizeof(int); i++) { bt2.insert(new BinoTreeNode(b[i])); } cout << "traverse binomial tree" << endl; bt1.travers(); bt1.unionHeap(&bt2); cout << "traverse binomial tree after merging" << endl; bt1.travers(); // BinoTreeNode *p = bt1.minimum(); // cout << "the minimum value is " << p->key << endl; BinoTreeNode *p = bt1.extractMin(); cout << "extract minimum value " << p->key << endl; bt1.travers(); return 0; }
2. 程序运行结果如下:
traverse binomial tree
--- ---
---0---
---2---
-1-|- -
---0---
---1---
---1---
-7-|-5-
---0---
---5---
---0---
- -|- -
---1---
---7---
---0---
- -|- -
traverse binomial tree after merging
--- ---
---2---
---0---
- -|-0-
--- ---
---0---
---3---
-3-|- -
---0---
---3---
---2---
-8-|-1-
---0---
---1---
---1---
-7-|-5-
---0---
---5---
---0---
- -|- -
---1---
---7---
---0---
- -|- -
---0---
---5---
---0---
- -|- -
---3---
---8---
---1---
-9-|-4-
---3---
---4---
---0---
- -|- -
---8---
---9---
---0---
- -|- -
--- ---
---0---
---3---
-3-|- -
---0---
---3---
---2---
-8-|-1-
---0---
---1---
---1---
-7-|-5-
---0---
---5---
---0---
- -|- -
---1---
---7---
---0---
- -|- -
---0---
---5---
---0---
- -|- -
---3---
---8---
---1---
-9-|-4-
---3---
---4---
---0---
- -|- -
---8---
---9---
---0---
- -|- -
extract minimum value 0
--- ---
---1---
---3---
-3-|- -
---1---
---3---
---2---
-8-|-2-
---1---
---2---
---1---
-5-|-7-
---1---
---7---
---0---
- -|- -
---2---
---5---
---0---
- -|- -
---1---
---7---
---0---
- -|- -
---3---
---8---
---1---
-9-|-4-
---3---
---4---
---0---
- -|- -
---8---
---9---
---0---
- -|- -
3. 测试结果二项堆的图示:
2 --- 0 / | / 3 1 5 / / | 8 4 7 | 9 // after extracting min value 0 1 / | / 3 2 7 / / | 8 4 5 | 9
说明:一共9个测试数据,对应的二进制数据为1001,从上图可以看出,恰为B3和B0两个二项树。抽取最小值0后,得到的二项堆有8个数据,为B3。