参考 斐波那契堆(二)之 C++的实现 和 斐波那契堆的C++实现,可参考视频 【B站首发】来学斐波那契堆吧♪(^∀^●)
势函数的作用:得到进行一次操作的代价和势函数的变化关系:costi=Δϕ+kcost_i=\Delta \phi +kcosti​=Δϕ+k,累加求 NNN 次 costicost_icosti​
合并两个双向循环链表 catList 操作如下图:

#include <iomanip>
#include <iostream>
#include <cstdlib>
#include <cmath>
using namespace std;template <class T>
class FibNode {public:T data;                // 存储的值int degree;            // 度数,即此节点的子节点数目FibNode<T> *left;       // 左兄弟FibNode<T> *right;      // 右兄弟FibNode<T> *child;      // 第一个孩子节点FibNode<T> *parent;    // 父节点bool marked;            //指示节点自从上一次成为另一个节点的孩子之后,是否失去过孩子FibNode(T d):data(d),marked(false),degree(0),child(nullptr),parent(nullptr),left(this),right(this){};
};template <class T>
class FibHeap {//斐波那契堆,高效可并堆,摊还时间界最优//主要包括一列堆序树集合,有多个子节点//第一层树的根串成了环形双向链表,称为斐波那契堆的根链表//对每棵树而言,每层子节点也串成双向循环链表,通过child指针和下一层双向循环链表沟通//斐波那契堆的一些操作要尽可能长地延后执行,不同的操作可以进行性能平衡private:int currentSize;         // 堆中节点的总数int maxDegree;          // 斐波那契堆中节点的最大孩子数目FibNode<T> *minRoot;    // 最小节点(某个最小堆的根节点)FibNode<T> **cons;    // 最大度的内存区域public:FibHeap():currentSize(0),maxDegree(0),minRoot(nullptr),cons(nullptr){};// 新建data对应的节点,并将其插入到斐波那契堆中void insert(T data){FibNode<T>* node = new FibNode<T>(data);if (!node) return ;insert(node);}// 将rhs合并到当前堆中void merge(FibHeap<T> *rhs){if (!rhs) return ;if(rhs->maxDegree > maxDegree) swap(*this, *rhs);if(!minRoot){                // this无"最小节点"minRoot = rhs->minRoot;currentSize = rhs->currentSize;}                                   // this有"最小节点" && rhs有"最小节点"else if(!rhs->minRoot){// 将"rhs中根链表"添加到"this"中catList(minRoot, rhs->minRoot);if (minRoot->data > rhs->minRoot->data)minRoot = rhs->minRoot;currentSize += rhs->currentSize;}free(rhs->cons);delete rhs;}// 移除斐波那契堆中的最小节点void removeMin(){if (!minRoot) return;FibNode<T> *child = nullptr;FibNode<T> *m = minRoot;// 将minRoot每一个儿子(儿子和儿子的兄弟)都添加到"斐波那契堆的根链表"中while (m->child){child = m->child;removeNode(child);if (child->right == child) m->child=nullptr;else m->child = child->right;insertToRootList(child, minRoot);child->parent = nullptr;}// 将m从根链表中移除removeNode(m);// 若m是堆中唯一节点,则设置堆的最小节点为nullptr;// 否则,设置堆的最小节点为一个非空节点(m->right),然后再进行调节。if (m->right == m) minRoot=nullptr;else{minRoot = m->right;consolidate();}currentSize--;delete m;}// 获取斐波那契堆中最小键值,并保存到pdata中;成功返回true,否则返回false。bool minRootimum(T *pdata);// 将斐波那契堆中键值olddata更新为newdatavoid update(T olddata, T newdata);// 删除键值为data的节点void remove(T data);// 斐波那契堆中是否包含键值databool contains(T data);// 打印斐波那契堆void print();// 销毁void destroy();private:// 将节点node插入到斐波那契堆中void insert(FibNode<T> *node){if (currentSize == 0) minRoot = node;else{insertToRootList(node, minRoot);if (node->data < minRoot->data) minRoot = node;}currentSize++;}// 将node从双向循环链表移除void removeNode(FibNode<T> *node){node->left->right = node->right;node->right->left = node->left;}// 将node堆结点加入root结点之前(循环链表中)void insertToRootList(FibNode<T> *node, FibNode<T> *root){node->left        = root->left;root->left->right = node;node->right       = root;root->left        = node;}// 将双向链表b链接到双向链表a的后面void catList(FibNode<T> *a, FibNode<T> *b){FibNode<T>* tmp= a->right;a->right       = b->right;b->right->left = a;b->right       = tmp;tmp->left      = b;}// 将"堆的最小结点"从根链表中移除,FibNode<T>* extractMin(){FibNode<T> *p = minRoot;if (p == p->right) minRoot = nullptr;else{removeNode(p);minRoot = p->right;}p->left = p->right = p;return p;}// 将node链接到root根结点,node称为root的孩子节点void link(FibNode<T>* node, FibNode<T>* root){// 将node从双链表中移除removeNode(node);// 将node设为root的孩子if (!root->child) root->child = node;else insertToRootList(node, root->child);node->parent = root;root->degree++;node->marked = false;}// 创建consolidate所需空间void makeCons(){int old = maxDegree;// 计算log2(currentSize),"+1"意味着向上取整!// ex. log2(13) = 3,向上取整为3+1=4。maxDegree = (log(currentSize)/log(2.0)) + 1;if (old >= maxDegree) return ;// 因为度为maxDegree可能被合并,所以要maxDegree+1cons = (FibNode<T> **)realloc(cons,sizeof(FibHeap<T> *) * (maxDegree + 1));}// 合并斐波那契堆的根链表中左右相同度数的树void consolidate(){int i, d, D;FibNode<T> *x, *y, *tmp;makeCons();//开辟哈希所用空间D = maxDegree + 1;for (i = 0; i < D; i++) cons[i] = nullptr;// 合并相同度的根节点,使每个度数的树唯一while (minRoot){x = extractMin();                // 取出堆中的最小树(最小节点所在的树)d = x->degree;                    // 获取最小树的度数// cons[d] != nullptr,意味着有两棵树(x和y)的"度数"相同。while (cons[d]){y = cons[d];                // y是"与x的度数相同的树"if (x->data > y->data) swap(x, y);       // 保证x的键值比y小link(y, x);    // 将y链接到x中cons[d] = nullptr;d++;}cons[d] = x;}minRoot = nullptr;// 将cons中的结点重新加到根表中for (i=0; i<D; i++){if (cons[i]){if (!minRoot) minRoot = cons[i];else{insertToRootList(cons[i], minRoot);if ((cons[i])->data < minRoot->data) minRoot = cons[i];}}}}// 修改度数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的值减少为datavoid decrease(FibNode<T> *node, T data);// 将斐波那契堆中节点node的值增加为datavoid increase(FibNode<T> *node, T data);// 更新斐波那契堆的节点node的键值为datavoid update(FibNode<T> *node, T data);// 在最小堆root中查找键值为data的节点FibNode<T>* search(FibNode<T> *root, T data);// 在斐波那契堆中查找键值为data的节点FibNode<T>* search(T data);// 删除结点nodevoid remove(FibNode<T> *node);// 销毁斐波那契堆void destroyNode(FibNode<T> *node);// 打印"斐波那契堆"void print(FibNode<T> *node, FibNode<T> *prev, int direction);
};/** 获取斐波那契堆中最小键值,并保存到pdata中;成功返回true,否则返回false。*/
template <class T>
bool FibHeap<T>::minRootimum(T *pdata)
{if (minRoot==nullptr || pdata==nullptr)return false;*pdata = minRoot->data;return true;
}/** 修改度数*/
template <class T>
void FibHeap<T>::renewDegree(FibNode<T> *parent, int degree)
{parent->degree -= degree;if (parent-> parent != nullptr)renewDegree(parent->parent, degree);
}/** 将node从父节点parent的子链接中剥离出来,* 并使node成为"堆的根链表"中的一员。*/
template <class T>
void FibHeap<T>::cut(FibNode<T> *node, FibNode<T> *parent)
{removeNode(node);renewDegree(parent, node->degree);// node没有兄弟if (node == node->right)parent->child = nullptr;elseparent->child = node->right;node->parent = nullptr;node->left = node->right = node;node->marked = false;// 将"node所在树"添加到"根链表"中insertToRootList(node, minRoot);
}/** 对节点node进行"级联剪切"** 级联剪切:如果减小后的结点破坏了最小堆性质,*     则把它切下来(即从所在双向链表中删除,并将*     其插入到由最小树根节点形成的双向链表中),*     然后再从"被切节点的父节点"到所在树根节点递归执行级联剪枝*/
template <class T>
void FibHeap<T>::cascadingCut(FibNode<T> *node)
{FibNode<T> *parent = node->parent;if (parent != nullptr){if (node->marked == false)node->marked = true;else{cut(node, parent);cascadingCut(parent);}}
}/** 将斐波那契堆中节点node的值减少为data*/
template <class T>
void FibHeap<T>::decrease(FibNode<T> *node, T data)
{FibNode<T> *parent;if (minRoot==nullptr ||node==nullptr)return ;if ( data>=node->data){cout << "decrease failed: the new data(" << data <<") "<< "is no smaller than current data(" << node->data <<")" << endl;return ;}node->data = data;parent = node->parent;if (parent!=nullptr && node->data < parent->data){// 将node从父节点parent中剥离出来,并将node添加到根链表中cut(node, parent);cascadingCut(parent);}// 更新最小节点if (node->data < minRoot->data)minRoot = node;
}/** 将斐波那契堆中节点node的值增加为data*/
template <class T>
void FibHeap<T>::increase(FibNode<T> *node, T data)
{FibNode<T> *child, *parent, *right;if (minRoot==nullptr ||node==nullptr)return ;if (data <= node->data){cout << "increase failed: the new data(" << data <<") "<< "is no greater than current data(" << node->data <<")" << endl;return ;}// 将node每一个儿子(不包括孙子,重孙,...)都添加到"斐波那契堆的根链表"中while (node->child != nullptr){child = node->child;removeNode(child);               // 将child从node的子链表中删除if (child->right == child)node->child = nullptr;elsenode->child = child->right;insertToRootList(child, minRoot);       // 将child添加到根链表中child->parent = nullptr;}node->degree = 0;node->data = data;// 如果node不在根链表中,//     则将node从父节点parent的子链接中剥离出来,//     并使node成为"堆的根链表"中的一员,//     然后进行"级联剪切"// 否则,则判断是否需要更新堆的最小节点parent = node->parent;if(parent != nullptr){cut(node, parent);cascadingCut(parent);}else if(minRoot == node){right = node->right;while(right != node){if(node->data > right->data)minRoot = right;right = right->right;}}
}/** 更新斐波那契堆的节点node的键值为data*/
template <class T>
void FibHeap<T>::update(FibNode<T> *node, T data)
{if(data < node->data)decrease(node, data);else if(data > node->data)increase(node, data);elsecout << "No need to update!!!" << endl;
}template <class T>
void FibHeap<T>::update(T olddata, T newdata)
{FibNode<T> *node;node = search(olddata);if (node!=nullptr)update(node, newdata);
}/** 在最小堆root中查找键值为data的节点*/
template <class T>
FibNode<T>* FibHeap<T>::search(FibNode<T> *root, T data)
{FibNode<T> *t = root;    // 临时节点FibNode<T> *p = nullptr;    // 要查找的节点if (root==nullptr)return root;do{if (t->data == data){p = t;break;}else{if ((p = search(t->child, data)) != nullptr)break;}t = t->right;} while (t != root);return p;
}/** 在斐波那契堆中查找键值为data的节点*/
template <class T>
FibNode<T>* FibHeap<T>::search(T data)
{if (minRoot==nullptr)return nullptr;return search(minRoot, data);
}/** 在斐波那契堆中是否存在键值为data的节点。* 存在返回true,否则返回false。*/
template <class T>
bool FibHeap<T>::contains(T data)
{return search(data)!=nullptr ? true: false;
}/** 删除结点node*/
template <class T>
void FibHeap<T>::remove(FibNode<T> *node)
{T m = minRoot->data-1;decrease(node, m-1);removeMin();
}template <class T>
void FibHeap<T>::remove(T data)
{FibNode<T> *node;if (minRoot==nullptr)return ;node = search(data);if (node==nullptr)return ;remove(node);
}/** 销毁斐波那契堆*/
template <class T>
void FibHeap<T>::destroyNode(FibNode<T> *node)
{FibNode<T> *start = node;if(node == nullptr)return;do {destroyNode(node->child);// 销毁node,并将node指向下一个node = node->right;delete node->left;} while(node != start);
}template <class T>
void FibHeap<T>::destroy()
{destroyNode(minRoot);free(cons);
}/** 打印"斐波那契堆"** 参数说明:*     node       -- 当前节点*     prev       -- 当前节点的前一个节点(父节点or兄弟节点)*     direction  --  1,表示当前节点是一个左孩子;*                    2,表示当前节点是一个兄弟节点。*/
template <class T>
void FibHeap<T>::print(FibNode<T> *node, FibNode<T> *prev, int direction)
{FibNode<T> *start=node;if (node==nullptr)return ;do{if (direction == 1)cout << setw(8) << node->data << "(" << node->degree << ") is "<< setw(2) << prev->data << "'s child" << endl;elsecout << setw(8) << node->data << "(" << node->degree << ") is "<< setw(2) << prev->data << "'s next" << endl;if (node->child != nullptr)print(node->child, node, 1);// 兄弟节点prev = node;node = node->right;direction = 2;} while(node != start);
}template <class T>
void FibHeap<T>::print()
{int i=0;FibNode<T> *p;if (minRoot==nullptr)return ;cout << "== 斐波那契堆的详细信息: ==" << endl;p = minRoot;do {i++;cout << setw(2) << i << ". " << setw(4) << p->data << "(" << p->degree << ") is root" << endl;print(p->child, p, 1);p = p->right;} while (p != minRoot);cout << endl;
}#define DEBUG 0// 共8个
int a[] = {12,  7, 25, 15, 28,33, 41,  1};
// 共14个
int b[] = {18, 35, 20, 42,  9,31, 23,  6, 48, 11,24, 52, 13,  2};// 验证"基本信息(斐波那契堆的结构)"
void testBasic()
{int i;int blen=sizeof(b)/sizeof(b[0]);FibHeap<int>* hb=new FibHeap<int>();// 斐波那契堆hbcout << "== 斐波那契堆(hb)中依次添加: ";for(i=0; i<blen; i++){cout << b[i] <<" ";hb->insert(b[i]);}cout << endl;cout << "== 斐波那契堆(hb)删除最小节点" << endl;hb->removeMin();hb->print();
}// 验证"插入操作"
void testInsert()
{int i;int alen=sizeof(a)/sizeof(a[0]);FibHeap<int>* ha=new FibHeap<int>();cout << "== 斐波那契堆(ha)中依次添加: ";for(i=0; i<alen; i++){cout << a[i] <<" ";ha->insert(a[i]);}cout << endl;cout << "== 斐波那契堆(ha)删除最小节点" << endl;ha->removeMin();ha->print();// 斐波那契堆hbcout << "== 插入50" << endl;ha->insert(50);ha->print();
}// 验证"合并操作"
void testUnion()
{int i;int alen=sizeof(a)/sizeof(a[0]);int blen=sizeof(b)/sizeof(b[0]);FibHeap<int>* ha=new FibHeap<int>();FibHeap<int>* hb=new FibHeap<int>();cout << "== 斐波那契堆(ha)中依次添加: ";for(i=0; i<alen; i++){cout << a[i] <<" ";ha->insert(a[i]);}cout << endl;cout << "== 斐波那契堆(ha)删除最小节点" << endl;ha->removeMin();ha->print();// 斐波那契堆hbcout << "== 斐波那契堆(hb)中依次添加: ";for(i=0; i<blen; i++){cout << b[i] <<" ";hb->insert(b[i]);}cout << endl;cout << "== 斐波那契堆(hb)删除最小节点" << endl;hb->removeMin();hb->print();// 将"斐波那契堆hb"合并到"斐波那契堆ha"中。cout << "== 合并ha和hb" << endl;ha->merge(hb);ha->print();
}// 验证"删除最小节点"
void testRemoveMin()
{int i;int alen=sizeof(a)/sizeof(a[0]);int blen=sizeof(b)/sizeof(b[0]);FibHeap<int>* ha=new FibHeap<int>();FibHeap<int>* hb=new FibHeap<int>();cout << "== 斐波那契堆(ha)中依次添加: ";for(i=0; i<alen; i++){cout << a[i] <<" ";ha->insert(a[i]);}cout << endl;cout << "== 斐波那契堆(ha)删除最小节点" << endl;ha->removeMin();//ha->print();// 斐波那契堆hbcout << "== 斐波那契堆(hb)中依次添加: ";for(i=0; i<blen; i++){cout << b[i] <<" ";hb->insert(b[i]);}cout << endl;cout << "== 斐波那契堆(hb)删除最小节点" << endl;hb->removeMin();//hb->print();// 将"斐波那契堆hb"合并到"斐波那契堆ha"中。cout << "== 合并ha和hb" << endl;ha->merge(hb);ha->print();cout << "== 删除最小节点" << endl;ha->removeMin();ha->print();
}// 验证"减小节点"
void testDecrease()
{int i;int blen=sizeof(b)/sizeof(b[0]);FibHeap<int>* hb=new FibHeap<int>();// 斐波那契堆hbcout << "== 斐波那契堆(hb)中依次添加: ";for(i=0; i<blen; i++){cout << b[i] <<" ";hb->insert(b[i]);}cout << endl;cout << "== 斐波那契堆(hb)删除最小节点" << endl;hb->removeMin();hb->print();cout << "== 将20减小为2" << endl;hb->update(20, 2);hb->print();
}// 验证"增大节点"
void testIncrease()
{int i;int blen=sizeof(b)/sizeof(b[0]);FibHeap<int>* hb=new FibHeap<int>();// 斐波那契堆hbcout << "== 斐波那契堆(hb)中依次添加: ";for(i=0; i<blen; i++){cout << b[i] <<" ";hb->insert(b[i]);}cout << endl;cout << "== 斐波那契堆(hb)删除最小节点" << endl;hb->removeMin();hb->print();cout << "== 将20增加为60" << endl;hb->update(20, 60);hb->print();
}// 验证"删除节点"
void testDelete()
{int i;int blen=sizeof(b)/sizeof(b[0]);FibHeap<int>* hb=new FibHeap<int>();// 斐波那契堆hbcout << "== 斐波那契堆(hb)中依次添加: ";for(i=0; i<blen; i++){cout << b[i] <<" ";hb->insert(b[i]);}cout << endl;cout << "== 斐波那契堆(hb)删除最小节点" << endl;hb->removeMin();hb->print();cout << "== 删除节点20" << endl;hb->remove(20);hb->print();
}int main()
{// 验证"基本信息(斐波那契堆的结构)"testBasic();// 验证"插入操作"testInsert();// 验证"合并操作"testUnion();// 验证"删除最小节点"testRemoveMin();// 验证"减小节点"testDecrease();// 验证"增大节点"testIncrease();// 验证"删除节点"testDelete();return 0;
}

数据结构与算法分析:斐波那契堆相关推荐

  1. 优先队列——斐波那契堆(without source code)

    [0]README 0.1) 本文部分内容转自 数据结构与算法分析,旨在理解 斐波那契堆 的基础知识: 0.2) 文本旨在理清 斐波那契堆的 核心idea,还没有写出源代码实现,表遗憾: 0.3)从实 ...

  2. 算法导论读书笔记-第十九章-斐波那契堆

    算法导论第19章--斐波那契堆 可合并(最小)堆(mergeable min-heap) : 支持以下5种操作的一种数据结构, 其中每一个元素都有一个关键字: MAKE-HEAP(): 创建和返回一个 ...

  3. 算法导论之斐波那契堆

    斐波那契堆,和二项堆类似,也是由一组最小堆有序的树构成.注意区别,不是二项树,是有根而无序的树.导论中,斐波那契堆只是具有理论上的意义,是以平摊分析为指导思想来设计的数据结构,主要是渐进时间界比二项堆 ...

  4. 算法导论--斐波那契堆

    斐波那契堆 斐波那契堆也是数据储存结构的一种,这种数据结构之所以产生,主要有两个优点:1.对于数据合并操作具有很高的效率:2.对于其他一般数据操作平均时间复杂度较好(注意这里是平均复杂度,不是最坏情形 ...

  5. 斐波那契堆(Fibonacci heaps)

    一:斐波那契堆 1:特性 斐波那契堆同二项堆一样,也是一种可合并堆.斐波那契堆的优势是:不涉及删除元素的操作仅需要O(1)的平摊运行时间(关于平摊分析的知识建议看<算法导论>第17章).和 ...

  6. Interview:算法岗位面试—上海某公司算法岗位(偏机器学习,互联网金融行业)技术面试考点之数据结构相关考察点—斐波那契数列、八皇后问题、两种LCS问题

    ML岗位面试:上海某公司算法岗位(偏机器学习,互联网金融行业)技术面试考点之数据结构相关考察点-斐波那契数列.八皇后问题.两种LCS问题 Interview:算法岗位面试-上海某公司算法岗位(偏机器学 ...

  7. boost::graph模块实现斐波那契堆的测试程序

    boost::graph模块实现斐波那契堆的测试程序 实现功能 C++实现代码 实现功能 boost::graph模块实现斐波那契堆的测试程序 C++实现代码 #include <boost/c ...

  8. 斐波那契堆(不太详尽)

    总结:这一章讲了斐波那契堆,它是一种比二项堆更松散的堆,它由一组无序的二项树组成,对不涉及删除元素的操作,它仅需O(1)的平摊运行时间.本章介绍斐波那契堆的插入.合并.删除等操作. 1.    斐波那 ...

  9. 二项堆与斐波那契堆各个操作时间复杂度

    过程 二项堆 斐波那契堆 MAKE_HEAP Θ(1) Θ(1) INSERT Ω(lgn) Θ(1) MINIMUM Ω(lgn) Θ(1) EXTRACT-MIN Θ(lgn) O(lgn) UN ...

最新文章

  1. LeetCode 1027. Longest Arithmetic Sequence--笔试题--C++解法
  2. 代码混淆工具Dotfuscator 在VS2008中的使用步骤
  3. 远程连接——Win连接远程Linux的软件
  4. 摩根大通分析:随着灰度资金流动缓慢,比特币能否重回4万美元仍存疑问
  5. python 文件和目录操作题库
  6. UnityShader27:屏幕雾效
  7. Dijkstra 算法初探
  8. C语言的体系结构--main函数存在的必然性(听杨力祥老师的课)
  9. 《SEM长尾搜索营销策略解密》一一2.12 宝洁里的长尾与创新
  10. Visio绘制架构图(一)
  11. Arduino+WZ指令+Onenet
  12. 软件人才应具备的五种素质
  13. 我是如何成为一名少儿编程竞赛老师的
  14. 【OBS】OBS Studio 的安装、参数设置和录屏、摄像头使用教程
  15. CPU是沙子做的,凭什么卖那么贵?
  16. 一个屌丝程序猿的人生(一百零八)
  17. aws亚马逊云购买服务器的操作记录
  18. 苹果新款笔记本_微软为Bing桌面体验也带来了语音搜索功能_苹果 新款MacBook Pro 13英寸_笔记本新闻...
  19. 便利贴--25{uniapp移动端滑动模块-因为uniapp打包后没有window,所以要另外去做监听和触控事件的传递}
  20. c语言makecode头文件,cmake 添加头文件目录,链接动态、静态库

热门文章

  1. Ubuntu系统下制作USB启动盘
  2. windows server 2008 英文版安装中文vs2008 sp1补丁失败的解决办法
  3. 永中Office—公文打印
  4. 各类学习资料(网址)汇总~
  5. 字节跳动前端实习一面二面(凉面)
  6. MODIS数据下载、拼接、转tif
  7. IDEA导入Mybatis源码
  8. BarTender安装不出现激活页面
  9. Web渗透测试之逻辑漏洞挖掘
  10. nRF52840作为通信模块与Arduino的联动