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

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

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

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

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

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

代码如下:(仅供参考)

 class FibHeap {
private :
struct Node {
Node * parent;
Node * child;
Node * left;
Node * right;
int key;
int degree; //degree of children
bool mark; //whether lose any child
Node() : parent(nullptr), child(nullptr), left(this), right(this),
key(), degree(), mark(false) {}
};
private :
Node * min; //pointer to the minimum node of heap
int n;
private :
void listAdd(Node * &r, Node * p);//add p to r
void listdelete(Node * p);
void listUnion(Node * x, Node * y);//add x and y
int Dn() {return (log2(n) + );} //当所有根都合并到一棵树上时,dn最大,为log2(n), 参考二项树
void consolidate();
void heapLink(Node * y, Node * x);
void cut(Node * x, Node * y);
void cascadingCut(Node * y);
Node * search(Node * r, int k);//search is not good in heap
public :
FibHeap() : min(nullptr), n() {}
void insert(int k);
int extractMin(); //get minimum node and delete it
int minimum() {return min->key;}
void decreaseKey(Node * x, int k);
void remove(int k);
void heapUnion(FibHeap &b);
bool search(int k) {return (search(min, k) == nullptr ? false : true);}
bool empty() {return n == ;}
}; void FibHeap::listAdd(Node * &r, Node * p) {
if (r == nullptr) {
r = p;
r->left = r;
r->right = r;
}
else {
Node * x = r; //去引用
p->right = x->right;
p->left = x;
x->right->left = p;
x->right = p;
}
} void FibHeap::listdelete(Node * p) {
p->left->right = p->right;
p->right->left = p->left;
} void FibHeap::listUnion(Node * x, Node * y) {
if (x == nullptr)
x = y;
else {
Node * tail = x->left;
x->left->right = y;
y->left->right = x;
x->left = y->left;
y->left = tail;
}
} void FibHeap::insert(int k) {
Node * p = new Node;
p->key = k;
listAdd(min, p);
if (min->key > k) {
min = p;
}
++n;
} void FibHeap::heapLink(Node * y, Node * x) {
listdelete(y);
listAdd(x->child, y);
++x->degree;
y->mark = false;
} void FibHeap::consolidate() {
vector<Node*> a(Dn(), nullptr);
Node *x, *y, *z;
int d;
Node * sentry = new Node;
listAdd(min->left, sentry); //add a sentry
for (x = min; x != sentry; x = z) {
z = x->right; //防止x被link到y上,导致x-right无法指向正确的位置,所以先保存
d = x->degree;
while (a[d] != nullptr) {
y = a[d];
if (x->key > y->key)
swap(x, y);
heapLink(y, x);
a[d] = nullptr;
++d;
}
a[d] = x;
}
min = nullptr;
for (int i = ; i < a.size(); ++i) {
if (a[i] != nullptr) {
listAdd(min, a[i]);
if (a[i]->key < min->key)
min = a[i];
}
}
delete sentry;
} int FibHeap::extractMin() {
int ret = ;
Node * p = min;
if (p) {
ret = p->key;
if (p->child) {
Node * x = p->child;
Node * y = x->right;
for (int i = ; i < p->degree; ++i) {
listAdd(min, x);
x->parent = nullptr;
x = y;
y = y->right;
}
}
if (p->right == p) //the child of p is empty, and p is the only one in root list
min = nullptr;
else {
min = p->right;
listdelete(p);
consolidate();
}
delete p;
--n;
}
return ret;
} void FibHeap::cut(Node * x, Node * y) {
listdelete(x);
--y->degree;
listAdd(min, x);
x->parent = nullptr;
x->mark = false;
} void FibHeap::cascadingCut(Node * y) {
Node * z = y->parent;
if (z) {
if (y->mark == false)
y->mark = true;
else {
cut(y, z);
cascadingCut(z);
}
}
} void FibHeap::decreaseKey(Node * x, int k) {
if (k >= x->key)
return ;
x->key = k;
Node * y = x->parent;
if (y && y->key > x->key) {
cut(x, y);
cascadingCut(y);
}
if (x->key < min->key)
min = x;
} void FibHeap::remove(int k) {
Node * p = search(min, k);
if (p == nullptr)
return ;
decreaseKey(p, INT_MIN);
extractMin();
} void FibHeap::heapUnion(FibHeap &b) { //can't use b any more
if (b.min == nullptr)
return ;
listUnion(min, b.min);
if (min->key > b.min->key)
min = b.min;
n += b.n;
} FibHeap::Node * FibHeap::search(Node * r, int k) {
if (r == nullptr)
return r;
Node * x = r, *y;
do {
if (x->key == k)
return x;
else if (x->key < k) {
y = search(x->child, k);
if (y)
return y;
}
x = x->right;
} while (x != r); return nullptr;
}

fibonacci-Heap(斐波那契堆)原理及C++代码实现的更多相关文章

  1. 斐波那契堆(一)之 图文解析 和 C语言的实现

    概要 本章介绍斐波那契堆.和以往一样,本文会先对斐波那契堆的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现:实现的语言虽不同,但是原理如出一辙,选择其中之一进行了 ...

  2. 斐波那契堆(二)之 C++的实现

    概要 上一章介绍了斐波那契堆的基本概念,并通过C语言实现了斐波那契堆.本章是斐波那契堆的C++实现. 目录1. 斐波那契堆的介绍2. 斐波那契堆的基本操作3. 斐波那契堆的C++实现(完整源码)4.  ...

  3. 斐波那契堆(三)之 Java的实现

    概要 前面分别通过C和C++实现了斐波那契堆,本章给出斐波那契堆的Java版本.还是那句老话,三种实现的原理一样,择其一了解即可. 目录1. 斐波那契堆的介绍2. 斐波那契堆的基本操作3. 斐波那契堆 ...

  4. 斐波那契堆(Fibonacci heap)原理详解(附java代码实现)

    前言 斐波那契堆(Fibonacci heap)是计算机科学中最小堆有序树的集合.它和二项式堆有类似的性质,但比二项式堆有更好的均摊时间.堆的名字来源于斐波那契数,它常用于分析运行时间. 堆结构介绍 ...

  5. 基于visual Studio2013解决算法导论之045斐波那契堆

     题目 斐波那契堆 解决代码及点评 // 斐波那契堆.cpp : 定义控制台应用程序的入口点. // #include<iostream> #include<cstdio> ...

  6. 笔试算法题(46):简介 - 二叉堆 & 二项树 & 二项堆 & 斐波那契堆

    二叉堆(Binary Heap) 二叉堆是完全二叉树(或者近似完全二叉树):其满足堆的特性:父节点的值>=(<=)任何一个子节点的键值,并且每个左子树或者右子树都是一 个二叉堆(最小堆或者 ...

  7. 10、end关键字和Fibonacci series: 斐波纳契数列

    # Fibonacci series: 斐波纳契数列 # 两个元素的总和确定了下一个数 a, b = 0, 1 #复合赋值表达式,a,b同时赋值0和1 while b < 10: print(b ...

  8. [LeetCode] Fibonacci Number 斐波那契数字

    The Fibonacci numbers, commonly denoted F(n) form a sequence, called the Fibonacci sequence, such th ...

  9. fibonacci数列-斐波那契数列-python编程

    未完待续~ 了解fibonacci数列: 斐波纳契数列(Fibonacci Sequence),又称黄金分割数列. 1,1,2,3,5,8,13,21,34,55,89,144,233,377,610 ...

随机推荐

  1. 201771010123汪慧和《面向对象程序设计Java》第十七周实验总结

    一.理论部分 1.多线程并发执行中的问题 ◆多个线程相对执行的顺序是不确定的. ◆线程执行顺序的不确定性会产生执行结果的不确定性. ◆在多线程对共享数据操作时常常会产生这种不确定性. 2.线程的同步 ...

  2. CKeditor上传图片 实现所见即所得界面

    迟了好多天的分享,CKeditor这个编辑器虽然不错,但也真苟啊,搞图片上传这个功能,快给我搞佛系了,话不多说,上代码 1.首先去官网下载一个full的版本,我用的是CKeditor 4.13,解压之 ...

  3. unzip 小坑

    unzip test.zip 直接将zip解压到当前目录下,保留test级目录. unzip test.war 直接将.war解压到当前目录,不保留test级目录,所以建议使用 unzip test. ...

  4. Python快速安装库的靠谱办法

    我们如果使用python,并且使用pip安装一些库 会经常遇到pip在线安装速度慢 !   慢也就算了,安装经常会由于timeout等原因中断 所以有没有什么在线安装库并且速度较快的办法么? 其实是有 ...

  5. 给普通用户加sudo权限

    系统环境:centos 7.0 引文:在实验室的服务器上给每个人分配了一个账号,但是有的时候普通用户需要使用root权限,比如装一些软件之类的.下面介绍怎么给普通用户添加sudo命令权限. 前提: s ...

  6. 指针数组的初始化和遍历,并且通过for循环方式、函数传参方式进行指针数组的遍历

    /************************************************************************* > File Name: message.c ...

  7. 正文内容 python3编码问题

    来源:http://www.jb51.net/article/92006.htm 以下是全文: 这两天写了个监测网页的爬虫,作用是跟踪一个网页的变化,但运行了一晚出现了一个问题....希望大家不吝赐教 ...

  8. css常见符号

    * 通配符使用星号*表示,意思是“所有的” 比如:* { color : red; } 这里就把所有元素的字体设置为红色 缺点: 不过,由于*会匹配所有的元素,这样会影响网页渲染的时间 解决: res ...

  9. Vue动画封装

    <head> <meta charset="UTF-8"> <title>Title</title> <script src= ...

  10. Thread--synchronized&volatile