(C语言版)力扣(LeetCode)+牛客网(nowcoder)链表相关面试题OJ题解析

news2024/11/20 12:22:37

在这里插入图片描述

链表面试题

  • 203. 移除链表元素
    • 题目
    • 解法一:递归
    • 解法二:迭代
  • 206. 反转链表
    • 题目
    • 解法一:递归
    • 解法二:迭代
  • 876. 链表的中间结点
    • 题目
    • 解法一:快慢指针法
    • 解法二:单指针法
  • 链表中倒数第k个结点
    • 题目
    • 解法
  • 21. 合并两个有序链表
    • 题目
    • 解法一:递归
    • 解法二:迭代
  • CM11 链表分割
    • 题目
    • 解法
  • OR36 链表的回文结构
    • 题目
    • 解法
  • 160. 相交链表
    • 题目
    • 解法
  • 141. 环形链表
    • 解法
  • 142. 环形链表 II
    • 题目
    • 解析
  • 138. 复制带随机指针的链表
    • 题目
    • 解析
  • 结语

203. 移除链表元素

题目

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
题目链接:移除链表元素

解法一:递归

代码如下:

struct ListNode* removeElements(struct ListNode* head, int val){
    if(head==NULL)
        return NULL;
    head->next=removeElements(head->next,val);
    return head->val==val?head->next:head;
}

递归的写法看起来简洁,实际并没有迭代写法好理解,而且在空间复杂度上也比迭代高,这里的递归写法思路主要是先向下找到尾结点后,向上逐个返回,如果等于val值,就将该节点上一个元素直接指向该节点下一个元素,等于是将该点从链表中删除了
如下图:
在这里插入图片描述

解法二:迭代

代码如下:

struct ListNode* removeElements(struct ListNode* head, int val){
    struct ListNode* headhead=malloc(sizeof(struct ListNode));
    headhead->next=head;
    struct ListNode* temp=headhead;
    while(temp->next!=NULL)
    {
        if(temp->next->val==val)
            temp->next=temp->next->next;
        else
            temp=temp->next;
    }
    return headhead->next;
}

迭代的思路就比较好理解了,先创建一个结点空间headhead,让它指向head,再用temp复制该内存地址,使用temp对链表进行遍历,找到等于val值的元素就删除,直至遍历完整个链表,最后headhead指向的下一个位置即为删除val结点的head头结点位置。

206. 反转链表

题目

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
题目链接:反转链表

解法一:递归

代码如下:

struct ListNode* reverseList(struct ListNode* head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode* newHead = reverseList(head->next);
    head->next->next = head;
    head->next = NULL;
    return newHead;
}

这里的递归写法相对于上一题更不好理解一些,具体也是向下找到最后一个结点,逐个反转,如下图:
在这里插入图片描述

解法二:迭代

代码如下:

struct ListNode* reverseList(struct ListNode* head){
    struct ListNode* prev=NULL;
    struct ListNode* cur=head;
    while(cur)
    {
        struct ListNode* next=cur->next;
        cur->next=prev;
        prev=cur;
        cur=next;
    }
    return prev;
}

迭代写法就很简单了,设定两个指针,prev指向NULL,cur指向头结点,再用循环从头开始反转,最后prev即为头结点,返回prev即可。

876. 链表的中间结点

题目

给你单链表的头结点 head ,请你找出并返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
题目链接:链表的中间结点

解法一:快慢指针法

代码如下:

struct ListNode* middleNode(struct ListNode* head){
struct ListNode* fast = head;
struct ListNode* slow = head;
while(fast&&fast->next)
{
    slow=slow->next;
    fast=fast->next->next;
}
return slow;
}

个人觉得快慢指针的写法更简洁且好理解,大概的思路就是slow指针走一步,fast指针走两步,fast遍历完链表,slow指针指向的即为中间结点。

解法二:单指针法

代码如下:

struct ListNode* middleNode(struct ListNode* head){
    int n=0;
    struct ListNode* cur=head;
    while(cur!=NULL)
    {
        n++;
        cur=cur->next;
    }
    int k=n/2;
    cur=head;
    while(k>0)
    {
        cur=cur->next;
        k--;
    }
    return cur;
}

这个算法的思路就是用cur指针先遍历一遍数组,用n记录结点个数,再用结点数/2的值赋给k,cur重新指向头结点,再进行遍历k个位置,最后cur停在的结点位置即为中间节点位置。

链表中倒数第k个结点

题目

输入一个链表,输出该链表中倒数第k个结点。
题目链接:链表中倒数第k个结点

解法

代码如下:

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    struct ListNode* fast=pListHead;
    struct ListNode* slow=pListHead;
    while(k--)
    {
        if(fast==NULL)
        {
            return NULL;
        }
        fast=fast->next;
    }
    while(fast)
    {
        fast=fast->next;
        slow=slow->next;
    }
    return slow;
}

这里用的是双指针的写法,先让fast指针向前走k个结点位置,再让fast和slow同时走,直到fast走到NULL,此时的slow指向的就是倒数第k个结点。

21. 合并两个有序链表

题目

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
题目链接:合并两个有序链表

解法一:递归

代码如下:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    if(list1==NULL)
        return list2;
    else if(list2==NULL)
        return list1;
    else if(list1->val<list2->val)
    {
        list1->next=mergeTwoLists(list1->next,list2);
        return list1;
    }
    else
    {
        list2->next=mergeTwoLists(list1,list2->next);
        return list2;
    }
}

这种递归写法相对好理解一些,前两个条件是考虑list1或list2为空的情况发生,后两个条件都是使用递归,当list1头结点值小于list2头结点值时,则头结点为list1,否则为list2,然后继续向下一结点递归,最后合并完整个链表。

解法二:迭代

代码如下:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    struct ListNode* list3=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* p3=list3;
    while(list1!=NULL&&list2!=NULL)
    {
        if(list1->val<list2->val)
        {
            p3->next=list1;
            list1=list1->next;
            p3=p3->next;
            p3->next=NULL;
        }
        else
        {
            p3->next=list2;
            list2=list2->next;
            p3=p3->next;
            p3->next=NULL;
        }
    }
    if(list1==NULL)
        p3->next=list2;
    if(list2==NULL)
        p3->next=list1;
    return list3->next;
}

这种写法的思路是借助额外的空间,也是逐个比较大小,再将结点从小到大串联,最后返回额外的空间结点指向的下一结点,即为调整好的链表。

CM11 链表分割

题目

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。
题目链接:链表分割

解法

代码如下:

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        struct ListNode* lesstail=(struct ListNode*)malloc(sizeof(struct ListNode));
        struct ListNode* moretail=(struct ListNode*)malloc(sizeof(struct ListNode));
        struct ListNode* less=lesstail;
        struct ListNode* more=moretail;
        struct ListNode* cur=pHead;
        while(cur)
        {
            if(cur->val<x)
            {
                less->next=cur;
                less=less->next;
                cur=cur->next;
            }
            else 
            {
                more->next=cur;
                more=more->next;
                cur=cur->next;
            }
        }
        more->next=NULL;
        less->next=moretail->next;
        pHead=lesstail->next;
        free(lesstail);
        free(moretail);
        return pHead;
    }
};

这里的题,没有c语言选项,可以直接在c++里写也是没有问题的,因为c++兼容c的大部分代码,首先我们创建两个临时空间用于保存较小值和较大值的链表空间分别复制给less和more两个指针,将pHead复制给cur指针,然后利用循环将cur指针逐个遍历pHead中的结点值与val进行比较,较小值用less指向,较大值用more指向,最后more再指向NULL(此时more指向的应该是最后的结点),less指向moretail第一个结点,再将pHead指向lesstail第一个结点,再将两个临时空间释放,最后返回pHead即为分割好的链表。

OR36 链表的回文结构

题目

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。
给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

测试样例:1->2->2->1
返回:true
题目链接:链表的回文结构

解法

代码如下:

class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) 
    {
        struct ListNode*slow=A;
        struct ListNode*fast=A;
        while(fast->next)
        {
            slow=slow->next;
            fast=fast->next;
        }
        struct ListNode*change=NULL;
        struct ListNode*head=slow;
        while(head)
        {
            struct ListNode*next=slow->next;
            head->next=change;
            change=head;//重新置头
            head=next;
        }
        while(slow)
        {
            if(A->val!=change->val)
            {
                return false;
            }
            slow=slow->next;
            change=change->next;
        }
        return true;
    }
};

这个算法的思路是先建立两个快慢指针,fast指针走两步,slow指针走一步,当fast指针遍历完整个链表时,slow指向链表中间位置,再创建两个指针一个指向NULL,另一个复制slow当前地址,再将slow之后的链表进行反转,再比较,只要有一个值不相等即返回false,遍历后都相等,返回ture。

160. 相交链表

题目

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

图示两个链表在节点 c1 开始相交:
在这里插入图片描述
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构。
题目链接:相交链表

解法

代码如下:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if (headA == NULL || headB == NULL) {
        return NULL;
    }
        struct ListNode *p, *q;

        for (p = headA, q = headB; p != q; ){
            if (p != NULL)
                p = p->next;
            else 
                p = headB;
            if (q != NULL)
                q = q->next;
            else 
                q = headA;
        }

        return p;
}

这种算法的主体思路为复制AB两个头结点指针,两个结点同时开始遍历,如果第一趟遍历不相等,那先到尾结点的指针先走到另一头结点的位置,之后另一个指针接着走一步,如果两指针不相等,就一直进入循环,直至两指针相等跳出循环,最后返回其中一个结点即为相交结点。
上述代码可改为下面的简洁形式:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if(headA==NULL||headB==NULL)
        return NULL;
    struct ListNode *p=headA,*q=headB;
    while(p!=q)
    {
        p=p==NULL?headB:p->next;
        q=q==NULL?headA:q->next;
    }
    return q;
}

141. 环形链表

给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
题目链接:环形链表

解法

代码如下:

bool hasCycle(struct ListNode* head) {
    if (head == NULL || head->next == NULL) {
        return false;
    }
    struct ListNode* slow = head;
    struct ListNode* fast = head->next;
    while (slow != fast) {
        if (fast == NULL || fast->next == NULL) {
            return false;
        }
        slow = slow->next;
        fast = fast->next->next;
    }
    return true;
}

这里使用快慢指针的写法,slow指针从头开始,fast指针从第二个结点开始,首先在循环中,如果fast指针走到了NULL或下一结点为空,则直接返回false,如果是环状的,则fast指针走两步,slow指针走一步,最终两指针会相遇, 最后跳出循环,返回ture。

142. 环形链表 II

题目

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
题目链接:环形链表||

解析

代码如下:

struct ListNode* detectCycle(struct ListNode* head) {
    struct ListNode *slow = head, *fast = head;
    while (fast != NULL) {
        slow = slow->next;
        if (fast->next == NULL) {
            return NULL;
        }
        fast = fast->next->next;
        if (fast == slow) {
            struct ListNode* ptr = head;
            while (ptr != slow) {
                ptr = ptr->next;
                slow = slow->next;
            }
            return ptr;
        }
    }
    return NULL;
}

这种解法思路延续上一题的快慢指针,只不过fast指针也是从头开始以及返回值改变了,遍历环形链表fast等于slow时,此时先判断slow是否等于头结点,如果等于头结点,则直接返回头结点,如果不等,则进入循环,各自走一步,直至相等,返回相等时的结点即为环结点。

138. 复制带随机指针的链表

题目

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
你的代码 只 接受原链表的头节点 head 作为传入参数。
题目链接:复制带随机指针的链表

解析

代码如下:

struct Node* copyRandomList(struct Node* head) {
    if(head == NULL)
        return NULL;
    struct Node* p = head;
    struct Node* phead = (struct Node*)malloc(sizeof(struct Node));//复制后要返回的链表头结点
    struct Node* ph = phead;//复制phead结点
    while(p)//p不为NULL则一直循环
    {
        struct Node* tmp = p->next;//保存p的下一结点
        ph->val = p->val;//复制值到pHead
        p->next = ph;//p指向ph
        ph->random = p->random;//复制random指针给ph
        ph->next = (struct Node*)malloc(sizeof(struct Node));//开辟下一结点空间
        if(tmp)
            ph = ph->next;//为真表示后面还有结点,ph指向下一结点
        else
            ph->next = NULL;//为假表示后面没结点了
        p = tmp;//p指向p的下一结点
    }
    ph = phead;//再复制phead到ph
    while(ph)
    {
        if(ph->random)//random指向空则不执行
            ph->random = ph->random->next;//random指向的修正
        ph = ph->next;//指向下一结点
    }
    return phead;
}

代码分析我写在注释中了,主要思路是,先将p(head)的val复制到ph(phead),然后将p的next指向当前ph结点,然后将p当前的random复制给ph(phead)的random,遍历直至p指向空,再将ph(phead)的random指向修正,最后phead即为复制后的链表
可以结合作者画的草图理解一下:
在这里插入图片描述

这个图可能画的不好,小伙伴如果理解不了可以自己画一遍推一下代码,应该就可以理解了。

结语

这里的解法代码部分来自力扣官方和作者自己的解法,作者只是进行了详细的剖析和部分改动方便大家理解和提升自己,学会多角度观察问题,解决问题。

有兴趣的小伙伴可以关注作者,如果觉得内容不错,请给个一键三连吧,蟹蟹你哟!!!
制作不易,如有不正之处敬请指出
感谢大家的来访,UU们的观看是我坚持下去的动力
在时间的催化剂下,让我们彼此都成为更优秀的人吧!!!
在这里插入图片描述

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

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

相关文章

22.碳交易机制下考虑需求响应的综合能源系统优化运行

说明书 MATLAB代码&#xff1a;碳交易机制下考虑需求响应的综合能源系统优化运行 注意&#xff1a;另外还有含义柔性负荷、蓄冷式空调、共享储能以及碳捕集的综合能源系统优化运行代码&#xff0c;欢迎咨询 关键词&#xff1a;需求响应 碳交易机制 日前优化调度 综合能源系统…

pdf怎么分割成一页一页的文件?

pdf怎么分割成一页一页的文件&#xff1f;相信很多使用电脑办公的小伙伴们都知道&#xff0c;无论是pdf文件还是ppt文件其都是由很多页组成的。一般当我们需要其中的部分内容时候&#xff0c;可以通过手动的方式将ppt文件来拆分成一页一页的来使用。但是这种手动的方法对于pdf文…

数据库中数据的操作(进阶)

数据库中数据的约束 键值约束 primary key唯一性约束 unique key非空约束 not null默认值 default val扩展属性&#xff08;auto_increment&#xff09;外键约束 foreign keycheck 子句约束 键值约束 primary key 主键约束&#xff1a;primary key 约束指定字段中的值&#xff…

虹科干货 | 零售业数智升级不掉队,get数据,get未来!

电商崛起&#xff0c;传统零售行业危机四伏&#xff0c;全渠道盈利与可持续化成为难点&#xff0c;库存管理这块难啃的“硬骨头”也同样让零售商倍感压力… 背腹受敌的零售商&#xff0c;如何才能在数字化转型道路上避免利润缩水&#xff0c;与供应商协作共赢&#xff0c;摆脱困…

【Mac教学】如何打开macOS 的最大权限

相信有不少用户都知道&#xff0c;目前苹果的Mac 电脑中&#xff0c;有不少功能为了安全问题&#xff0c;设立了多项安全措施&#xff0c;当中有一些需要安装第三方的软件&#xff0c;但因为缺少了苹果认证&#xff0c;而无法使用或安装&#xff0c;因此为各位讲解一个设定&…

汇编语言-复习自用

本文用于自我复习汇编语言&#xff0c;参考b站一位老师的讲解整理而成&#xff0c;感谢老师的无私付出视频链接链接 文章目录 1.第一章1.1计算机组成1.2读取1.3 寄存器及数据存储1.4 mov和and指令1.5 确定物理地址1.6 内存分段表示法1.7debug使用1.8CS:IP1.9jmp指令改变csip1.1…

Git教程(一)

1、Git概述 1.1 、Git历史 同生活中的许多伟大事件一样&#xff0c;Git 诞生于一个极富纷争大举创新的年代。Linux 内核开源项目有着为数众广的参与者。绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上&#xff08;1991&#xff0d;2002年间&#xff09;…

ThingsBoard使用jar包进行初始化数据库

1、概述 ThingsBoard的官方虽然提供了直接使用他们的官方镜像来部署,但是根据我了解到的一些信息,目前国内几乎都是基于ThingsBoard进行二开,都需要拉取ThingsBoard的源代码,然后自己进行修改,然后部署自己修改后的代码,在这里我就不说如何进行本地编译了,目前网上有很…

SpringBoot的依赖管理和自动配置

目录 依赖管理自动配置 依赖管理 1.父项目做依赖管理 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version> </parent>他的父项目 &…

如何远程访问本地jupyter notebook服务器,实现无公网IP端口映射

文章目录 前言视频教程1. Python环境安装2. Jupyter 安装3. 启动Jupyter Notebook4. 远程访问4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5. 固定公网地址 转载自远控源码文章&#xff1a;公网远程访问jupyter notebook【cpolar内网穿透】 前言 Jupyter Notebook&am…

【数据结构】插入排序

插入排序 1. 排序2.插入排序2.1直接插入排序2.2折半插入法2.3希尔排序 1. 排序 排序的概念 排序就是将一组杂乱无章的数据按一定规律&#xff08;顺序或者逆序&#xff09;排列起来。 排序的目的 方便查找元素。 内部排序和外部排序 若待排序记录都在内存中&#xff0c;称为内…

ASEMI代理ADI亚德诺LTC6992IS6-1#TRMPBF车规级芯片

编辑-Z LTC6992IS6-1#TRMPBF参数描述&#xff1a; 型号&#xff1a;LTC6992IS6-1#TRMPBF 输出频率&#xff1a;3.81Hz 工作电源电压范围&#xff1a;2.25 - 5.5V 通电复位电压&#xff1a;1.95V 电源电流&#xff1a;105-365A SET引脚处的电压&#xff1a;1V 频率设置电…

性能测试工程师岗分级(初中高/资深/专家)?提高性能测试的价值...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试岗位按照…

嵌入式Linux驱动开发(十二)platform设备驱动实验

1. platform设备驱动简介 基于驱动可重用性考虑&#xff0c;提出驱动分离与分层思想。平台设备驱动就是基于此。 1.1 驱动分隔与分层 1&#xff09;驱动分隔&#xff1a;   以I2C驱动为例&#xff0c;假设有三类SOC&#xff0c;各自对一个设备写I2C驱动&#xff0c;就需要3…

StarUML破解失败解决办法

明明以及安装了asar但是输入反编译命令还是显示asar不是内部命令 于是根据提示找到了这个文件夹&#xff0c;发现里面有asar的命令&#xff0c;而且输入asar -v也可以查看版本 于是我把app.asar那个文件复制过来了&#xff0c;然后在这个路径输入反编译命令&#xff0c;成功…

6.2.2邻接表法 6.2.3十字链表,邻接多重表

由于用邻接矩阵存储稀疏图会造成大量空间浪费。 而本节课我们所学的邻接表是采用顺序存储加上链式存储的方式。 arcnum指的是弧的数量 对比&#xff1a;树的孩子表示法&#xff08;相同的实现方式&#xff09; Compare&#xff1a; 6.2.3十字链表&#xff0c;邻接多重表 定义这…

Android 内存分析(java/native heap内存、虚拟内存、处理器内存 )

1.jvm 堆内存(dalvik 堆内存) 不同手机中app进程的 jvm 堆内存是不同的&#xff0c;因厂商在出厂设备时会自定义设置其峰值。比如,在Android Studio 创建模拟器时&#xff0c;会设置jvm heap 默认384m , 如下图所示&#xff1a; 当app 进程中java 层 new 对象(加起来总和)占用…

知识图谱实战应用8-从文本关系抽取到知识图谱关系构建流程贯通

大家好,我是微学AI,今天给大家介绍一下知识图谱实战应用8-从文本关系抽取到知识图谱关系构建流程贯通。我们从文本数据中采集到关键信息,并抽取出其中的关系信息,然后在存入图数据库中,整个过程实现自动化,我这里将举一个文本例子进行抽取。 对于知识图谱的构建是将实体…

ThingsBoard使用jar包自己构建镜像部署

1、概述 这一节主要讲解你自己使用jar包构建镜像,一般在很多企业中,都是使用Jenkins配置流水线,自动打包,然后拷贝程序在target目录下生成的jar包,然后使用Dockerfile文件进行构建镜像,其实我这一节讲的也是类似,只是不使用Jenkins来实现自动,原理都一样,估计也是很多…

网络协议 — BGP 边界网关协议

目录 文章目录 目录BGP 和 ASBGP Router 和 RoutesBGP Message 类型和格式BGP Msg HeaderBGP Msg DataOpen MsgKeepalive MsgNotification MsgRoute-refresh MsgUpdate Msg BGP Msg 状态机 BGP RR&#xff08;Route-Reflectors&#xff0c;路由反射器&#xff09;BGP MP&#x…