斐波那契堆.docVIP

  • 3
  • 0
  • 约3.88千字
  • 约 5页
  • 2016-12-03 发布于重庆
  • 举报
斐波那契堆

斐波那契堆 一、堆的结构 堆中各个有序树的树根之间用双向循环链表连接。每颗有序树中兄弟节点之间用双向循环链表连接。 每个节点拥有fa,child,last,next四个指针:分别指向父节点、任意一个子节点、左右相邻的兄弟节点。 每个节点还记录dat,du,mark三个值:分别表示关键字的值、度数(子节点个数)、剪枝标记。一个指针p,指向所有树根中关键字最小的那个。通过这个指针可以访问该斐波那契堆。 二、堆的操作 (1)插入一个节点x(Insert) 创建一棵仅含有节点x的树,并插入到斐波那契堆的树根链表中 更新指针P指向的节点(如果需要) (2)查询最小值(GetMin) 直接返回指针P指向的节点的关键字值由于斐波那契堆中的所有树均满足最小堆性质, 因此最小值就是所有树根关键字的最小值。 (3)合并两个斐波那契堆(Merge/Union) 将两个斐波那契堆的树根链表连接起来(连接两个双向循环链表) 更新指针P指向的节点(如果需要) (4)删除(Delete) Delete = Decrease + Extract 即首先把要删除的节点的关键值减小为负无穷大,然后删除最小节点。 (5)修改关键字的值(Change) 减小关键字的值 = Decrease 增大关键字的值 = Delete + Insert 即首先删除要修改的节点,再重新插入该节点。 三、复杂度 插入、查询最小值、合并两个斐波那契堆、合并堆中两个有序树的实际代价和平摊代价 均为为O(1)。定义φ(DS)=k*根节点数 + 2*带标记节点数(常数k不妨设为1)。 抽取最小节点: 实际代价为遍历根节点和遍历桶的代价,O(根节点数)+O(logN)? 合并后树根的度数各不相同,因此合并后最多有logN个树根,所以势能函数的改变为 Δφ(DS) = logN – 根节点数。 平摊代价为:(根节点数+logN) + (logN–根节点数) = O(logN) 四、具体实现: #include iostream #include cstring #include cstdlib #define du(x) heap[x].du #define fa(x) heap[x].fa #define ch(x) heap[x].child #define r(x) heap[x].next #define l(x) heap[x].last #define mark(x) heap[x].mark typedef long long ll; using namespace std; const int mx = 1000000; int v[mx]; int p,n,m; struct Fibonacci_Heap { int du,fa,child,next,last,mark; } heap[mx]; vectorint a[25]; ///桶 ll d[mx]; ///距离数组 int head[mx],cnt; struct N { int from,to,w,next; } edge[mx]; ///链式前向星(用数组模拟的邻接链表) void add(int from,int to,int w) { edge[cnt].to = to; edge[cnt].from = from; edge[cnt].w = w; edge[cnt].next = head[from]; head[from] = cnt++; } ///向邻接链表中添加一条由from到to的边,且权重为w void Link(int x,int y) { if(!x||!y) return; l(r(x))=l(y),r(l(y))=r(x); r(x)=y,l(y)=x; } /// 此方法将x点与y点相连 void Cut(int x) { if(ch(fa(x))==x) ch(fa(x))=r(x)==x?0:r(x); du(fa(x))--; r(l(x))=r(x),l(r(x))=l(x); l(x)=r(x)=x; fa(x)=mark(x)=0; } /// 次方法将x点从堆中切除 void Insert(int x) { l(x)=r(x)=x,v[x]=1; Link(x,p); if(d[x]d[p]) p=x; } ///将点x插入到堆中 void Decrease(int x) { if(!fa(x)) { if(d[x]d[p]) p=x;

文档评论(0)

1亿VIP精品文档

相关文档