fibonacci-Heap(斐波那契堆)原理及C++代码实现

斐波那契堆是一种高级的堆结构,建议与二项堆一起食用效果更佳。

斐波那契堆是一个摊还性质的数据结构,很多堆操作在斐波那契堆上的摊还时间都很低,达到了θ(1)的程度,取最小值和删除操作的时间复杂度是O(lgn)。

斐波那契堆的关键操作我觉得是合并树和级联剪切。下面我简要地说一些关于这两个方法的体会。

斐波那契堆深度的增加应该就是通过合并树(consolidate)这个操作,如果没有剪切的影响,那么consolidate后的堆非常类似与二项堆。

级联剪切操作则是减小堆深度的操作,我在学习的时候一直有个问题,就是为什么级联剪切一定要失去第二个子结点时才开始剪切?为什么恰恰是二,而不是第三个或其他数?后来我看到一个大佬的博客写的是,这样可以尽量保证斐波那契堆可以类似于二项堆,防止“越剪越乱”。这个解释也是目前我最接受的。

所以可以看到的是斐波那契堆其实可以看做一个宽松的二项堆。

代码如下:(仅供参考)

  1 class FibHeap {
  2 private :
  3     struct Node {
  4         Node * parent;
  5         Node * child;
  6         Node * left;
  7         Node * right;
  8         int key;
  9         int degree; //degree of children
 10         bool mark; //whether lose any child
 11         Node() : parent(nullptr), child(nullptr), left(this), right(this),
 12                  key(0), degree(0), mark(false) {}
 13     };
 14 private :
 15     Node * min; //pointer to the minimum node of heap
 16     int n;
 17 private :
 18     void listAdd(Node * &r, Node * p);//add p to r
 19     void listdelete(Node * p);
 20     void listUnion(Node * x, Node * y);//add x and y
 21     int Dn() {return (log2(n) + 1);} //当所有根都合并到一棵树上时,dn最大,为log2(n), 参考二项树
 22     void consolidate();
 23     void heapLink(Node * y, Node * x);
 24     void cut(Node * x, Node * y);
 25     void cascadingCut(Node * y);
 26     Node * search(Node * r, int k);//search is not good in heap
 27 public :
 28     FibHeap() : min(nullptr), n(0) {}
 29     void insert(int k);
 30     int extractMin(); //get minimum node and delete it
 31     int minimum() {return min->key;}
 32     void decreaseKey(Node * x, int k);
 33     void remove(int k);
 34     void heapUnion(FibHeap &b);
 35     bool search(int k) {return (search(min, k) == nullptr ? false : true);}
 36     bool empty() {return n == 0;}
 37 };
 38 
 39 void FibHeap::listAdd(Node * &r, Node * p) {
 40     if (r == nullptr) {
 41         r = p;
 42         r->left = r;
 43         r->right = r;
 44     }
 45     else {
 46         Node * x = r; //去引用
 47         p->right = x->right;
 48         p->left = x;
 49         x->right->left = p;
 50         x->right = p;
 51     }
 52 }
 53 
 54 void FibHeap::listdelete(Node * p) {
 55     p->left->right = p->right;
 56     p->right->left = p->left;
 57 }
 58 
 59 void FibHeap::listUnion(Node * x, Node * y) {
 60     if (x == nullptr)
 61         x = y;
 62     else {
 63         Node * tail = x->left;
 64         x->left->right = y;
 65         y->left->right = x;
 66         x->left = y->left;
 67         y->left = tail;
 68     }
 69 }
 70 
 71 void FibHeap::insert(int k) {
 72     Node * p = new Node;
 73     p->key = k;
 74     listAdd(min, p);
 75     if (min->key > k) {
 76         min = p;
 77     }
 78     ++n;
 79 }
 80 
 81 void FibHeap::heapLink(Node * y, Node * x) {
 82     listdelete(y);
 83     listAdd(x->child, y);
 84     ++x->degree;
 85     y->mark = false;
 86 }
 87 
 88 void FibHeap::consolidate() {
 89     vector<Node*> a(Dn(), nullptr);
 90     Node *x, *y, *z;
 91     int d;
 92     Node * sentry = new Node;
 93     listAdd(min->left, sentry); //add a sentry
 94     for (x = min; x != sentry; x = z) {
 95         z = x->right; //防止x被link到y上,导致x-right无法指向正确的位置,所以先保存
 96         d = x->degree;
 97         while (a[d] != nullptr) {
 98             y = a[d];
 99             if (x->key > y->key)
100                 swap(x, y);
101             heapLink(y, x);
102             a[d] = nullptr;
103             ++d;
104         }
105         a[d] = x;
106     }
107     min = nullptr;
108     for (int i = 0; i < a.size(); ++i) {
109         if (a[i] != nullptr) {
110             listAdd(min, a[i]);
111             if (a[i]->key < min->key)
112                 min = a[i];
113         }
114     }
115     delete sentry;
116 }
117 
118 int FibHeap::extractMin() {
119     int ret = 0;
120     Node * p = min;
121     if (p) {
122         ret = p->key;
123         if (p->child) {
124             Node * x = p->child;
125             Node * y = x->right;
126             for (int i = 0; i < p->degree; ++i) {
127                 listAdd(min, x);
128                 x->parent = nullptr;
129                 x = y;
130                 y = y->right;
131             }
132         }
133         if (p->right == p) //the child of p is empty, and p is the only one in root list
134             min = nullptr;
135         else {
136             min = p->right;
137             listdelete(p);
138             consolidate();
139         }
140         delete p;
141         --n;
142     }
143     return ret;
144 }
145 
146 void FibHeap::cut(Node * x, Node * y) {
147     listdelete(x);
148     --y->degree;
149     listAdd(min, x);
150     x->parent = nullptr;
151     x->mark = false;
152 }
153 
154 void FibHeap::cascadingCut(Node * y) {
155     Node * z = y->parent;
156     if (z) {
157         if (y->mark == false)
158             y->mark = true;
159         else {
160             cut(y, z);
161             cascadingCut(z);
162         }
163     }
164 }
165 
166 void FibHeap::decreaseKey(Node * x, int k) {
167     if (k >= x->key)
168         return ;
169     x->key = k;
170     Node * y = x->parent;
171     if (y && y->key > x->key) {
172         cut(x, y);
173         cascadingCut(y);
174     }
175     if (x->key < min->key)
176         min = x;
177 }
178 
179 void FibHeap::remove(int k) {
180     Node * p = search(min, k);
181     if (p == nullptr)
182         return ;
183     decreaseKey(p, INT_MIN);
184     extractMin();
185 }
186 
187 void FibHeap::heapUnion(FibHeap &b) { //can't use b any more
188     if (b.min == nullptr)
189         return ;
190     listUnion(min, b.min);
191     if (min->key > b.min->key)
192         min = b.min;
193     n += b.n;
194 }
195 
196 FibHeap::Node * FibHeap::search(Node * r, int k) {
197     if (r == nullptr)
198         return r;
199     Node * x = r, *y;
200     do {
201         if (x->key == k)
202             return x;
203         else if (x->key < k) {
204             y = search(x->child, k);
205             if (y)
206                 return y;
207         }
208         x = x->right;
209     } while (x != r);
210 
211     return nullptr;
212 }

 

posted @ 2020-02-01 19:26  简讯  阅读(1051)  评论(0编辑  收藏  举报