zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    二分法模板
    二分答案模板
    51nod 1010 只包含因子2 3 5的数
    三次握手和四次挥手(面试必问)
    TCP协议和UDP协议
    纯CSS3画出小黄人并实现动画效果
    正则表达式里字符串”不包含”匹配技巧
    12个C语言面试题,涉及指针、进程、运算、结构体、函数、内存,看看你能做出几个!
    使用jTopo给Html5 Canva中绘制的元素添加鼠标事件_html5教程技巧
    程序猿们,快用Emoji表情写代码吧
  • 原文地址:https://www.cnblogs.com/yxsrt/p/12249679.html
Copyright © 2011-2022 走看看