【原理思路】斐波那契堆各操作编程思路

来源:互联网 发布:麦当劳改名金拱门知乎 编辑:程序博客网 时间:2024/05/21 10:17

在二项堆的各基本操作中我们发现,在插入一个节点,取最小值,抽取最小关键字,以及合并的操作中,时间复杂度均为O(lgn),本节介绍斐波那契堆,它有一个长处,即不涉及删除元素的操作仅需O(1)的平摊运行时间;


斐波那契堆的性质

(1)斐波那契堆由一组最小堆有序树构成的,但堆中的树不一定是二项树;

(2)斐波那契堆的树都是有根而无序的;

(3)每一个节点包含指向父节点的指针parent;

(4)每一个节点包含指向其任一子女的指针child;

(5)每一个节点的所有子女都被练成了一个环形双向链表;个子女次序任意;

(6)每一个节点的所有子女的有指针left,right分别指向其左右兄弟;若仅有一个子女,则left=y=right;

(7)每一个节点包含degree,是其子女的个数;

(8)每一个节点包含mark,仅当它成为另一个节点以来,它是否失去过一个子女,置为false;它本身成为一个别人的孩子,是不会置成false的;

(9)含有指针min,指向关键字最小的根;

注:环形链表的好处:在O(1)可将一个节点删除;在O(1)可连接好这两个环形链表;




操作的平摊时间复杂度为O(1)

(1)斐波那契堆插入一个节点,直接插入即可,无需合并,但记得可能要更新好最小关键字的指针;

(2)最小关键字,min直接指向,返回即可;

(3)合并两个斐波那契堆,也是简单的合并,但记得可能要更新好最小关键字的指针;


抽取最小关键字节点

(1)主要是树的合并被推后了,这时,就要完成合并;

(2)首先使最小节点的每一个子女都成为一个根,并将最小根节点从根表中去掉;

(3)关键思想,要将根表成为每一个度数都不同的斐波那契堆;

(4)调整的过程主要是基于一个度数表(通过指针来指向),直到所有的根度数都不同;

(4.1)每次先初始化一次度数表,然后进行合并更新;主要这样可以一次性的处理最大的度数表的根;

(4.2)循环4.1步骤;

(5)时间复杂度为O(lgn);虽然申请了一个常数级的度数表,但空间复杂度O(1);





减小一个节点关键字的大小

(1)只是简单的将该节点,去除成为一个根;并使它的父亲,用mark来标记成false;

(2)如果用mark来标记它父亲成为false的过程中,已经发现它父亲被标记过了,就也要将它去除成为一个根,并标记根的父亲;根节点是不需要标记的;

(3)平摊的时间复杂度仍为O(1);


删除一个节点

(1)先减小一个节点关键字的大小为-oo;

(2)抽取最小关键字-oo的节点;

(3)平摊的时间复杂度仍为O(lgn);


下面是二叉堆(大根堆或小根堆),二项堆,斐波那契堆的各操作的时间复杂度;


0 0