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

article/2025/8/29 17:33:43

出自:http://www.cnblogs.com/skywang12345/p/3659060.html 

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

 

概要

本章介绍斐波那契堆。和以往一样,本文会先对斐波那契堆的理论知识进行简单介绍,然后给出C语言的实现。后续再分别给出C++和Java版本的实现;实现的语言虽不同,但是原理如出一辙,选择其中之一进行了解即可。若文章有错误或不足的地方,请不吝指出!

目录
1. 斐波那契堆的介绍
2. 斐波那契堆的基本操作
3. 斐波那契堆的C实现(完整源码)
4. 斐波那契堆的C测试程序

转载请注明出处:http://www.cnblogs.com/skywang12345/p/3659060.html


更多内容:数据结构与算法系列 目录

(01) 斐波那契堆(一)之 图文解析 和 C语言的实现 
(02) 斐波那契堆(二)之 C++的实现 
(03) 斐波那契堆(三)之 Java的实现

 

斐波那契堆的介绍

斐波那契堆(Fibonacci heap)是堆中一种,它和二项堆一样,也是一种可合并堆;可用于实现合并优先队列。斐波那契堆比二项堆具有更好的平摊分析性能,它的合并操作的时间复杂度是O(1)。
与二项堆一样,它也是由一组堆最小有序树组成,并且是一种可合并堆。
与二项堆不同的是,斐波那契堆中的树不一定是二项树;而且二项堆中的树是有序排列的,但是斐波那契堆中的树都是有根而无序的。

 

斐波那契堆的基本操作

1. 基本定义

复制代码
typedef int Type;typedef struct _FibonacciNode
{Type   key;                     // 关键字(键值)int degree;                     // 度数struct _FibonacciNode *left;    // 左兄弟struct _FibonacciNode *right;   // 右兄弟struct _FibonacciNode *child;   // 第一个孩子节点struct _FibonacciNode *parent;  // 父节点int marked;                     //是否被删除第1个孩子(1表示删除,0表示未删除)
}FibonacciNode, FibNode;
复制代码

FibNode是斐波那契堆的节点类,它包含的信息较多。key是用于比较节点大小的,degree是记录节点的度,left和right分别是指向节点的左右兄弟,child是节点的第一个孩子,parent是节点的父节点,marked是记录该节点是否被删除第1个孩子(marked在删除节点时有用)。

 

typedef struct _FibonacciHeap{int   keyNum;                   // 堆中节点的总数int   maxDegree;                // 最大度struct _FibonacciNode *min;     // 最小节点(某个最小堆的根节点)struct _FibonacciNode **cons;   // 最大度的内存区域
}FibonacciHeap, FibHeap;

FibHeap是斐波那契堆对应的类。min是保存当前堆的最小节点,keyNum用于记录堆中节点的总数,maxDegree用于记录堆中最大度,而cons在删除节点时来暂时保存堆数据的临时空间。

 

下面看看斐波那契堆的内存结构图。

从图中可以看出,斐波那契堆是由一组最小堆组成,这些最小堆的根节点组成了双向链表(后文称为"根链表");斐波那契堆中的最小节点就是"根链表中的最小节点"!

PS. 上面这幅图的结构和测试代码中的"基本信息"测试函数的结果是一致的;你可以通过测试程序来亲自验证!

 

2. 插入操作

插入操作非常简单:插入一个节点到堆中,直接将该节点插入到"根链表的min节点"之前即可;若被插入节点比"min节点"小,则更新"min节点"为被插入节点。

上面是插入操作的示意图。

斐波那契堆的根链表是"双向链表",这里将min节点看作双向联表的表头(后文也是如此)。在插入节点时,每次都是"将节点插入到min节点之前(即插入到双链表末尾)"。此外,对于根链表中最小堆都只有一个节点的情况,插入操作就很演化成双向链表的插入操作。

此外,插入操作示意图与测试程序中的"插入操作"相对应,感兴趣的可以亲自验证。

 

插入操作代码

复制代码
/** 将"单个节点node"加入"链表root"之前*   a …… root*   a …… node …… root** 注意: 此处node是单个节点,而root是双向链表
*/
static void fib_node_add(FibNode *node, FibNode *root)
{node->left        = root->left;root->left->right = node;node->right       = root;root->left        = node;
}/** 将节点node插入到斐波那契堆heap中*/
static void fib_heap_insert_node(FibHeap *heap, FibNode *node)
{if (heap->keyNum == 0)heap->min = node;else{fib_node_add(node, heap->min);if (node->key < heap->min->key)heap->min = node;}heap->keyNum++;
}
复制代码

 

3. 合并操作

合并操作和插入操作的原理非常类似:将一个堆的根链表插入到另一个堆的根链表上即可。简单来说,就是将两个双链表拼接成一个双向链表。

上面是合并操作的示意图。该操作示意图与测试程序中的"合并操作"相对应!

合并操作代码

复制代码
/** 将双向链表b链接到双向链表a的后面** 注意: 此处a和b都是双向链表
*/
static void fib_node_cat(FibNode *a, FibNode *b)
{FibNode *tmp;tmp            = a->right;a->right       = b->right;b->right->left = a;b->right       = tmp;tmp->left      = b;
}/** 将h1, h2合并成一个堆,并返回合并后的堆*/
FibHeap* fib_heap_union(FibHeap *h1, FibHeap *h2)
{FibHeap *tmp;if (h1==NULL)return h2;if (h2==NULL)return h1;// 以h1为"母",将h2附加到h1上;下面是保证h1的度数大,尽可能的少操作。if(h2->maxDegree > h1->maxDegree){tmp = h1;h1 = h2;h2 = tmp;}if((h1->min) == NULL)                // h1无"最小节点"
    {h1->min = h2->min;h1->keyNum = h2->keyNum;free(h2->cons);free(h2);}else if((h2->min) == NULL)           // h1有"最小节点" && h2无"最小节点"
    {free(h2->cons);free(h2);}                                   // h1有"最小节点" && h2有"最小节点"else{// 将"h2中根链表"添加到"h1"中fib_node_cat(h1->min, h2->min);if (h1->min->key > h2->min->key)h1->min = h2->min;h1->keyNum += h2->keyNum;free(h2->cons);free(h2);}return h1;
}
复制代码

 

4. 取出最小节点

抽取最小结点的操作是斐波那契堆中较复杂的操作。
(1)将要抽取最小结点的子树都直接串联在根表中;
(2)合并所有degree相等的树,直到没有相等的degree的树。

上面是取出最小节点的示意图。图中应该写的非常明白了,若有疑问,看代码。

此外,该操作示意图与测试程序中的"删除最小节点"相对应!有兴趣的可以亲自验证。

取出最小节点代码

复制代码
/** 移除最小节点,并返回移除节点后的斐波那契堆*/
FibNode* _fib_heap_extract_min(FibHeap *heap)
{if (heap==NULL || heap->min==NULL)return NULL;FibNode *child = NULL;FibNode *min = heap->min;// 将min每一个儿子(儿子和儿子的兄弟)都添加到"斐波那契堆的根链表"中while (min->child != NULL){child = min->child;fib_node_remove(child);if (child->right == child)min->child = NULL;elsemin->child = child->right;fib_node_add(child, heap->min);child->parent = NULL;}// 将min从根链表中移除
    fib_node_remove(min);// 若min是堆中唯一节点,则设置堆的最小节点为NULL;// 否则,设置堆的最小节点为一个非空节点(min->right),然后再进行调节。if (min->right == min)heap->min = NULL;else{heap->min = min->right;fib_heap_consolidate(heap);}heap->keyNum--;return min;
}
复制代码

其中fib_heap_consolidate(heap)的作用是合并斐波那契堆的根链表中相同度数的树,它的相关代码如下:

复制代码
 1 /*
 2  * 将node链接到root根结点
 3  */
 4 static void fib_heap_link(FibHeap * heap, FibNode * node, FibNode *root)
 5 {
 6     // 将node从双链表中移除
 7     fib_node_remove(node);
 8     // 将node设为root的孩子
 9     if (root->child == NULL)
10         root->child = node;
11     else
12         fib_node_add(node, root->child);
13 
14     node->parent = root;
15     root->degree++;
16     node->marked = 0;
17 }
18  
19 /* 
20  * 创建fib_heap_consolidate所需空间
21  */
22 static void fib_heap_cons_make(FibHeap * heap)
23 {
24     int old = heap->maxDegree;
25 
26     // 计算log2(x),"+1"意味着向上取整!
27     // ex. log2(13) = 3,向上取整为3+1=4。
28     heap->maxDegree = LOG2(heap->keyNum) + 1;
29 
30     // 如果原本空间不够,则再次分配内存
31     if (old >= heap->maxDegree)
32         return ;
33 
34     // 因为度为heap->maxDegree可能被合并,所以要maxDegree+1
35     heap->cons = (FibNode **)realloc(heap->cons, 
36             sizeof(FibHeap *) * (heap->maxDegree + 1));
37 }
38 
39 /* 
40  * 合并斐波那契堆的根链表中左右相同度数的树
41  */
42 static void fib_heap_consolidate(FibHeap *heap)
43 {
44     int i, d, D;
45     FibNode *x, *y, *tmp;
46 
47     fib_heap_cons_make(heap);//开辟哈希所用空间
48     D = heap->maxDegree + 1;
49 
50     for (i = 0; i < D; i++)
51         heap->cons[i] = NULL;
52  
53     // 合并相同度的根节点,使每个度数的树唯一
54     while (heap->min != NULL)
55     {
56         x = fib_heap_remove_min(heap);    // 取出堆中的最小树(最小节点所在的树)
57         d = x->degree;                    // 获取最小树的度数
58         // heap->cons[d] != NULL,意味着有两棵树(x和y)的"度数"相同。
59         while (heap->cons[d] != NULL)
60         {
61             y = heap->cons[d];            // y是"与x的度数相同的树" 
62             if (x->key > y->key)        // 保证x的键值比y小
63             {
64                 tmp = x;
65                 x = y;
66                 y = tmp;
67 
68             }
69             fib_heap_link(heap, y, x);    // 将y链接到x中
70             heap->cons[d] = NULL;
71             d++;
72         }
73         heap->cons[d] = x;
74     }
75     heap->min = NULL;
76  
77     // 将heap->cons中的结点重新加到根表中
78     for (i=0; i<D; i++)
79     {
80         if (heap->cons[i] != NULL)
81         {
82             if (heap->min == NULL)
83                 heap->min = heap->cons[i];
84             else
85             {
86                 fib_node_add(heap->cons[i], heap->min);
87                 if ((heap->cons[i])->key < heap->min->key)
88                     heap->min = heap->cons[i];
89             }
90         }
91     }
92 }
复制代码

 

5. 减小节点值

减少斐波那契堆中的节点的键值,这个操作的难点是:如果减少节点后破坏了"最小堆"性质,如何去维护呢?下面对一般性情况进行分析。
(1) 首先,将"被减小节点"从"它所在的最小堆"剥离出来;然后将"该节点"关联到"根链表"中。 倘若被减小的节点不是单独一个节点,而是包含子树的树根。则是将以"被减小节点"为根的子树从"最小堆"中剥离出来,然后将该树关联到根链表中。
(2) 接着,对"被减少节点"的原父节点进行"级联剪切"。所谓"级联剪切",就是在被减小节点破坏了最小堆性质,并被切下来之后;再从"它的父节点"进行递归级联剪切操作。
      而级联操作的具体动作则是:若父节点(被减小节点的父节点)的marked标记为false,则将其设为true,然后退出。
                                                          否则,将父节点从最小堆中切下来(方式和"切被减小节点的方式"一样);然后递归对祖父节点进行"级联剪切"。
      marked标记的作用就是用来标记"该节点的子节点是否有被删除过",它的作用是来实现级联剪切。而级联剪切的真正目的是为了防止"最小堆"由二叉树演化成链表。
(3) 最后,别忘了对根链表的最小节点进行更新。

上面是减小节点值的示意图。该操作示意图与测试程序中的"减小节点"相对应!

减小节点值的代码

复制代码
/* * 将斐波那契堆heap中节点node的值减少为key*/
static void fib_heap_decrease(FibHeap *heap, FibNode *node, Type key)
{FibNode *parent;if (heap==NULL || heap->min==NULL ||node==NULL) return ;if ( key>=node->key){printf("decrease failed: the new key(%d) is no smaller than current key(%d)\n", key, node->key);return ;}node->key = key;parent = node->parent;if (parent!=NULL && node->key < parent->key){// 将node从父节点parent中剥离出来,并将node添加到根链表中
        fib_heap_cut(heap, node, parent);fib_heap_cascading_cut(heap, parent);}// 更新最小节点if (node->key < heap->min->key)heap->min = node;
}
复制代码

其中,fib_heap_cut()和fib_heap_cascading_cut()的相关代码如下:

复制代码
 1 /* 
 2  * 将node从父节点parent的子链接中剥离出来,
 3  * 并使node成为"堆的根链表"中的一员。
 4  */
 5 static void fib_heap_cut(FibHeap *heap, FibNode *node, FibNode *parent)
 6 {
 7     fib_node_remove(node);
 8     renew_degree(parent, node->degree);
 9     // node没有兄弟
10     if (node == node->right) 
11         parent->child = NULL;
12     else 
13         parent->child = node->right;
14 
15     node->parent = NULL;
16     node->left = node->right = node;
17     node->marked = 0;
18     // 将"node所在树"添加到"根链表"中
19     fib_node_add(node, heap->min);
20 }
21 
22 /* 
23  * 对节点node进行"级联剪切"
24  *
25  * 级联剪切:如果减小后的结点破坏了最小堆性质,
26  *     则把它切下来(即从所在双向链表中删除,并将
27  *     其插入到由最小树根节点形成的双向链表中),
28  *     然后再从"被切节点的父节点"到所在树根节点递归执行级联剪枝
29  */
30 static void fib_heap_cascading_cut(FibHeap *heap, FibNode *node) 
31 {
32     FibNode *parent = node->parent;
33     if (parent != NULL)
34         return ;
35 
36     if (node->marked == 0) 
37         node->marked = 1;
38     else
39     {
40         fib_heap_cut(heap, node, parent);
41         fib_heap_cascading_cut(heap, parent);
42     }
43 }
复制代码

 

6. 增加节点值

增加节点值和减少节点值类似,这个操作的难点也是如何维护"最小堆"性质。思路如下:
(1) 将"被增加节点"的"左孩子和左孩子的所有兄弟"都链接到根链表中。
(2) 接下来,把"被增加节点"添加到根链表;但是别忘了对其进行级联剪切。

上面是增加节点值的示意图。该操作示意图与测试程序中的"增大节点"相对应!

增加节点值的代码

复制代码
/* * 将斐波那契堆heap中节点node的值增加为key*/
static void fib_heap_increase(FibHeap *heap, FibNode *node, Type key)
{FibNode *child, *parent, *right;if (heap==NULL || heap->min==NULL ||node==NULL) return ;if (key <= node->key){printf("increase failed: the new key(%d) is no greater than current key(%d)\n", key, node->key);return ;}// 将node每一个儿子(不包括孙子,重孙,...)都添加到"斐波那契堆的根链表"中while (node->child != NULL){child = node->child;fib_node_remove(child);               // 将child从node的子链表中删除if (child->right == child)node->child = NULL;elsenode->child = child->right;fib_node_add(child, heap->min);       // 将child添加到根链表中child->parent = NULL;}node->degree = 0;node->key = key;// 如果node不在根链表中,//     则将node从父节点parent的子链接中剥离出来,//     并使node成为"堆的根链表"中的一员,//     然后进行"级联剪切"// 否则,则判断是否需要更新堆的最小节点parent = node->parent;if(parent != NULL){fib_heap_cut(heap, node, parent);fib_heap_cascading_cut(heap, parent);}else if(heap->min == node){right = node->right;while(right != node){if(node->key > right->key)heap->min = right;right = right->right;}}
}
复制代码

 

7. 删除节点

删除节点,本文采用了操作是:"取出最小节点"和"减小节点值"的组合。
(1) 先将被删除节点的键值减少。减少后的值要比"原最小节点的值"即可。
(2) 接着,取出最小节点即可。

删除节点值的代码

复制代码
/** 删除结点node*/
static void _fib_heap_delete(FibHeap *heap, FibNode *node)
{Type min = heap->min->key;fib_heap_decrease(heap, node, min-1);_fib_heap_extract_min(heap);free(node);
}
复制代码


注意:关于斐波那契堆的"更新"、"打印"、"销毁"等接口就不再单独介绍了。后文的源码中有给出它们的实现代码,Please RTFSC(Read The Fucking Source Code)!

 

斐波那契堆的C实现(完整源码)

斐波那契堆的头文件(fibonacci_heap.h)

复制代码
 1 #ifndef _FIBONACCI_HEAP_H_
 2 #define _FIBONACCI_HEAP_H_
 3 
 4 typedef int Type;
 5 
 6 typedef struct _FibonacciNode
 7 {
 8     Type   key;                        // 关键字(键值)
 9     int degree;                        // 度数
10     struct _FibonacciNode *left;    // 左兄弟
11     struct _FibonacciNode *right;    // 右兄弟
12     struct _FibonacciNode *child;    // 第一个孩子节点
13     struct _FibonacciNode *parent;    // 父节点
14     int marked;                       //是否被删除第1个孩子(1表示删除,0表示未删除)
15 }FibonacciNode, FibNode;
16 
17 typedef struct _FibonacciHeap{
18     int   keyNum;                    // 堆中节点的总数
19     int   maxDegree;                // 最大度
20     struct _FibonacciNode *min;        // 最小节点(某个最小堆的根节点)
21     struct _FibonacciNode **cons;    // 最大度的内存区域
22 }FibonacciHeap, FibHeap;
23 
24 // 创建Fibonacci堆
25 FibHeap* fib_heap_make();
26 // 新建键值为key的节点,并将其插入到斐波那契堆中
27 void fib_heap_insert_key(FibHeap *heap, Type key);
28 // 删除键值为key的结点
29 void fib_heap_delete(FibHeap *heap, Type key);
30 // 移除最小节点
31 void fib_heap_extract_min(FibHeap *heap);
32 // 更新heap的中的oldkey为newkey
33 void fib_heap_update(FibHeap *heap, Type oldkey, Type newkey);
34 // 将h1, h2合并成一个堆,并返回合并后的堆
35 FibHeap* fib_heap_union(FibHeap *h1, FibHeap *h2);
36 // 在斐波那契堆heap中是否存在键值为key的节点;存在返回1,否则返回0。
37 int fib_heap_contains(FibHeap *heap, Type key);
38 // 获取最小节点对应的值(保存在pkey中);成功返回1,失败返回0。
39 int fib_heap_get_min(FibHeap *heap, Type *pkey);
40 // 销毁斐波那契堆
41 void fib_heap_destroy(FibHeap *heap);
42 // 打印"斐波那契堆"
43 void fib_print(FibHeap *heap);
44 
45 #endif
复制代码

斐波那契堆的实现文件(fibonacci_heap.c)

复制代码
  1 /**
  2  * C语言实现的斐波那契堆
  3  *
  4  * @author skywang
  5  * @date 2014/04/05
  6  */
  7 
  8 #include <stdio.h>
  9 #include <stdlib.h>
 10 #include <math.h>
 11 #include <float.h>
 12 #include "fibonacci_heap.h"
 13 
 14 #if 0
 15 #define LOG2(x) ({ \
 16         unsigned int _i = 0; \
 17         __asm__("bsr %1, %0" : "=r" (_i) : "r" ((x))); \
 18         _i; })
 19 #else   // 注意:通过gcc编译时,要添加 -lm 选项。
 20 #define LOG2(x) ((log((double)(x))) / (log(2.0)))
 21 #endif
 22 
 23 
 24 static FibNode *fib_heap_search(FibHeap *heap, Type key);
 25  
 26 /* 
 27  * 将node从双链表移除
 28  */
 29 static void fib_node_remove(FibNode *node)
 30 {
 31     node->left->right = node->right;
 32     node->right->left = node->left;
 33 }
 34  
 35 /*
 36  * 将"单个节点node"加入"链表root"之前
 37  *   a …… root
 38  *   a …… node …… root
 39  *
 40  * 注意: 此处node是单个节点,而root是双向链表
 41 */
 42 static void fib_node_add(FibNode *node, FibNode *root)
 43 {
 44     node->left        = root->left;
 45     root->left->right = node;
 46     node->right       = root;
 47     root->left        = node;
 48 }
 49 
 50 /*
 51  * 将双向链表b链接到双向链表a的后面
 52  *
 53  * 注意: 此处a和b都是双向链表
 54 */
 55 static void fib_node_cat(FibNode *a, FibNode *b)
 56 {
 57     FibNode *tmp;
 58 
 59     tmp            = a->right;
 60     a->right       = b->right;
 61     b->right->left = a;
 62     b->right       = tmp;
 63     tmp->left      = b;
 64 }
 65 
 66  
 67 /*
 68  * 创建斐波那契堆
 69  */
 70 FibHeap* fib_heap_make()
 71 {
 72     FibHeap* heap;
 73 
 74     heap = (FibHeap *) malloc(sizeof(FibHeap));
 75     if (heap == NULL)
 76     {
 77         printf("Error: make FibHeap failed\n");
 78         return NULL;
 79     }
 80 
 81     heap->keyNum = 0;
 82     heap->maxDegree = 0;
 83     heap->min = NULL;
 84     heap->cons = NULL;
 85 
 86     return heap;
 87 }
 88  
 89 /*
 90  * 创建斐波那契堆的节点
 91  */
 92 static FibNode* fib_node_make(Type key)
 93 {
 94     FibNode * node;
 95 
 96     node = (FibNode *) malloc(sizeof(FibNode));
 97     if (node == NULL)
 98     {
 99         printf("Error: make Node failed\n");
100         return NULL;
101     }
102     node->key    = key;
103     node->degree = 0;
104     node->left   = node;
105     node->right  = node;
106     node->parent = NULL;
107     node->child  = NULL;
108 
109     return node;
110 }
111  
112 /*
113  * 将节点node插入到斐波那契堆heap中
114  */
115 static void fib_heap_insert_node(FibHeap *heap, FibNode *node)
116 {
117     if (heap->keyNum == 0)
118         heap->min = node;
119     else
120        {
121         fib_node_add(node, heap->min);
122         if (node->key < heap->min->key)
123             heap->min = node;
124     }
125     heap->keyNum++;
126 }
127  
128 /* 
129  * 新建键值为key的节点,并将其插入到斐波那契堆中
130  */
131 void fib_heap_insert_key(FibHeap *heap, Type key)
132 {
133     FibNode *node;
134 
135     if (heap==NULL)
136         return ;
137 
138     node = fib_node_make(key);
139     if (node == NULL)
140         return ;
141 
142     fib_heap_insert_node(heap, node);
143 }
144   
145 /*
146  * 将h1, h2合并成一个堆,并返回合并后的堆
147  */
148 FibHeap* fib_heap_union(FibHeap *h1, FibHeap *h2)
149 {
150     FibHeap *tmp;
151 
152     if (h1==NULL)
153         return h2;
154     if (h2==NULL)
155         return h1;
156 
157     // 以h1为"母",将h2附加到h1上;下面是保证h1的度数大,尽可能的少操作。
158     if(h2->maxDegree > h1->maxDegree)
159     {
160         tmp = h1;
161         h1 = h2;
162         h2 = tmp;
163     }
164 
165     if((h1->min) == NULL)                // h1无"最小节点"
166     {
167         h1->min = h2->min;
168         h1->keyNum = h2->keyNum;
169         free(h2->cons);
170         free(h2);
171     }
172     else if((h2->min) == NULL)           // h1有"最小节点" && h2无"最小节点"
173     {
174         free(h2->cons);
175         free(h2);
176     }                                   // h1有"最小节点" && h2有"最小节点"
177     else
178     {
179         // 将"h2中根链表"添加到"h1"中
180         fib_node_cat(h1->min, h2->min);
181         if (h1->min->key > h2->min->key)
182             h1->min = h2->min;
183         h1->keyNum += h2->keyNum;
184         free(h2->cons);
185         free(h2);
186     }
187 
188     return h1;
189 }
190 
191 /*
192  * 将"堆的最小结点"从根链表中移除,
193  * 这意味着"将最小节点所属的树"从堆中移除!
194  */
195 static FibNode *fib_heap_remove_min(FibHeap *heap)
196 {
197     FibNode *min = heap->min;
198 
199     if (heap->min == min->right)
200         heap->min = NULL;
201     else
202     {
203         fib_node_remove(min);
204         heap->min = min->right;
205     }
206     min->left = min->right = min;
207 
208     return min;
209 }
210  
211 /*
212  * 将node链接到root根结点
213  */
214 static void fib_heap_link(FibHeap * heap, FibNode * node, FibNode *root)
215 {
216     // 将node从双链表中移除
217     fib_node_remove(node);
218     // 将node设为root的孩子
219     if (root->child == NULL)
220         root->child = node;
221     else
222         fib_node_add(node, root->child);
223 
224     node->parent = root;
225     root->degree++;
226     node->marked = 0;
227 }
228  
229 /* 
230  * 创建fib_heap_consolidate所需空间
231  */
232 static void fib_heap_cons_make(FibHeap * heap)
233 {
234     int old = heap->maxDegree;
235 
236     // 计算log2(x),"+1"意味着向上取整!
237     // ex. log2(13) = 3,向上取整为3+1=4。
238     heap->maxDegree = LOG2(heap->keyNum) + 1;
239 
240     // 如果原本空间不够,则再次分配内存
241     if (old >= heap->maxDegree)
242         return ;
243 
244     // 因为度为heap->maxDegree可能被合并,所以要maxDegree+1
245     heap->cons = (FibNode **)realloc(heap->cons, 
246             sizeof(FibHeap *) * (heap->maxDegree + 1));
247 }
248 
249 /* 
250  * 合并斐波那契堆的根链表中左右相同度数的树
251  */
252 static void fib_heap_consolidate(FibHeap *heap)
253 {
254     int i, d, D;
255     FibNode *x, *y, *tmp;
256 
257     fib_heap_cons_make(heap);//开辟哈希所用空间
258     D = heap->maxDegree + 1;
259 
260     for (i = 0; i < D; i++)
261         heap->cons[i] = NULL;
262  
263     // 合并相同度的根节点,使每个度数的树唯一
264     while (heap->min != NULL)
265     {
266         x = fib_heap_remove_min(heap);    // 取出堆中的最小树(最小节点所在的树)
267         d = x->degree;                    // 获取最小树的度数
268         // heap->cons[d] != NULL,意味着有两棵树(x和y)的"度数"相同。
269         while (heap->cons[d] != NULL)
270         {
271             y = heap->cons[d];            // y是"与x的度数相同的树" 
272             if (x->key > y->key)        // 保证x的键值比y小
273             {
274                 tmp = x;
275                 x = y;
276                 y = tmp;
277 
278             }
279             fib_heap_link(heap, y, x);    // 将y链接到x中
280             heap->cons[d] = NULL;
281             d++;
282         }
283         heap->cons[d] = x;
284     }
285     heap->min = NULL;
286  
287     // 将heap->cons中的结点重新加到根表中
288     for (i=0; i<D; i++)
289     {
290         if (heap->cons[i] != NULL)
291         {
292             if (heap->min == NULL)
293                 heap->min = heap->cons[i];
294             else
295             {
296                 fib_node_add(heap->cons[i], heap->min);
297                 if ((heap->cons[i])->key < heap->min->key)
298                     heap->min = heap->cons[i];
299             }
300         }
301     }
302 }
303  
304 /*
305  * 移除最小节点,并返回移除节点后的斐波那契堆
306  */
307 FibNode* _fib_heap_extract_min(FibHeap *heap)
308 {
309     if (heap==NULL || heap->min==NULL)
310         return NULL;
311 
312     FibNode *child = NULL;
313     FibNode *min = heap->min;
314     // 将min每一个儿子(儿子和儿子的兄弟)都添加到"斐波那契堆的根链表"中
315     while (min->child != NULL)
316     {
317         child = min->child;
318         fib_node_remove(child);
319         if (child->right == child)
320             min->child = NULL;
321         else
322             min->child = child->right;
323 
324         fib_node_add(child, heap->min);
325         child->parent = NULL;
326     }
327 
328     // 将min从根链表中移除
329     fib_node_remove(min);
330     // 若min是堆中唯一节点,则设置堆的最小节点为NULL;
331     // 否则,设置堆的最小节点为一个非空节点(min->right),然后再进行调节。
332     if (min->right == min)
333         heap->min = NULL;
334     else
335     {
336         heap->min = min->right;
337         fib_heap_consolidate(heap);
338     }
339     heap->keyNum--;
340 
341     return min;
342 }
343 
344 void fib_heap_extract_min(FibHeap *heap)
345 {
346     FibNode *node;
347 
348     if (heap==NULL || heap->min==NULL)
349         return ;
350 
351     node = _fib_heap_extract_min(heap);
352     if (node!=NULL)
353         free(node);
354 }
355 
356 /*
357  * 在斐波那契堆heap中是否存在键值为key的节点;存在返回1,否则返回0。
358  */
359 int fib_heap_get_min(FibHeap *heap, Type *pkey)
360 {
361     if (heap==NULL || heap->min==NULL || pkey==NULL)
362         return 0;
363 
364     *pkey = heap->min->key;
365     return 1;
366 }
367   
368 /* 
369  * 修改度数
370  */
371 static void renew_degree(FibNode *parent, int degree)
372 {
373     parent->degree -= degree;
374     if (parent-> parent != NULL)
375         renew_degree(parent->parent, degree);
376 }
377  
378 /* 
379  * 将node从父节点parent的子链接中剥离出来,
380  * 并使node成为"堆的根链表"中的一员。
381  */
382 static void fib_heap_cut(FibHeap *heap, FibNode *node, FibNode *parent)
383 {
384     fib_node_remove(node);
385     renew_degree(parent, node->degree);
386     // node没有兄弟
387     if (node == node->right) 
388         parent->child = NULL;
389     else 
390         parent->child = node->right;
391 
392     node->parent = NULL;
393     node->left = node->right = node;
394     node->marked = 0;
395     // 将"node所在树"添加到"根链表"中
396     fib_node_add(node, heap->min);
397 }
398 
399 /* 
400  * 对节点node进行"级联剪切"
401  *
402  * 级联剪切:如果减小后的结点破坏了最小堆性质,
403  *     则把它切下来(即从所在双向链表中删除,并将
404  *     其插入到由最小树根节点形成的双向链表中),
405  *     然后再从"被切节点的父节点"到所在树根节点递归执行级联剪枝
406  */
407 static void fib_heap_cascading_cut(FibHeap *heap, FibNode *node) 
408 {
409     FibNode *parent = node->parent;
410     if (parent != NULL)
411         return ;
412 
413     if (node->marked == 0) 
414         node->marked = 1;
415     else
416     {
417         fib_heap_cut(heap, node, parent);
418         fib_heap_cascading_cut(heap, parent);
419     }
420 }
421 
422 /* 
423  * 将斐波那契堆heap中节点node的值减少为key
424  */
425 static void fib_heap_decrease(FibHeap *heap, FibNode *node, Type key)
426 {
427     FibNode *parent;
428 
429     if (heap==NULL || heap->min==NULL ||node==NULL) 
430         return ;
431 
432     if ( key>=node->key)
433     {
434         printf("decrease failed: the new key(%d) is no smaller than current key(%d)\n", key, node->key);
435         return ;
436     }
437 
438     node->key = key;
439     parent = node->parent;
440     if (parent!=NULL && node->key < parent->key)
441     {
442         // 将node从父节点parent中剥离出来,并将node添加到根链表中
443         fib_heap_cut(heap, node, parent);
444         fib_heap_cascading_cut(heap, parent);
445     }
446 
447     // 更新最小节点
448     if (node->key < heap->min->key)
449         heap->min = node;
450 }
451 
452 /* 
453  * 将斐波那契堆heap中节点node的值增加为key
454  */
455 static void fib_heap_increase(FibHeap *heap, FibNode *node, Type key)
456 {
457     FibNode *child, *parent, *right;
458 
459     if (heap==NULL || heap->min==NULL ||node==NULL) 
460         return ;
461 
462     if (key <= node->key)
463     {
464         printf("increase failed: the new key(%d) is no greater than current key(%d)\n", key, node->key);
465         return ;
466     }
467 
468     // 将node每一个儿子(不包括孙子,重孙,...)都添加到"斐波那契堆的根链表"中
469     while (node->child != NULL)
470     {
471         child = node->child;
472         fib_node_remove(child);               // 将child从node的子链表中删除
473         if (child->right == child)
474             node->child = NULL;
475         else
476             node->child = child->right;
477 
478         fib_node_add(child, heap->min);       // 将child添加到根链表中
479         child->parent = NULL;
480     }
481     node->degree = 0;
482     node->key = key;
483 
484     // 如果node不在根链表中,
485     //     则将node从父节点parent的子链接中剥离出来,
486     //     并使node成为"堆的根链表"中的一员,
487     //     然后进行"级联剪切"
488     // 否则,则判断是否需要更新堆的最小节点
489     parent = node->parent;
490     if(parent != NULL)
491     {
492         fib_heap_cut(heap, node, parent);
493         fib_heap_cascading_cut(heap, parent);
494     }
495     else if(heap->min == node)
496     {
497         right = node->right;
498         while(right != node)
499         {
500             if(node->key > right->key)
501                 heap->min = right;
502             right = right->right;
503         }
504     }
505 }
506 
507 /* 
508  * 更新二项堆heap的节点node的键值为key
509  */
510 void _fib_heap_update(FibHeap *heap, FibNode *node, Type key)
511 {
512     if(key < node->key)
513         fib_heap_decrease(heap, node, key);
514     else if(key > node->key)
515         fib_heap_increase(heap, node, key);
516     else
517         printf("No need to update!!!\n");
518 }
519   
520 void fib_heap_update(FibHeap *heap, Type oldkey, Type newkey)
521 {
522     FibNode *node;
523 
524     if (heap==NULL)
525         return ;
526 
527     node = fib_heap_search(heap, oldkey);
528     if (node!=NULL)
529         _fib_heap_update(heap, node, newkey);
530 }
531 
532 /*
533  * 在最小堆root中查找键值为key的节点
534  */
535 static FibNode* fib_node_search(FibNode *root, Type key)
536 {
537     FibNode *t = root;    // 临时节点
538     FibNode *p = NULL;    // 要查找的节点
539 
540     if (root==NULL)
541         return root;
542 
543     do
544     {
545         if (t->key == key)
546         {
547             p = t;
548             break;
549         } 
550         else
551         {
552             if ((p = fib_node_search(t->child, key)) != NULL) 
553                 break;
554         }    
555         t = t->right;
556     } while (t != root);
557 
558     return p;
559 }
560  
561 /*
562  * 在斐波那契堆heap中查找键值为key的节点
563  */
564 static FibNode *fib_heap_search(FibHeap *heap, Type key)
565 {
566     if (heap==NULL || heap->min==NULL)
567         return NULL;
568 
569     return fib_node_search(heap->min, key);
570 }
571 
572 /*
573  * 在斐波那契堆heap中是否存在键值为key的节点。
574  * 存在返回1,否则返回0。
575  */
576 int fib_heap_contains(FibHeap *heap, Type key)
577 {
578     return fib_heap_search(heap,key)!=NULL ? 1: 0;
579 }
580 
581 /*
582  * 删除结点node
583  */
584 static void _fib_heap_delete(FibHeap *heap, FibNode *node)
585 {
586     Type min = heap->min->key;
587     fib_heap_decrease(heap, node, min-1);
588     _fib_heap_extract_min(heap);
589     free(node);
590 }
591 
592 void fib_heap_delete(FibHeap *heap, Type key)
593 {
594     FibNode *node;
595 
596     if (heap==NULL || heap->min==NULL)
597         return ;
598 
599     node = fib_heap_search(heap, key);
600     if (node==NULL)
601         return ;
602 
603     _fib_heap_delete(heap, node);
604 }
605  
606 /* 
607  * 销毁斐波那契堆
608  */
609 static void fib_node_destroy(FibNode *node)
610 {
611     FibNode *start = node;
612 
613     if(node == NULL)
614         return;
615 
616     do {
617         fib_node_destroy(node->child);
618         // 销毁node,并将node指向下一个
619         node = node->right;
620         free(node->left);
621     } while(node != start);
622 }
623  
624 void fib_heap_destroy(FibHeap *heap)
625 {
626     fib_node_destroy(heap->min);
627     free(heap->cons);
628     free(heap);
629 }
630 
631 /*
632  * 打印"斐波那契堆"
633  *
634  * 参数说明:
635  *     node       -- 当前节点
636  *     prev       -- 当前节点的前一个节点(父节点or兄弟节点)
637  *     direction  --  1,表示当前节点是一个左孩子;
638  *                    2,表示当前节点是一个兄弟节点。
639  */
640 static void _fib_print(FibNode *node, FibNode *prev, int direction)
641 {
642     FibonacciNode *start=node;
643 
644     if (node==NULL)
645         return ;
646     do
647     {
648         if (direction == 1)
649             printf("%8d(%d) is %2d's child\n", node->key, node->degree, prev->key);
650         else
651             printf("%8d(%d) is %2d's next\n", node->key, node->degree, prev->key);
652 
653         if (node->child != NULL)
654             _fib_print(node->child, node, 1);
655 
656         // 兄弟节点
657         prev = node;
658         node = node->right;
659         direction = 2;
660     } while(node != start);
661 }
662 
663 void fib_print(FibHeap *heap)
664 {
665     int i=0;
666     FibonacciNode *p;
667 
668     if (heap==NULL || heap->min==NULL)
669         return ;
670 
671     printf("== 斐波那契堆的详细信息: ==\n");
672     p = heap->min;
673     do {
674         i++;
675         printf("%2d. %4d(%d) is root\n", i, p->key, p->degree);
676 
677         _fib_print(p->child, p, 1);
678         p = p->right;
679     } while (p != heap->min);
680     printf("\n");
681 }
复制代码

斐波那契堆的测试程序(main.c)

复制代码
  1 /**
  2  * C语言实现的斐波那契堆
  3  *
  4  * @author skywang
  5  * @date 2014/04/06
  6  */
  7 
  8 #include <stdio.h>
  9 #include "fibonacci_heap.h"
 10 
 11 #define DEBUG 0
 12 
 13 #if DEBUG
 14 #define log(x, ...)   printf(x, __VA_ARGS__)
 15 #else
 16 #define log(x, ...)   
 17 #endif
 18 
 19 #define LENGTH(a) ( (sizeof(a)) / (sizeof(a[0])) )
 20 
 21 // 共8个
 22 int a[] = {12,  7, 25, 15, 28, 
 23            33, 41, 1};
 24 // 共14个
 25 int b[] = {18, 35, 20, 42,  9, 
 26            31, 23,  6, 48, 11, 
 27            24, 52, 13, 2};
 28 
 29 // 验证"基本信息(斐波那契堆的结构)"
 30 void test_basic()
 31 {
 32     int i;
 33     int blen=LENGTH(b);
 34     FibHeap *hb = fib_heap_make();
 35 
 36     // 斐波那契堆hb
 37     printf("== 斐波那契堆(hb)中依次添加: ");
 38     for(i=0; i<blen; i++)
 39     {
 40         printf("%d ", b[i]);
 41         fib_heap_insert_key(hb, b[i]);
 42     }
 43     printf("\n");
 44     printf("== 斐波那契堆(hb)删除最小节点\n");
 45     fib_heap_extract_min(hb);
 46     fib_print(hb);
 47 
 48     fib_heap_destroy(hb);
 49 }
 50 
 51 // 验证"插入操作"
 52 void test_insert()
 53 {
 54     int i;
 55     int alen=LENGTH(a);
 56     FibHeap *ha = fib_heap_make();
 57 
 58     // 斐波那契堆ha
 59     printf("== 斐波那契堆(ha)中依次添加: ");
 60 
 61     for(i=0; i<alen; i++)
 62     {
 63         printf("%d ", a[i]);
 64         fib_heap_insert_key(ha, a[i]);
 65     }
 66     printf("\n");
 67     printf("== 斐波那契堆(ha)删除最小节点\n");
 68     fib_heap_extract_min(ha);
 69     fib_print(ha);
 70 
 71     // 插入50
 72     printf("== 插入50\n");
 73     fib_heap_insert_key(ha, 50);
 74     fib_print(ha);
 75 
 76     fib_heap_destroy(ha);
 77 }
 78 
 79 // 验证"合并操作"
 80 void test_union()
 81 {
 82     int i;
 83     int alen=LENGTH(a);
 84     int blen=LENGTH(b);
 85     FibHeap *ha = fib_heap_make();
 86     FibHeap *hb = fib_heap_make();
 87 
 88     // 斐波那契堆ha
 89     printf("== 斐波那契堆(ha)中依次添加: ");
 90 
 91     for(i=0; i<alen; i++)
 92     {
 93         printf("%d ", a[i]);
 94         fib_heap_insert_key(ha, a[i]);
 95     }
 96     printf("\n");
 97     printf("== 斐波那契堆(ha)删除最小节点\n");
 98     fib_heap_extract_min(ha);
 99     fib_print(ha);
100 
101     // 斐波那契堆hb
102     printf("== 斐波那契堆(hb)中依次添加: ");
103     for(i=0; i<blen; i++)
104     {
105         printf("%d ", b[i]);
106         fib_heap_insert_key(hb, b[i]);
107     }
108     printf("\n");
109     printf("== 斐波那契堆(hb)删除最小节点\n");
110     fib_heap_extract_min(hb);
111     fib_print(hb);
112 
113     // 将"斐波那契堆hb"合并到"斐波那契堆ha"中。
114     printf("== 合并ha和hb\n");
115     ha = fib_heap_union(ha, hb);
116     fib_print(ha);
117 
118     // 销毁堆
119     fib_heap_destroy(ha);
120 }
121 
122 // 验证"删除最小节点"
123 void test_remove_min()
124 {
125     int i;
126     int alen=LENGTH(a);
127     int blen=LENGTH(b);
128     FibHeap *ha = fib_heap_make();
129     FibHeap *hb = fib_heap_make();
130 
131     // 斐波那契堆ha
132     printf("== 斐波那契堆(ha)中依次添加: ");
133 
134     for(i=0; i<alen; i++)
135     {
136         printf("%d ", a[i]);
137         fib_heap_insert_key(ha, a[i]);
138     }
139     printf("\n");
140     printf("== 斐波那契堆(ha)删除最小节点\n");
141     fib_heap_extract_min(ha);
142     //fib_print(ha);
143 
144     // 斐波那契堆hb
145     printf("== 斐波那契堆(hb)中依次添加: ");
146     for(i=0; i<blen; i++)
147     {
148         printf("%d ", b[i]);
149         fib_heap_insert_key(hb, b[i]);
150     }
151     printf("\n");
152     printf("== 斐波那契堆(hb)删除最小节点\n");
153     fib_heap_extract_min(hb);
154     //fib_print(hb);
155 
156     // 将"斐波那契堆hb"合并到"斐波那契堆ha"中。
157     printf("== 合并ha和hb\n");
158     ha = fib_heap_union(ha, hb);
159     fib_print(ha);
160 
161     printf("== 删除最小节点\n");
162     fib_heap_extract_min(ha);
163     fib_print(ha);
164 
165     // 销毁堆
166     fib_heap_destroy(ha);
167 }
168 
169 // 验证"减小节点"
170 void test_decrease()
171 {
172     int i;
173     int blen=LENGTH(b);
174     FibHeap *hb = fib_heap_make();
175 
176     // 斐波那契堆hb
177     printf("== 斐波那契堆(hb)中依次添加: ");
178     for(i=0; i<blen; i++)
179     {
180         printf("%d ", b[i]);
181         fib_heap_insert_key(hb, b[i]);
182     }
183     printf("\n");
184     printf("== 斐波那契堆(hb)删除最小节点\n");
185     fib_heap_extract_min(hb);
186     fib_print(hb);
187 
188     printf("== 将20减小为2\n");
189     fib_heap_update(hb, 20, 2);
190     fib_print(hb);
191 
192     fib_heap_destroy(hb);
193 }
194 
195 // 验证"增大节点"
196 void test_increase()
197 {
198     int i;
199     int blen=LENGTH(b);
200     FibHeap *hb = fib_heap_make();
201 
202     // 斐波那契堆hb
203     printf("== 斐波那契堆(hb)中依次添加: ");
204     for(i=0; i<blen; i++)
205     {
206         printf("%d ", b[i]);
207         fib_heap_insert_key(hb, b[i]);
208     }
209     printf("\n");
210     printf("== 斐波那契堆(hb)删除最小节点\n");
211     fib_heap_extract_min(hb);
212     fib_print(hb);
213 
214     fib_heap_update(hb, 20, 60);
215     printf("== 将20增加为60\n");
216     fib_print(hb);
217 
218     fib_heap_destroy(hb);
219 }
220 
221 // 验证"删除节点"
222 void test_delete()
223 {
224     int i;
225     int blen=LENGTH(b);
226     FibHeap *hb = fib_heap_make();
227 
228     // 斐波那契堆hb
229     printf("== 斐波那契堆(hb)中依次添加: ");
230     for(i=0; i<blen; i++)
231     {
232         printf("%d ", b[i]);
233         fib_heap_insert_key(hb, b[i]);
234     }
235     printf("\n");
236     printf("== 斐波那契堆(hb)删除最小节点\n");
237     fib_heap_extract_min(hb);
238     fib_print(hb);
239 
240     fib_heap_delete(hb, 20);
241     printf("== 删除节点20\n");
242     fib_print(hb);
243 
244     fib_heap_destroy(hb);
245 }
246 
247 void main()
248 {
249     // 验证"基本信息(斐波那契堆的结构)"
250     test_basic();
251     // 验证"插入操作"
252     //test_insert();
253     // 验证"合并操作"
254     //test_union();
255     // 验证"删除最小节点"
256     //test_remove_min();
257     // 验证"减小节点"
258     //test_decrease();
259     // 验证"增大节点"
260     //test_increase();
261     // 验证"删除节点"
262     //test_delete();
263 }
复制代码

 

斐波那契堆的C测试程序

斐波那契堆的测试程序包括了"插入"、"合并"、"增大"、"减小"、"删除"、"基本信息"等几种功能的测试代码。默认是运行的"基本信息(验证斐波那契堆的结构)"测试代码,你可以根据自己的需要来对相应的功能进行验证!

注意:C语言版的斐波那契堆的LOG2宏定义中使用了math.h,记得引入math库。例如,若你是在Linux下通过gcc编译,记得添加-lm参数(gcc *.c -lm)。

下面是基本信息测试代码的运行结果:

复制代码
== 斐波那契堆(hb)中依次添加: 18 35 20 42 9 31 23 6 48 11 24 52 13 2 
== 斐波那契堆(hb)删除最小节点
== 斐波那契堆的详细信息: ==1.    6(3) is root9(0) is  6's child18(1) is  9's next35(0) is 18's child20(2) is 18's next42(0) is 20's child23(1) is 42's next31(0) is 23's child2.   11(2) is root48(0) is 11's child24(1) is 48's next52(0) is 24's child3.   13(0) is root
复制代码


http://chatgpt.dhexx.cn/article/0CcLi1hJ.shtml

相关文章

斐波那契堆的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…

双极型晶体管及其放大电路

双极型晶体管及其放大电路 半导体基本特性.双极型晶体管结构与工作原理工作组态与性质 放大电路放大电路基础知识基本共射放大电路的工作原理与分析方法图解法分析:等效电路法 静态工作点稳定问题稳定原理静态工作点计算交流指标的计算 晶体单管放大电路三种组态共集放大电路共…

多级放大电路超详细分析

多级放大电路多由共射、共基、共集电路组成。我们通过将电路分别分析来计算放大倍数。 并且对于三大基本电路的放大倍数计算方法需要熟练掌握 共射 共集 共基 多级放大倍数分析 多级放大电路分析 第一题 2. 若信号经电路一放大后&#xff0c;再经电路二输出 第二级电路静态工…

关于百钱百鸡问题的简易算法表示

我国古代数学家张丘建在《算经》一书中提出的数学问题&#xff1a;鸡翁一值钱五&#xff0c;鸡母一值钱三&#xff0c;鸡雏三值钱一。百钱买百鸡&#xff0c;问鸡翁、鸡母、鸡雏各几何&#xff1f; 代码如下&#xff1a; int x 0,y 0,z 0; for(x 0;x<20;x){ if((100-7*…