斐波那契堆(Fibonacci heap)原理详解(附java代码实现)

article/2025/8/29 17:27:10

前言

  斐波那契堆(Fibonacci heap)是计算机科学中最小堆有序树的集合。它和二项式堆有类似的性质,但比二项式堆有更好的均摊时间。堆的名字来源于斐波那契数,它常用于分析运行时间。

     

 

 

堆结构介绍

  基本术语介绍:

  关键字:堆节点储存的用于比较的信息

  度数:堆节点拥有的孩子数(注意,不包括孩子的孩子)

  左兄弟:节点左边的兄弟节点

  右兄弟:节点右边的兄弟节点

  mark:是否有孩子节点被删除

 

  斐波那契堆是一系列无序树的集合,每棵树是一个最小堆,满足最小堆的性质。(注意,树是无序的,所以不要纠结树该怎么排序)。堆保存了堆中所有节点的数目,保存了最小关键字的节点(这是整个堆的唯一入口,根据这个最小节点可以获取整个堆的任何节点)。

  堆的节点是堆的最小单位,它是双向链表的节点,意味着它保存了上下节点的信息,如下图,(也能看出树的根节点排列是无序的)。

  

  它主要有如下性质:

  1、关键字

  2、度数

  3、左兄弟

  4、右兄弟

  5、父节点

  6、孩子节点(任一个孩子节点,随意)

 

堆基本操作

  一、插入操作

    1、创建一个节点,如21

  

  2、把新建的节点插入到根链表中,如果是最小值,则更新它为堆的最小节点。插入位置没有规定,一般习惯插入到min的左边。把堆的“所有节点数”值加1

  

  3、插入操作完成了(插入并不会对堆进行修改,修改是在其他操作中进行的,所以比较简单)

 

  二、删除最小节点

    1、删除最小节点,并把它的所有孩子合并到堆的根链表中,并更新min

 

  2、合并根节点的树,使任何树的度(rank)不相等

    观察到7有1个孩子节点,即度为1,先保存起来,由于是初始的,肯定没有和7度相同的

    接着下一个根节点24,度为2,继续。

    23, 度为1,继续

    17, 度为1。 由于已经有度为1的根节点了,所以需要合并这两个节点

    根据最小堆得性质,把23合并到17上,作为17的孩子节点

    此时17的度为2,仍然重复,继续合并,直到没有度一样的根节点

 

    最终结果如下图

 

    

 

  三、减小key值

    如果没有违背最小堆的性质,直接减小key的值

    否则,把以key为根节点的树合并到堆的根链表中

    如果有一个节点有两个孩子移除了,把这个节点也合并到根链表中,并且unmark它

    

    现在举一个例子来说明各种可能情况

    1、不违反最小堆性质

      把46减小为29,不违反最小堆性质,不改变堆结构

  

    2、违反最小堆性质,合并到根链表中,并且unmark 它

      把29减小为15,违反了堆性质

  

    把15合并到根链表中

  如果父节点没有mark(没有失去孩子), 设置它为mark

  

  如果父节点已经是mark,则把父节点合并到根链表中,并设置为unmark。

  把节点35减小到5 

  

  由于违反了,把5合并到根

  由于26已经mark,把26这个子树合并到根

  同理24合并到根

  由于7已经是根节点了,停止,全部结束

  四、删除节点

    删除节点比较简单,主要分为两步

    1、把节点值decrease比堆最小值还小

    2、删除最小值

 

java代码实现(仅供参考,逻辑并不十分严谨)

 

 1 public class FibonNode<T extends Comparable<T>> {
 2 
 3     public T key;
 4     
 5     public FibonNode<T> child;
 6     
 7     public FibonNode<T> left;
 8     
 9     public FibonNode<T> right;
10     
11     public boolean mark;
12     
13     public FibonNode<T> parent;
14     
15     public int degree;
16     
17     public FibonNode(T key){
18         this.degree = 0;
19         this.key = key;
20         this.parent = null;
21         this.child = null;
22         this.left = null;
23         this.right = null;
24         this.mark = false;
25     }
26 }

 

 

 

 

  1 public class FibonHeap<T extends Comparable<T>> {
  2 
  3     private int keyNum;
  4 
  5     private FibonNode<T> min;
  6 
  7     /*
  8      * 保存当前指针
  9      */
 10     private FibonNode<T> current;
 11 
 12     /*
 13      * 保存各个度对应的节点,如度为1的节点对应的节点
 14      */
 15     private Map<Integer, FibonNode<T>> degreeNodes;
 16 
 17     public FibonHeap(T key) {
 18         min = new FibonNode<T>(key);
 19         keyNum += 1;
 20         min.left = min;
 21         min.right = min;
 22     }
 23 
 24     /*
 25      * 插入值
 26      */
 27     public void insert(T key) {
 28         FibonNode<T> node = new FibonNode<T>(key);
 29         insert(node);
 30     }
 31 
 32     
 33     /*
 34      * 删除最小值
 35      */
 36     public void deleteMin() {
 37         degreeNodes = new HashMap<Integer, FibonNode<T>>();
 38         removeMinNode();
 39         consolidate();
 40 
 41     }
 42     
 43     /*
 44      * 删除节点
 45      */
 46     public void deleteNode(FibonNode<T> node){
 47         T everSmall = null;
 48         decrease(node, everSmall);
 49         deleteMin();
 50     }
 51     
 52     /*
 53      * 合并堆
 54      */
 55     public FibonHeap<T> union(FibonHeap<T> heapA, FibonHeap<T> heapB){
 56         FibonNode<T> minA = heapA.min;
 57         FibonNode<T> minB = heapB.min;
 58         minA.right = minB;
 59         minA.right.left = minB.right;
 60         minB.left = minA;
 61         minB.right.left = minA.right;
 62         FibonNode<T> min = minA;
 63         if(minB.key.compareTo(minB.key) < 0){
 64             min = minB;
 65         }
 66         heapA.min = min;
 67         heapA.keyNum += heapB.keyNum;
 68         return heapA;
 69     }
 70     
 71     private void insert(FibonNode<T> node) {
 72         //插入就是直接更新左右节点就可以了
 73         min.left.right = node;
 74         node.left = min.left;
 75         node.right = min;
 76         min.left = node;
 77         T minKey = min.key;
 78         if (node.key.compareTo(minKey) < 0) {
 79             min = node;
 80         }
 81         keyNum += 1;
 82     }
 83     
 84     /*
 85      * 把节点从堆中删除
 86      */
 87     private void removeMinNode() {
 88         FibonNode<T> left = min.left;
 89         if (left == min) {
 90             //说明只剩最后一个节点了,也就是最小节点自己
 91             if (min.child != null) {
 92                 min = null;//这里不是null,应该是孩子节点中最小节点,笔者没有写完而已
 93             }
 94         } else {
 95             deleteInList(min);
 96             addChToR(min);
 97             min = left;    //    先随意选个节点作为最小节点,在随后环节会更新的
 98         }
 99         keyNum--;
100     }
101 
102 
103     /*
104      * 把根节点合并使其所有节点的度不相等
105      */
106     private void consolidate() {
107         current = min;
108         do {
109             current = putDegreeNodes(current);
110             if (current.key.compareTo(min.key) < 0) {
111                 min = current;
112             }
113             current = current.right;
114         } while (current != min && current.left != current);
115     }
116 
117     /*
118      * 
119      */
120     private FibonNode<T> putDegreeNodes(FibonNode<T> node) {
121         int nodeDegree = node.degree;
122         //从map中找节点对应的度是否存在,存在说明有相同度的节点了,需要合并
123         FibonNode<T> nodeInMap = degreeNodes.get(nodeDegree);    
124         if (nodeInMap == null) {
125             degreeNodes.put(nodeDegree, node);
126         } else {
127             if (node.key.compareTo(nodeInMap.key) < 0) {
128                 deleteInList(nodeInMap);
129                 nodeInMap.left = nodeInMap;
130                 nodeInMap.right = nodeInMap;
131                 node = fibLink(node, nodeInMap);
132                 nodeInMap = node;
133             } else {
134                 deleteInList(node);
135                 node.left = node;
136                 node.right = node;
137                 nodeInMap = fibLink(nodeInMap, node);
138 
139                 node = nodeInMap;
140             }
141             degreeNodes.put(nodeDegree, null);
142             node = putDegreeNodes(node);
143         }
144         return node;
145     }
146 
147     private FibonNode<T> fibLink(FibonNode<T> parent, FibonNode<T> child) {
148         if (parent.child == null) {
149             parent.child = child;
150             
151         } else {
152             parent.child = insertCyle(parent.child, child);
153         }
154         child.parent = parent;
155         parent.degree += 1;
156         return parent;
157     }
158 
159     /*
160      * 从所在链中删除
161      */
162     private void deleteInList(FibonNode<T> node) {
163         FibonNode<T> left = node.left;
164         FibonNode<T> right = node.right;
165         left.right = right;
166         right.left = left;
167     }
168 
169     /*
170      * 插入到链中
171      */
172     private FibonNode<T> insertCyle(FibonNode<T> target, FibonNode<T> node) {
173         FibonNode<T> left = target.left;
174         left.right = node;
175         node.left = target;
176         node.right = target;
177         target.left = node;
178         return target;
179     }
180 
181     /*
182      * 把孩子节点添加到根链表中
183      */
184     private void addChToR(FibonNode<T> node) {
185         FibonNode<T> aChild = node.child;
186         if (aChild == null) {
187             return;
188         }
189         do {
190             //孩子节点循环插入根
191             FibonNode<T> right = aChild.right;
192             min.right = insertCyle(min.right, aChild);
193             aChild = right;
194 
195         } while (aChild != node.child);
196     }
197     
198     public void decrease(FibonNode<T> target, T key){
199         FibonNode<T> parent = target.parent;
200         if(target.key.compareTo(key) < 0){
201             System.out.println("只能减少key值");
202             return;
203         }
204         if(parent == null){
205             //如果修改节点是根节点,直接修改
206             target.key = key;
207             if(key.compareTo(min.key) < 0){
208                 //更新最小节点
209                 min = target;
210             }
211             return;
212         }
213         if(parent.key.compareTo(key) < 0){
214             //如果值修改稿后不违反最小堆,直接修改即可
215             target.key = key;
216             return;
217         }
218         cutAndMeld(target);
219         parent = cascadingCut(parent);
220     }
221     
222     /*
223      * 删除节点,并合并到根中
224      */
225     private void cutAndMeld(FibonNode<T> target){
226         target.parent = null;
227         target.mark = false;
228         insert(target);
229     }
230     
231     /*
232      * 级联删除,使其符合斐波那契堆性质
233      */
234     private FibonNode<T> cascadingCut(FibonNode<T> parent){
235         if(null == parent){
236             return null;
237         }
238         parent.degree--;
239         if(parent.mark == false){
240             parent.mark = true;
241         }else{
242             cutAndMeld(parent);
243             parent = cascadingCut(parent);
244         }
245         return parent;
246     }
247     
248     
249 }

 

 

 

 

参考文献

  http://staff.ustc.edu.cn/~csli/graduate/algorithms/book6/chap21.htm

  斐波那契堆(一)之 图文解析 和 C语言的实现

  fibonacci-heap

  Fibonacci_heap

  

转载于:https://www.cnblogs.com/junyuhuang/p/4463758.html


http://chatgpt.dhexx.cn/article/CZee4Mc0.shtml

相关文章

斐波那契堆

斐波那契堆 作者&#xff1a; 大树先生 博客&#xff1a; http://blog.csdn.net/koala_tree GitHub&#xff1a;https://github.com/koalatree 2017 年 09 月 13 日 自《算法导论》. 斐波那契堆有两种用途&#xff1a;第一种&#xff0c;支持一系列操作&#xff0c;这些操作…

斐波那契堆(Fibonacci Heap)

也许我们每个人都知道斐波那契数列&#xff08;Fibonacci sequence&#xff09;。即这样一个数列&#xff1a;1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144...,如果我们用伪代码比表示: int FibonacciSequence(int n){if (n 1 || n 2) {return 1;}return FibonacciSequence(n …

斐波那契堆(一)之 图文解析 和 C语言的实现

出自&#xff1a;http://www.cnblogs.com/skywang12345/p/3659060.html 斐波那契堆(一)之 图文解析 和 C语言的实现 概要 本章介绍斐波那契堆。和以往一样&#xff0c;本文会先对斐波那契堆的理论知识进行简单介绍&#xff0c;然后给出C语言的实现。后续再分别给出C和Java版本…

斐波那契堆的C++实现

本文改编自《算法导论》第三版第19章&#xff1a;斐波那契堆。文中代码为书中伪代码的C实现&#xff0c;如有疏漏还请指出。 1.斐波那契堆的结构 斐波那契堆是一种可并堆&#xff0c;它支持以下操作&#xff1a; ( 1 ) (1) (1)在 O ( 1 ) O(1) O(1)时间内插入元素、获取最小…

常见电子元器件检测方法。——Arvin

电子设备中使用着大量各种类型的电子元器件&#xff0c;设备发生故障大多是由于电子元器件失效或损坏引起的。因此怎么正确检测电子元器件就显得尤其重要&#xff0c;这也是电子维修人员必须掌握的技能。我在电器维修中积累了部分常见电子元器件检测经验和技巧&#xff0c;供大…

电工电子复习题

1、应用叠加定理时&#xff0c;理想电压源不作用时视为______&#xff0c; 理想电流源不作用时视为____。 2、电容元件具有“通_____隔_____”的特性&#xff0c; 电感元件具有通___阳___ ”的特性&#xff0c;。 3、已知:“u 60sin(628t -135度)(v),则其有效值为____V,角频率为…

我的元器件入门

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 元器件 前言一、电阻器1、什么是电阻器2、电阻的标示方法和测量方法3、电阻的特性4、基本参数5、电阻的功能 二、电容器1、什么是电容&#xff1f;组成&#xff0c;基本参数&…

2023年天津中德应用技术大学专升本机械电子工程专业考试大纲

天津中德应用技术大学 机械电子工程专业&#xff08;高职升本科&#xff09; 2023年专业基础考试大纲 备注&#xff1a;考试题型&#xff1a;填空题、选择题、判断题、问答题、分析题、设计与计算题 《机械设计基础》主要知识点 第一部分常用机构 一、平面机构运动分析 知…

2021中级维修电工证考试题库2021职业技能鉴定

题库来源:特种作业模考题库小程序 1.三相负载作Y接时,无论负载对称与否,线电流总等于相电流。 √ 2.双向晶闸管是( )半导体结构。 B A.四层 B.五层 C.三层 D.二层 3.符合有“0”得“0”,全“1”得“1”的逻辑关系的逻辑门是( )。 B A.或门 B.与门 C.非门 D.或非门 4.示波…

2018第八届至2022年第十三届蓝桥杯单片机开放与设计省赛客观题及简解整理

前言&#xff1a; 由于本人马上要参加第十四届蓝桥杯单片机设计与开发的省赛了&#xff0c;在对客观题复习两轮后&#xff0c;发现效率是比较低的&#xff0c;因此整理了2018至2022年的省赛客观题&#xff0c;将大概的考点划分三部分&#xff0c;这样可以更加系统的复习其内容。…

晶体管频率特性——高频等效模型、频率特性、π模型的单向化

晶体管高频等效模型 通过之前的定性分析得出在高频情况下晶体管结电容将对信号传输带来较大影响。之前的 h 参数等效模型没有考虑结电容的影响&#xff0c;因此不再适用&#xff0c;此时要用新的模型来反映晶体管的结电容&#xff0c;这就是高频等效模型。 此时从晶体管的实际…

[渝粤教育] 郑州航空工业管理学院 电工电子技术基础 参考 资料

教育 -电工电子技术基础-章节资料考试资料-郑州航空工业管理学院【】 小节测试 1、【判断题】任何一个完整的电路都必须有电源、负载和中间环节三个基本部分组成。 A、正确 B、错误 参考资料【 】 2、【判断题】电路的作用是对电能进行传输、分配和转换&#xff1b;而对电信号进…

服务于期末考试的计算机硬件基础资料

电路的基本概念和基本定律 电流和电路模型 理想元件、理想电路、集总参数元件、集总参数电路 集总元件&#xff1a; 当电路器件的尺寸远小于电路最高工作频率所对应的波长时&#xff0c;可以认为元件的参数“集总”于一个点上&#xff0c;形成所谓的集总参数元件。 理想元件&am…

您需要了解的跨阻放大器——第1部分

跨阻放大器(TIA)是光学传感器(如光电二极管)的前端放大器,用于将传感器的输出电流转换为电压。跨阻放大器的概念很简单,即运算放大器(op amp)两端的反馈电阻(RF)使用欧姆定律VOUT= I RF 将电流(I)转换为电压(VOUT)。在这一系列博文中,我将介绍如何补偿TIA,及如…

小白的模拟电路初步学习20日打卡(11)

放大电路分析 一.基本共射放大电路的波形分析 输入电压。并且Ic等于βIb&#xff0c;所以本图可以表示Ic动态信号驮载在静态工作点上变化方向与之前的IbIc不同&#xff0c;但是是有关联的&#xff0c;即与其反向。 而这同时也是电压输出波形&#xff0c;所以可知共射放大电路…

8.1 正弦波振荡电路(1)

正弦波振荡电路是在没有外加输入信号的情况下&#xff0c;依靠电路自激振荡而产生正弦波输出电压的电路。它广泛地应用于测量、遥控、通讯、自动控制、热处理和超声波电焊等加工设备之中&#xff0c;也作为模拟电子电路的测试信号。 一、概述、 1、产生正弦波振荡的条件 在负…

【长篇肝文7万字】模电/数电/单片机/计算机组成原理/电力电子常见笔试/面试题(合集)未完更新ing

目录 一、模拟电子电路 1、基尔霍夫定理的内容 2、描述反馈电路的概念&#xff0c;列举它们的应用。 2.1 反馈的定义&#xff1a; 2.2 反馈的分类&#xff1a; 2.2.1 按反馈的效果分&#xff1a; 2.2.2 按反馈量的类型分&#xff1a; 2.3 负反馈电路 2.3.1 负反馈电路…

反相、同相比例运算电路与基尔霍夫电流定律的关联分析

基尔霍夫电流定律&#xff08;KCL&#xff09; 在任一瞬间&#xff0c;流向任一结点的电流等于流出该结点的电流。 At any given moment, the current flowing into any node is equal to the current flowing out of it. 即&#xff1a; 或&#xff1a; 反相比例运算电路…

【电路与电子技术】笔记 (完结)

前言 是自己复习的笔记。截图是老师的课件。 大标题按章节来分。 跳过了很多东西。 2021.11.2回来补充&#xff0c;考完了&#xff0c;谢谢老师的4.0&#xff1b; 第一章 1.电路和电路模型 集总参数电路模型&#xff1a; 当实际电路的尺寸远小于其使用时最高工作频率所对应…

模电笔记4 半导体三极管及放大电路基础

4.1半导体三极管 4.1.1BJT的结构简介 结构特点&#xff1a; 、、- 表示掺杂浓度的高低 4.1.2放大状态下BJT的工作原理 发射结正偏&#xff0c;发射区向基区注入载流子&#xff0c;基区有了大量与原基区少数载流子相同极性的载流子&#xff0c;从而集电区收集到大量载流子&am…