美文网首页CS专业上
算法导论斐波那契堆笔记

算法导论斐波那契堆笔记

作者: 琦思妙想君 | 来源:发表于2018-10-18 18:28 被阅读71次

    斐波那契堆相比普通的二项堆,主要区别在于它的性能更高,在合并堆、插入和 Decrease 等操作时具有更好的摊还性能。

    个人认为二项堆的性能已经足够好了,书中居然说二项堆在 UNION 操作时性能很差,而这个很差的性能是 O(n),对大部分操作来说这已经是性能的极限了。斐波那契堆的 UNION 操作只需要 O(1) 的摊还时间,确实有立场鄙视二项堆。

    不过书中也说了,斐波那契堆的实用性并不太好,编程复杂,性能的常数因子大,主要是理论研究。

    二项堆和斐波那契堆的 search 操作都比较低效(书中没有给出数值,我觉得这个低效的性能应该是 O(lgn),大佬的鄙视链是没有上限的)。

    斐波那契堆结构

    斐波那契堆是一系列具有最小堆序的有根树的集合。

    入口:堆的入口是整个堆中最小的元素,它处于一个双向循环链表中,这个链表叫根链表。所以结点会有 left 和 right 属性指向它的兄弟结点。

    孩子:结点只有一个孩子属性,指向孩子链表的入口,这个入口背后同样是一个双向循环链表。

    结点的 degree 属性表示其孩子链表的结点数目。

    结点的 mark 属性表示该结点自从上一次成为另一个结点的孩子后,是否失去过孩子。(不是太明白这个描述,mark 属性是在调整堆的结构时使用)

    可合并堆操作

    创建堆
    创建空堆的摊还代价为 O(1)

    插入结点
    插入操作很简单,初始化一个新的结点,加入到斐波那契堆的根链表中,完毕。摊还代价为 O(1)

    寻找最小结点
    最小结点就是斐波那契堆的入口结点 H.min,摊还代价为 O(1)

    合并
    合并操作就是把两个堆的根链表链接成一个,比较两个堆的入口结点选出合并后的入口结点

    抽取最小结点
    分为两步,第一步把入口结点(也就是最小结点)抽出,将它的子结点都添加到根链表中(这时候已经破坏了堆的性质)。第二步执行一系列复杂的合并恢复堆的性质。
    可由一系列复杂的操作证明,Extarct 操作的摊还代价为 O(lgn)

    关键字减值和删除一个结点

    关键字减值的意思是,把某个结点的关键字减小,然后调整堆的结构。这个调整的过程比较复杂,涉及到 mark 属性的使用,以及“切断”和“级联切断”。

    简单的描述减值操作的过程:
    1.将结点的关键字修改后判断是否比父结点小,如果小就从原位置切下来,放到根链表中。
    2.对父结点递归的执行“级联切断”
    3.比较被减值的结点(现在在根链表中)与原 min 结点,选出新的 min 结点。

    级联切断是一个向上递归的过程,到根链表中止,某一级中的操作为:判断结点是否被标记,如果被标记则执行“切断”并继续递归,如果没被标记,则标记该结点并中止递归。

    可以证明“减值”操作的摊还代价为 O(1)(我表示惊呆)

    删除结点的操作是由减值和 Extract 组成的,摊还时间为 O(lgn)

    最大度数的界

    通过一堆引理证明了斐波那契堆中任意结点的度数的上界 D(n) 为 O(lgn)。

    顺便解释了斐波那契堆名字的由来:斐波那契来自斐波那契数列,堆与数列的关联在于堆的合并操作中,结点的 size(结点为根的子树中所有结点的数目)按数列增长。(这个关联是我自己解释的,并不严谨)

    相关文章

      网友评论

        本文标题:算法导论斐波那契堆笔记

        本文链接:https://www.haomeiwen.com/subject/iavszftx.html