在二项堆的各基本操作中我们发现,在插入一个节点,取最小值,抽取最小关键字,以及合并的操作中,时间复杂度均为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);
下面是二叉堆(大根堆或小根堆),二项堆,斐波那契堆的各操作的时间复杂度;