数据结构与算法基础-学习-26-图之MST(最小代价生成树)之Kluskal(克鲁斯卡尔)算法

news2024/12/26 11:25:45

最小生成树的概念、源码实现和Prim(普利姆)算法的概念和源码实现请参考之前的博客:《数据结构与算法基础-学习-25-图之MST(最小代价生成树)之Prim(普利姆)算法》

一、算法思路

Kluskal算法相较于Prim算法选择的是边,我们还是以之前的图来举例。

我们可以看到有6条边,需要先对这些边进行升序排列,这个排序算法我选择的是插入排序,之前听老师讲的,还有其他更好更快的排序方式,好像叫桶排序,等以后会了,再和大家分享。排序结果如下:

[2023-7]--[ Debug ]--Printf WeightSortList
Data : [(0, 3, 10, 0xbf7c20),(0, 1, 20, 0xbf7c00),(0, 2, 30, 0xbf7c80),(2, 3, 40, 0xbf7c60),(1, 4, 50, 0xbf7ca0),(3, 4, 60, 0xbf7c40)]
NodeCnt : 6

(0, 3, 10, 0xbf7c20)分别表示:起始节点索引,结束节点索引,权值,下一个节点的指针(我是用链表实现的),由于是无向网是12条边,还需要去重。

Kluskal算法的难点在于如何判断是否形成环,为此我们需要维护一个祖先数组,里面记录了每个节点的祖先索引号。

我们先初始化这个数组,如下:

[2023-7]--[ Debug ]--Printf Parent Array
{ -1 ,-1 ,-1 ,-1 ,-1 }

第一条边:(0, 3, 10, 0xbf7c20)也就是A->D传入:

先判断是否成环,0号位的值是-1,停止往下搜索。3号位的值是-1,停止往下搜索。0 != 3,所以没有成环。加入到MST中,修改祖先数组,3号位的祖先是0。

新的祖先数组如下:

[2023-7]--[ Debug ]--Printf Parent Array
{ -1 ,-1 ,-1 ,0 ,-1 }

第二条边:(0, 1, 20, 0x8ffc00)也就是A->B传入:

先判断是否成环,0号位的值是-1,停止往下搜索。1号位的值是-1,停止往下搜索。0 != 1,所以没有成环。加入到MST中,修改祖先数组,1号位的祖先是0。

新的祖先数组如下:

[2023-7]--[ Debug ]--Printf Parent Array
{ -1 ,0 ,-1 ,0 ,-1 }

第三条边:(0, 2, 30, 0x8ffc80)也就是A->C传入:

先判断是否成环,0号位的值是-1,停止往下搜索。2号位的值是-1,停止往下搜索。0 != 2,所以没有成环。加入到MST中,修改祖先数组,2号位的祖先是0。

新的祖先数组如下:

[2023-7]--[ Debug ]--Printf Parent Array
{ -1 ,0 ,0 ,0 ,-1 }

第四条边:(2, 3, 40, 0x104fc60)也就是C->D传入:

先判断是否成环,2号位的值是0,0号位的值是-1,停止往下搜索。3号位的值是0,0号位的值是-1,停止往下搜索。0 = 0,所以成环。这条边不加入到MST中。不修改祖先数组。

第五条边:(1, 4, 50, 0x104fca0)也就是B->E传入:

先判断是否成环,1号位的值是0,0号位的值是-1,停止往下搜索。4号位的值是-1,停止往下搜索。0 != 4,所以没有成环。加入到MST中,修改祖先数组,2号位的祖先是0。

已经加入了四条边,五个点,只需要四条边便可以组成最小生成树,打印最终的MST。

[2023-7]--[ Debug ]--Printf MST
{ (0,3,10),(0,1,20),(0,2,30),(1,4,50)}

二、结构体定义

typedef struct WeightSortType
{
    VertexIndexType         StartIndex;//起始顶点
    VertexIndexType         EndIndex;  //结束顶点
    WeightType              Weight;    //起始顶点到结束顶点边上的权值
    struct WeightSortType*  NextNodePtr;
}WeightSortType;

//尾指针循环链表
typedef struct WeightSortListType
{
    WeightSortType* TailNodePtr;
    WeightType      NodeCnt;
}WeightSortListType;

用于链表的插入排序。

三、函数定义

1、KluskalMST

Status KluskalMST(AGraph* AG, MstType* MST)
{
    JudgeAllNullPointer(AG);
    JudgeAllNullPointer(MST);

    WeightSortListType* SortList = NULL;

    //对数据进行升序排序
    InitWeightSortList(&SortList);
    KluskalWeightSort(AG, SortList);
    PrintfWeightSortList(SortList);

    //初始化祖先数组
    VertexIndexType ParentArray[AG->VertexNum];
    memset(ParentArray, PARENT_INIT_VALUE, sizeof(VertexIndexType) * AG->VertexNum);

    //遍历升序数组
    WeightSortType* TmpNodePtr = SortList->TailNodePtr->NextNodePtr;//指向尾指针循环链表的头节点。
    while(TmpNodePtr != NULL)
    {
        PrintfParentArray(ParentArray, AG->VertexNum);

        if(JudgeMstIsCycle(ParentArray, TmpNodePtr->StartIndex, TmpNodePtr->EndIndex) == FailFlag)//表示没有成环。
        {
            PushMST(MST, TmpNodePtr->StartIndex, TmpNodePtr->EndIndex, TmpNodePtr->Weight);
        }

        if(MST->ArrayMaxLen == MST->ArrayLen)//判断是否最小生成树达到N-1条边。
        {
            break;
        }

        TmpNodePtr = TmpNodePtr->NextNodePtr;
    }

    DestroyWeightSortList(&SortList);
    Log("Kluskal Create MST OK\n",Info);
    return SuccessFlag;
}

Kluskal算法形成MST的过程。

克鲁斯卡尔算法适用于稀疏图,所有我们这边用邻接表实现。

邻接表的概念和源码实现请参考之前的博客《数据结构与算法基础-学习-23-图之邻接矩阵与邻接表》

2、InitWeightSortList

Status InitWeightSortList(WeightSortListType** WST)
{
    JudgeAllNullPointer(WST);

    *WST = (WeightSortListType*)MyMalloc(sizeof(WeightSortListType));
    (*WST)->TailNodePtr = NULL;
    (*WST)->NodeCnt     = 0;
    
    Log("Init WeightSortList OK\n",Debug);
    return SuccessFlag;
}

初始化权值排序链表。

3、DestroyWeightSortList

Status DestroyWeightSortList(WeightSortListType** WST)
{  
    JudgeAllNullPointer(WST);
    JudgeAllNullPointer(*WST); 

    WeightSortType* TmpNode     = (*WST)->TailNodePtr;
    WeightSortType* TmpNextNode = NULL;
    WeightType                i = 0;

    for(i = 0;i < (*WST)->NodeCnt; i++)
    {
        TmpNextNode = TmpNode->NextNodePtr;
        free(TmpNode);
        TmpNode     = TmpNextNode;
    }
    
    (*WST)->TailNodePtr = NULL;
    (*WST)->NodeCnt     = 0;
    free(*WST);
    *WST                = NULL;
    Log("Destroy WeightSortList OK\n",Debug);
    return SuccessFlag;
}

销毁权值排序链表。

4、KluskalWeightSort

/* 
 * 参数
 * AG        : 传入参数,邻接表。
 * SortList  : 传出参数,是一个尾指针循环链表,存储升序排列的权值以及顶点索引,为什么用链表呢,
 *             1、数组实现的话,在进行排序时需要移动其他数据,比较耗时。
 *             2、数据最后是升序的,我们是顺序访问,而不是随机访问。
 * 
 * 支持有向网,无向网。
 * 
 * ===============
 * 实现
 * 1、将邻接表中有权值的数据进行有序写入。
 * 2、选用插入排序的方法对数据进行升序排列。
 * 3、去重相同边。
 */
Status KluskalWeightSort(AGraph* AG, WeightSortListType* SortList)
{
    JudgeAllNullPointer(AG);
    JudgeAllNullPointer(SortList);

    WeightType      i;
    ArcNode*        TmpNode         = NULL;
    WeightSortType* TmpListNode     = NULL;// 尾指针循环链表临时节点指针,遍历节点或记录头指针。
    WeightSortType* TmpPreListNode  = NULL;// 尾指针循环链表临时节点指针,存放上一个节点指针。

    for(i = 0; i < AG->VertexNum; i++)
    {
        TmpNode = AG->Vertices[i].FirstArcNodePtr;
        while(TmpNode != NULL)
        {
            if(JudgeCommonElem(i,TmpNode->EndVertexIndex,TmpNode->Weight,SortList) == SuccessFlag)//判断是否有重复的边,去重。
            {
                TmpNode = TmpNode->NextNodePtr;
                continue;
            }

            if(SortList->NodeCnt == 0)
            {
                SortList->TailNodePtr              = NewWeightSortType(i, TmpNode->EndVertexIndex, TmpNode->Weight);
                SortList->TailNodePtr->NextNodePtr = SortList->TailNodePtr;
            }
            else
            {
                if(TmpNode->Weight >= SortList->TailNodePtr->Weight)//数据升序排列,邻接表中的权值大于尾节点的权值,直接插入在尾部即可。
                {
                    TmpListNode                        = SortList->TailNodePtr->NextNodePtr;//存储头节点指针。
                    SortList->TailNodePtr->NextNodePtr = NewWeightSortType(i, TmpNode->EndVertexIndex, TmpNode->Weight);
                    SortList->TailNodePtr              = SortList->TailNodePtr->NextNodePtr;
                    SortList->TailNodePtr->NextNodePtr = TmpListNode;
                }
                else if(TmpNode->Weight <= SortList->TailNodePtr->NextNodePtr->Weight)//小于头节点,头插法插入。
                {
                    TmpListNode                        = SortList->TailNodePtr->NextNodePtr;//头节点指针
                    SortList->TailNodePtr->NextNodePtr = NewWeightSortType(i, TmpNode->EndVertexIndex, TmpNode->Weight);
                    SortList->TailNodePtr->NextNodePtr->NextNodePtr = TmpListNode;
                }
                else//多个节点,且邻接表的权值小于链表节点的权值。
                {
                    TmpPreListNode = SortList->TailNodePtr->NextNodePtr;
                    TmpListNode    = SortList->TailNodePtr->NextNodePtr->NextNodePtr;
                    while(TmpNode->Weight > TmpListNode->Weight)
                    {
                        TmpPreListNode = TmpListNode;
                        TmpListNode    = TmpListNode->NextNodePtr;
                    }
                    TmpPreListNode->NextNodePtr              = NewWeightSortType(i, TmpNode->EndVertexIndex, TmpNode->Weight);
                    TmpPreListNode->NextNodePtr->NextNodePtr = TmpListNode;                    
                }
            }
            SortList->NodeCnt++;
            TmpNode = TmpNode->NextNodePtr;
        }
    }
    Log("Kluskal WeightSort OK\n",Debug);
    return SuccessFlag;
}

5、JudgeCommonElem

//判断是否存在相同的边。
Status JudgeCommonElem(WeightType StartIndex, WeightType EndIndex, WeightType Weight, WeightSortListType* SortList)
{
    WeightType      i;
    WeightSortType* TmpNode = SortList->TailNodePtr;

    for(i = 0; i < SortList->NodeCnt; i++)
    {
        if(Weight == TmpNode->Weight)
        {
            if(TmpNode->StartIndex == EndIndex && TmpNode->EndIndex == StartIndex)
            {
                return SuccessFlag;
            }
        }
        TmpNode = TmpNode->NextNodePtr;
    }
    return FailFlag;
}

6、NewWeightSortType

WeightSortType* NewWeightSortType(VertexIndexType StartIndex, VertexIndexType EndIndex, WeightType Weight)
{
    WeightSortType* Result = (WeightSortType*)MyMalloc(sizeof(WeightSortType));
    Result->StartIndex     = StartIndex;
    Result->EndIndex       = EndIndex;
    Result->Weight         = Weight;
    Result->NextNodePtr    = NULL;
    return Result;
}

链表中新生成一个节点。

7、JudgeMstIsCycle

//判断最小生成树是否是环。
Status JudgeMstIsCycle(VertexIndexType* ParentArray, VertexIndexType StartIndex, VertexIndexType EndIndex)
{
    JudgeAllNullPointer(ParentArray);

    //找到起始节点和结束节点的祖先。
    VertexIndexType PreVertexIndex1 = StartIndex;
    while(ParentArray[PreVertexIndex1] != PARENT_INIT_VALUE)
    {
        PreVertexIndex1 = ParentArray[PreVertexIndex1];
    }

    VertexIndexType PreVertexIndex2 = EndIndex;
    while(ParentArray[PreVertexIndex2] != PARENT_INIT_VALUE)
    {
        PreVertexIndex2 = ParentArray[PreVertexIndex2];
    }
    //printf("%d, %d\n",StartIndex,EndIndex);
    //printf("%d, %d\n",PreVertexIndex1,PreVertexIndex2);
    //printf("==============\n");
    //判断起始节点和结束节点的祖先是否相等。
    if(PreVertexIndex1 == PreVertexIndex2)//相等表示形成环。
    {
        LogFormat(Debug,"MST Is Cycle, StartIndex : %d, EndIndex : %d\n",StartIndex,EndIndex);
        return SuccessFlag;
    }
    else//不相等,将结束节点的祖先改为起始节点。
    {
        ParentArray[PreVertexIndex2] = PreVertexIndex1;
        return FailFlag;
    }
}

四、Linux环境编译测试

[gbase@czg2 Graph]$ ./TestGraph 
[2023-7]--[ Info  ]--Create Net Data                    : OK
[2023-7]--[ Info  ]--Create Undirection Net Use AMGraph : OK
[2023-7]--[ Debug ]--Printf AMGraph                     :
VertexArray    : [A ,B ,C ,D ,E ]
ArcArray       :
[32767 ,20    ,30    ,10    ,32767 ]
[20    ,32767 ,32767 ,32767 ,50    ]
[30    ,32767 ,32767 ,40    ,32767 ]
[10    ,32767 ,40    ,32767 ,60    ]
[32767 ,50    ,32767 ,60    ,32767 ]
CurVertexNum   : 5
CurArcNum      : 12
[2023-7]--[ Info  ]--Create Undirection Net Use AGraph  : OK
[2023-7]--[ Debug ]--Printf AGraph                      :
A : [(2, 30, 0x104f8b0),(1, 20, 0x104f870),(3, 10, (nil))]
B : [(4, 50, 0x104f8d0),(0, 20, (nil))]
C : [(3, 40, 0x104f910),(0, 30, (nil))]
D : [(4, 60, 0x104f950),(2, 40, 0x104f890),(0, 10, (nil))]
E : [(3, 60, 0x104f990),(1, 50, (nil))]
VertexNum      : 5
ArcNum         : 12
[2023-7]--[ Debug ]--Traverse Use AMGraph               : [4 ,1 ,0 ,2 ,3 ]
[2023-7]--[ Debug ]--Traverse Use AGraph                : [4 ,3 ,2 ,0 ,1 ]
[2023-7]--[ Debug ]--Init SqQueue Normal
[2023-7]--[ Debug ]--Enter SqQueue Normal
[2023-7]--[ Debug ]--Leave SqQueue Normal
[2023-7]--[ Debug ]--Enter SqQueue Normal
[2023-7]--[ Debug ]--Enter SqQueue Normal
[2023-7]--[ Debug ]--Leave SqQueue Normal
[2023-7]--[ Debug ]--Enter SqQueue Normal
[2023-7]--[ Debug ]--Leave SqQueue Normal
[2023-7]--[ Debug ]--Enter SqQueue Normal
[2023-7]--[ Debug ]--Destroy SqQueue Normal
[2023-7]--[ Debug ]--Breadth First Search Use AMGraph OK
[2023-7]--[ Debug ]--Traverse Use AMGraph               : [4 ,1 ,3 ,0 ,2 ]
[2023-7]--[ Debug ]--Init SqQueue Normal
[2023-7]--[ Debug ]--Enter SqQueue Normal
[2023-7]--[ Debug ]--Leave SqQueue Normal
[2023-7]--[ Debug ]--Enter SqQueue Normal
[2023-7]--[ Debug ]--Enter SqQueue Normal
[2023-7]--[ Debug ]--Leave SqQueue Normal
[2023-7]--[ Debug ]--Enter SqQueue Normal
[2023-7]--[ Debug ]--Enter SqQueue Normal
[2023-7]--[ Debug ]--Destroy SqQueue Normal
[2023-7]--[ Debug ]--Breadth First Search Use AGraph OK
[2023-7]--[ Debug ]--Traverse Use AGraph                : [4 ,3 ,1 ,2 ,0 ]
[2023-7]--[ Debug ]--Init WeightSortList OK
[2023-7]--[ Debug ]--Kluskal WeightSort OK
[2023-7]--[ Debug ]--Printf WeightSortList
Data : [(0, 3, 10, 0x104fc20),(0, 1, 20, 0x104fc00),(0, 2, 30, 0x104fc80),(2, 3, 40, 0x104fc60),(1, 4, 50, 0x104fca0),(3, 4, 60, 0x104fc40)]
NodeCnt : 6
[2023-7]--[ Debug ]--Printf Parent Array
{ -1 ,-1 ,-1 ,-1 ,-1 }
[2023-7]--[ Debug ]--Printf Parent Array
{ -1 ,-1 ,-1 ,0 ,-1 }
[2023-7]--[ Debug ]--Printf Parent Array
{ -1 ,0 ,-1 ,0 ,-1 }
[2023-7]--[ Debug ]--Printf Parent Array
{ -1 ,0 ,0 ,0 ,-1 }
[2023-7]--[ Debug ]--MST Is Cycle, StartIndex : 2, EndIndex : 3
[2023-7]--[ Debug ]--Printf Parent Array
{ -1 ,0 ,0 ,0 ,-1 }
[2023-7]--[ Debug ]--Destroy WeightSortList OK
[2023-7]--[ Info  ]--Kluskal Create MST OK
[2023-7]--[ Debug ]--Printf MST
{ (0,3,10),(0,1,20),(0,2,30),(1,4,50)}
[2023-7]--[ Debug ]--Printf ShortestEdgeArray
{(0,0),(0,20),(0,30),(0,10),(0,32767)}
ArrayLen    : 1
ArrayMaxLen : 5
[2023-7]--[ Debug ]--Init ShortestEdgeArray OK
LowestEdgeVertexIndex : 3
[2023-7]--[ Debug ]--Printf ShortestEdgeArray
{(0,0),(0,20),(0,30),(0,0),(3,60)}
ArrayLen    : 2
ArrayMaxLen : 5
LowestEdgeVertexIndex : 1
[2023-7]--[ Debug ]--Printf ShortestEdgeArray
{(0,0),(0,0),(0,30),(0,0),(1,50)}
ArrayLen    : 3
ArrayMaxLen : 5
LowestEdgeVertexIndex : 2
[2023-7]--[ Debug ]--Printf ShortestEdgeArray
{(0,0),(0,0),(0,0),(0,0),(1,50)}
ArrayLen    : 4
ArrayMaxLen : 5
LowestEdgeVertexIndex : 4
[2023-7]--[ Debug ]--Destroy ShortestEdgeArray OK
[2023-7]--[ Info  ]--Prim Create MST OK
[2023-7]--[ Debug ]--Printf MST
{ (0,3,10),(0,1,20),(0,2,30),(1,4,50)}
[2023-7]--[ Info  ]--Destroy Net Data                   : OK
[2023-7]--[ Info  ]--Destroy Undirection Net Use AMGraph: OK
[2023-7]--[ Info  ]--Destroy Undirection Net Use AGraph : OK

五、Prim算法和Kluskal算法对比

算法名PrimKluskal
思路选择点选择边
时间复杂度O(N^2)(n为顶点数)O(eloge)(e为边数)
适用范围稠密图稀疏图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/777424.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

11.键盘事件

键盘事件 html部分 <div class"insert"><div class"key">请按下你的键盘</div> </div>css部分 * {margin: 0;padding: 0; }body {display: flex;justify-content: center;align-items: center;height: 100vh;overflow: hidden; }…

Pytorch手动实现softmax回归

参考代码&#xff1a;https://blog.csdn.net/ccyyll1/article/details/126020585 softmax回归梯度计算方式&#xff0c;特别是ij和i! j时的计算问题&#xff0c;请看如下帖子中的描述&#xff0c;这个问题是反向传播梯度计算中的一个核心问题&#xff1a;反向传播梯度计算中的…

哈工大计算机网络课程局域网详解之:MAC地址与ARP协议

哈工大计算机网络课程局域网详解之&#xff1a;MAC地址与ARP协议 文章目录 哈工大计算机网络课程局域网详解之&#xff1a;MAC地址与ARP协议MAC地址ARP&#xff1a;地址解析协议寻址&#xff1a;从一个LAN路由至另一个LAN MAC地址 在介绍MAC地址前&#xff0c;首先回顾一下之前…

SAP ABAP 实现数据库表行项目和程序加解锁功能

1.SAP ABAP 实现数据库表行项目加解锁功能 实现效果&#xff1a; 当一个数据库表以某字段为关键字段的数据被锁定时&#xff0c;同一时间其他程序无法修改改表内被锁定的数据&#xff0c;除非被解锁或退出程序。 1.事务代码&#xff1a;SE11 创建锁对象。PS&#xff1a;命名…

【计组】不同进制数之间的相互转换

前言 1、推荐在线进制转换器&#xff1a;&#xff08;都还不错&#xff09; 在线进制转换 | 进制转换器 — 在线工具 (sojson.com) 在线进制转换器 | 菜鸟工具 (runoob.com) 在线进制转换 - 码工具 (matools.com) 2、进位计数法 &#xff08;1&#xff09;二进制&#xf…

JavaScript字符串和模板字面量

● 上节课我们说明&#xff0c;号可以当作字符串连接符号使用&#xff0c;例如 const firstName "Sun"; const job "技术分享博主"; const birthYear 1991; const year 2023;const sun "我叫" firstName ",是一个" (year - bi…

线性结构:队列

文章目录 队列定义队列应用热土豆问题打印任务 队列定义 队尾进&#xff0c;队头出 队列是一种有次序的数据集合&#xff0c;其特征是新数据项的添加总发生在一端(通常称为“尾rear”端&#xff09;而现存数据项的移除总发生在另一端&#xff08;通常称为“首front”端&#x…

刷题记录-2最短路径

考点&#xff1a; 图论-最短路-Dijkstra 解题&#xff1a; c #include <iostream> #include <vector> #include <queue> using namespace std; const long long inf 0x3f3f3f3f3f3f3f3fLL; const int num 3e52; struct edge {int from,to;long long w;e…

算法竞赛入门【码蹄集新手村600题】(MT1001-1020)

算法竞赛入门【码蹄集新手村600题】(MT1001-1020&#xff09; 目录MT1001 程序设计入门MT1002 输入和输出整型数据MT1003 整数运算MT1004 求余MT1005 输入和输出实型数据MT1006 实型数运算MT1007 平均分MT1008 圆球等的相关运算MT1009 公式计算MT1010 输入和输出字符型数据MT10…

【Visual Studio】Qt 在其他 cpp 文件中调用操作 ui 界面控件

知识不是单独的&#xff0c;一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏&#xff1a;Visual Studio。 还整了一个如何相互之间调用函数的文章&#xff0c;感兴趣可以看&#xff1a;【Visual Studio】Qt 在其他 cpp 文件中调用主工程下文件中的函数。 文章目录 …

第四章:包围体

第四章&#xff1a;包围体 引言-包围体&#xff08;1&#xff09;包围体测试和几何体测试&#xff08;2&#xff09;包围体测试的代价和作用&#xff08;3&#xff09;相交测试的优化&#xff08;4&#xff09;包围体相关章节和主旨 一、BV 期望特征1.1 有效的包围体1.2 包围体…

docker 网络配置详解

目录 1、docker网络模式 2、容器和容器之间是如何互通 3、容器之间互通 --link 3、自定义网络 4、不通网段的容器进行网络互通 1、docker网络模式 docker 网络模式采用的是桥接模式&#xff0c;当我们创建了一个容器后docker网络就会帮我们创建一个虚拟网卡&#xff0c;这…

Electron 学习_在进程之间通信

1.问题&#xff1a;Electron的主进程和渲染进程有着清楚的分工&#xff0c;并且不可互换。从渲染进程直接访问Node.js 接口&#xff0c;亦或者 从主进程访问HTML文档对象模型(DOM)都是不可能的 2.解决方法&#xff1a;使用进程间通信 (IPC) 可以使用 Electron 的ipcMain 模块和…

Redisson限流器RRateLimiter使用及源码分析

一、使用 使用很简单、如下 // 1、 声明一个限流器 RRateLimiter rateLimiter redissonClient.getRateLimiter(key);// 2、 设置速率&#xff0c;5秒中产生3个令牌 rateLimiter.trySetRate(RateType.OVERALL, 3, 5, RateIntervalUnit.SECONDS);// 3、试图获取一个令牌&#…

TCP首部格式【TCP原理(笔记五)】

文章目录 TCP首部格式源端口号&#xff08;Source Port&#xff09;目标端口号&#xff08;Destination Port&#xff09;序列号&#xff08;Sequence Number&#xff09;确认应答号&#xff08;Acknowledgement Number&#xff09;数据偏移&#xff08;Data Offset&#xff09…

Oracle 普通视图 (Oracle Standard Views)

视图&#xff08;views&#xff09;是一种基于表的"逻辑抽象"对象&#xff0c;由于它是从表衍生出来的&#xff0c;因此和表有许多相同点&#xff0c;我们可以和对待表一样对其进行查询/更新操作。但视图本身并不存储数据&#xff0c;也不分配存储空间。 本文只讨论普…

Linux下搭建pyqt5开发环境—基于Pycharm

防踩坑Tips&#xff1a; 1、不能学windows那样直接用pip安装PyQt5Designer和pyqt5-tools。这两个模块最根本的是用的windows的程序&#xff0c;linux上是运行不了的&#xff0c;特别是PyQt5Designer&#xff0c;会提示安装失败。 2、推荐在python环境安装同系统版本一致的pyq…

2023.7.16 第五十九次周报

目录 前言 文献阅读:跨多个时空尺度进行预测的时空 LSTM 模型 背景 本文思路 本文解决的问题 方法论 SPATIAL 自动机器学习模型 数据处理 模型性能 代码 用Python编写的LSTM多变量预测模型 总结 前言 This week, I studied an article that uses LSTM to solve p…

数据分析系统中的六边形战士——奥威BI系统

数据分析软件可以对收集的数据进行分析和报告&#xff0c;帮助企业获得更深入的数据洞察力&#xff0c;从而推动企业数字化运营决策&#xff0c;提高决策效率与质量。进入大数据时代&#xff0c;企业对数据分析软件的要求也在水涨船高&#xff0c;传统的数据分析软件显然已不能…

数据结构 单向链表(不循环)的基础知识和基础操作

头定义&#xff1a; typedef int datatype; typedef struct Node {//数据域存储数据datatype data;//指针域存储下一个地址struct Node *next; }*Linkelist; 创建节点 Linkelist create_node()//创建新节点 {Linkelist node(Linkelist)malloc(sizeof(struct Node));if(nodeN…