结构之美——优先队列三大结构(二)——斐波那契堆(Fibonacci Heap)

斐波那契堆是一种优于二项堆的数据结构,尤其在频繁进行插入、查找最小元素和合并操作时。它通过特殊的树结构和延迟合并策略,实现了这些操作的常数时间复杂度。虽然实际应用中可能因复杂性而较少使用,但在理论上,斐波那契堆对于解决最小生成树和最短路径等问题提供了高效的算法支持。
摘要由CSDN通过智能技术生成

1.简介

斐波那契堆是一种松散的二项堆,与二项堆的主要区别在于构成斐波那契堆得树可以不是二项树,并且这些树的根排列是无序的(二项堆的根结点排序从左到右是按照结点个数排序的,不是按照根结点的大小)。

斐波那契堆得优势在于它对建堆、插入、抽取最小关键字、联合等操作能在O(1)的时间内完成(不涉及删除元素的操作仅需要O(1))。这是对二项堆效率的巨大改善。在EXACT-MIN|, DELETE的操作数目较小时,斐波那契堆是很理想的,例如:某些图问题算法对每条边都要调用一次DECREASE-KEY(图的最小割:Graph-cut:Min-Cut Problem )。对许多稠密图来说,每一次DECREASE-KEY调用的O(1)加起来,就是对二叉或者二项堆的最坏情况的一种显著改善。用于解决最小生成树和寻找单源最短路径等问题的快速算法都要用到斐波那契堆。

但是,从实际上看,对于大多数应用来说,由于斐波那契堆得常数因子以及程序设计上的复杂度,使它不如通常的二叉堆合适。因此,它的价值大多存在于理论意义上(如果设计出一种与斐波那契堆具有相同平摊时间界但又简单得多数据结构,那他就会有很大的实用价值)。

斐波那契堆如果不进行DECREASE-KEY,DELETE,则堆中的树与二项树一致。由于相对于二项堆,斐波那契堆更松散,合并操作只发生在抽取一个结点之后,也就是说斐波那契堆的维护可以(总是)被延后到方便时再做。

 

1.1斐波那契堆结点ADT

结点含有以下域:

1) 父节点p[x]

2) 指向任一子女的指针child[x]——结点x的子女被链接成一个环形双链表,称为x的子女表

3) 左兄弟left[x]

4) 右兄弟right[x]——当left[x] = right[x] = x时,说明x是独子。

5) 子女的个数degree[x]

6) 布尔值域mark[x]——标记是否失去了一个孩子

//斐波那契结点ADT
struct FibonacciHeapNode {
    int key;       //结点
    int degree;    //度
    FibonacciHeapNode * left;  //左兄弟
    FibonacciHeapNode * right; //右兄弟
    FibonacciHeapNode * parent; //父结点
    FibonacciHeapNode * child;  //第一个孩子结点
    bool marked;           //是否被删除第1个孩子
};
typedef FibonacciHeapNode FibNode;
 


1.2斐波那契堆ADT

对于一个给定的斐波那契堆H,可以通过指向包含最小关键字的树根的指针min[H]来访问,这个结点被称为斐波那契堆中的最小结点。如果一个斐波那契堆H是空的,则min[H] = NIL. 在一个斐波那契堆中,所有树的根都通过left和right指针链接成一个环形的双链表,称为堆的根表。于是,指针min[H]就指向根表中具有最小关键字的结点(就是查找最小结点的操作,下文就没有再介绍了)。

//斐波那契堆ADT
struct FibonacciHeap {
    int keyNum;   //堆中结点个数
    FibonacciHeapNode * min;//最小堆,根结点
    int maxNumOfDegree;   //最大度
    FibonacciHeapNode * * cons;//指向最大度的内存区域
};
 
typedef FibonacciHeap FibHeap;

 

 

 

2.斐波那契堆操作

 

2.1.创建斐波那契堆

创建一个空的斐波那契堆,过程MAKE-FIB-HEAP 分配并返回一个斐波那契堆对象H; 

//初始化一个空的Fibonacci Heap
FibHeap * FibHeapMake() {
    FibHeap * heap = NULL;
    heap = (FibHeap *) malloc(sizeof(FibHeap));
    if (NULL == heap) {
        puts("Out of Space!!");
        exit(1);
    }
    memset(heap, 0, sizeof(FibHeap));
    return heap;
}
 
//初始化结点x
FibNode * FibHeapNodeMake() {
    FibNode * x = NULL;
    x = (FibNode *) malloc(sizeof(FibNode));
    if (NULL == x) {
        puts("Out of Space!!");
        exit(1);
    }
    memset(x, 0, sizeof(FibNode));
    x->left = x->right = x;
    return x;
}


 

 

2.2.插入一个结点

要插入一个结点x,对结点的各域初始化,赋值,然后构造自身的环形双向链表后,将x加入H的根表中。 也就是说,结点x 成为一棵单结点的最小堆有序树,同时就是斐波那契堆中一棵无序树而且在根表最小结点的左边。

如图是将关键字为21的结点插入斐波那契堆。该结点自成一棵最小堆有序树,从而被加入到根表中,成为根的左兄弟。 

 

 

 
FIB-HEAP-INSERT(H, x)

1  degree[x]  0

2  p[x]  NIL

3  child[x]  NIL

4  left[x]  x

5  right[x]  x

6  mark[x]  FALSE

7  concatenate the root list containing x with root list H 

8  if min[H] = NIL or key[x] < key[min[H]]

9     then min[H]  x

10  n[H]  n[H] + 1

 

 
 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值