数据结构笔记--链表经典高频题

目录

前言

1--反转单向链表

2--反转单向链表-II

3--反转双向链表

4--打印两个有序链表的公共部分

5--回文链表

6--链表调整

7--复制含有随机指针结点的链表

8--两个单链表相交问题


前言

面经:

        针对链表的题目,对于笔试可以不太在乎空间复杂度,以时间复杂度为主(能过就行,对于任何题型都一样,笔试能过就行);对于面试,时间复杂度依然处在第一位,但要力求空间复杂度最低的算法(突出亮点);

        链表题的重要技巧包括:使用额外的数据结构记录(例如哈希表等),使用快慢指针的思想;

1--反转单向链表

笔试解法:

        借助栈先进后出,可以遍历把结点存到栈中,然后不断出栈,这样结点的顺序就反转了;

        时间复杂度为O(n),空间复杂度为O(n);

#include <iostream>
#include <stack>struct ListNode {int val;ListNode *next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode *next) : val(x), next(next) {}
};class Solution {
public:ListNode* reverseList(ListNode* head) {if(head == NULL) return head;std::stack<ListNode*> st;while(head != NULL){st.push(head);head = head->next;}ListNode *new_head = new ListNode(0);ListNode *tmp = new_head;while(!st.empty()){tmp->next = st.top();st.pop();tmp = tmp->next;}tmp->next = NULL;return new_head->next;}
};int main(int argc, char *argv[]){ListNode *Node1 = new ListNode(1);ListNode *Node2 = new ListNode(2);ListNode *Node3 = new ListNode(3);ListNode *Node4 = new ListNode(4);ListNode *Node5 = new ListNode(5);Node1->next = Node2;Node2->next = Node3;Node3->next = Node4;Node4->next = Node5;Solution S1;ListNode *res = S1.reverseList(Node1);while(res != NULL){std::cout << res->val << " ";res = res->next;}return 0;
}

面试解法:

        不借助栈或递归,通过迭代将空间复杂度优化为O(1);

        利用一个额外的前驱结点 pre 来存储当前结点 cur 的前一个结点,不断更新 pre 和 cur即可;

#include <iostream>
#include <stack>struct ListNode {int val;ListNode *next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode *next) : val(x), next(next) {}
};class Solution {
public:ListNode* reverseList(ListNode* head) {if(head == NULL) return head;ListNode *pre = NULL;ListNode *cur = head;while(cur != NULL){ListNode* next = cur->next;cur->next = pre;pre = cur;cur = next;}return pre;}
};int main(int argc, char *argv[]){ListNode *Node1 = new ListNode(1);ListNode *Node2 = new ListNode(2);ListNode *Node3 = new ListNode(3);ListNode *Node4 = new ListNode(4);ListNode *Node5 = new ListNode(5);Node1->next = Node2;Node2->next = Node3;Node3->next = Node4;Node4->next = Node5;Solution S1;ListNode *res = S1.reverseList(Node1);while(res != NULL){std::cout << res->val << " ";res = res->next;}return 0;
}

2--反转单向链表-II

主要思路:

        使用三个指针,指针 pre 指向反转区域外的第一个节点,即上图中的 1;指针 cur 指向当前指针,指针 next 指向 cur 的下一个指针;

        遍历链表,每次将 next 指针头插,具体过程可以参考官方题解;

#include <iostream>struct ListNode {int val;ListNode *next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode *next) : val(x), next(next) {}
};class Solution {
public:ListNode* reverseBetween(ListNode* head, int left, int right) {ListNode *dummyNode = new ListNode(-1);dummyNode->next = head;ListNode *pre = dummyNode;ListNode *cur;ListNode *next;// 经过循环之后,pre指向反转区域前的第一个节点for(int i = 0; i < left - 1; i++){pre = pre->next;}cur = pre->next; // cur指向反转区域的第一个节点for(int i = 0; i < right - left; i++){next = cur->next;cur->next = next->next; // cur指向next的下一个节点,因为next节点要头插到pre节点后面next->next = pre->next; // next节点头插,指向原来的第一个节点pre->next = next; // next节点头插到pre节点后面}return dummyNode->next;}
};int main(){ListNode *Node1 = new ListNode(1);ListNode *Node2 = new ListNode(2);ListNode *Node3 = new ListNode(3);ListNode *Node4 = new ListNode(4);ListNode *Node5 = new ListNode(5);Node1->next = Node2;Node2->next = Node3;Node3->next = Node4;Node4->next = Node5;Solution S1;int left = 2, right = 4;ListNode *res = S1.reverseBetween(Node1, left, right);while(res != NULL){std::cout << res->val << " ";res = res->next;}return 0;
}

3--反转双向链表

主要思路:

        与反转单向链表类似,使用 pre,cur 和 next 指向前一个节点,当前节点和后一个节点,不断遍历更新三个指针所指向的节点即可,并修改对应的前驱指针和后驱指针;

#include <iostream>
#include <stack>struct ListNode {int val;ListNode *pre;ListNode *next;ListNode() : val(0), pre(nullptr), next(nullptr) {}ListNode(int x) : val(x), pre(nullptr), next(nullptr) {}ListNode(int x, ListNode *next) : val(x), pre(nullptr), next(next) {}
};class Solution {
public:ListNode* reverseList(ListNode* head) {if(head == NULL) return head;ListNode *pre = NULL;ListNode *cur = head;while(cur != NULL){ListNode* next = cur->next;cur->next = pre;cur->pre = next;pre = cur;cur = next;}return pre;}
};int main(int argc, char *argv[]){ListNode *Node1 = new ListNode(1);ListNode *Node2 = new ListNode(2);ListNode *Node3 = new ListNode(3);ListNode *Node4 = new ListNode(4);ListNode *Node5 = new ListNode(5);Node1->next = Node2;Node2->next = Node3;Node3->next = Node4;Node4->next = Node5;Node2->pre = Node1;Node3->pre = Node2;Node4->pre = Node3;Node5->pre = Node4;Solution S1;ListNode *res = S1.reverseList(Node1);while(res != NULL){std::cout << res->val << " ";if(res->pre != NULL) std::cout << res->pre->val;std::cout << std::endl;res = res->next;}return 0;
}

4--打印两个有序链表的公共部分

        给定两个有序链表的头指针 head1 和 head2,打印两个链表的公共部分;要求时间复杂度为O(n),额外空间复杂度要求为 O(1);

主要思路:

        类似于归并排序,由于两个链表时有序的,因此可以使用两个指针 i 和 j 分别指向两个链表;

        对于小的链表节点,指针后移;

        当比较到两个指针相等时,打印节点的值,两个指针 i 和 j 同时后移;

#include <iostream>
#include <vector>struct ListNode {int val;ListNode *next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode *next) : val(x), next(next) {}
};class Solution {
public:std::vector<ListNode*> printlist(ListNode* head1, ListNode* head2) {std::vector<ListNode*> res;if(head1 == NULL || head2 == NULL) return res;ListNode *i = head1;ListNode *j = head2;while(i != NULL && j != NULL){// 小的后移if(i->val < j->val) i = i->next;else if(i->val > j->val) j = j->next;else{ // 相等同时后移res.push_back(i);i = i->next;j = j->next;} }return res;}
};int main(int argc, char *argv[]){ListNode *Node1 = new ListNode(1);ListNode *Node2 = new ListNode(2);ListNode *Node3 = new ListNode(5);ListNode *Node4 = new ListNode(0);ListNode *Node5 = new ListNode(2);ListNode *Node6 = new ListNode(3);ListNode *Node7 = new ListNode(5);Node1->next = Node2;Node2->next = Node3;Node4->next = Node5;Node5->next = Node6;Node6->next = Node7;Solution S1;std::vector<ListNode *> res = S1.printlist(Node1, Node4);for(ListNode * node : res) std::cout << node->val << " ";return 0;
}

5--回文链表

主要思路:

        面试做法可以参考反转单向链表,将链表反转,与原链表的结点进行比较即可,当反转链表与原链表的结点不相等,表明不是回文链表;

        空间复杂度 O(n),时间复杂度 O(n);

#include <iostream>
#include <stack>struct ListNode {int val;ListNode *next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode *next) : val(x), next(next) {}
};class Solution {
public:bool isPalindrome(ListNode* head) {if(head == NULL) return true;std::stack<ListNode*> st;ListNode *tmp = head;while(tmp != NULL){st.push(tmp);tmp = tmp->next;}while(!st.empty()){if(head->val != st.top()->val) return false;head = head->next;st.pop();}return true;}
};int main(int argc, char *argv[]){ListNode *Node1 = new ListNode(1);ListNode *Node2 = new ListNode(2);ListNode *Node3 = new ListNode(2);ListNode *Node4 = new ListNode(1);Node1->next = Node2;Node2->next = Node3;Node3->next = Node4;Solution S1;bool res = S1.isPalindrome(Node1);if(res) std::cout << "true" << std::endl;else std::cout << "false" << std::endl;return 0;
}

主要思路:

        笔试解法:上述解法的空间复杂度是 O(n),使用快慢指针将空间复杂度优化为 O(1);

        主要原理是将链表由 1→2→1→2→1 构建为 1→2→1←2←1 的形式,从两端遍历进行比较;

#include <iostream>struct ListNode {int val;ListNode *next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode *next) : val(x), next(next) {}
};class Solution {
public:bool isPalindrome(ListNode* head) {if(head == NULL) return true;ListNode *i = head;ListNode *j = head;while(j->next != NULL && j->next->next != NULL){i = i -> next;j = j -> next -> next;}j = i->next; // right part first nodei->next = NULL;ListNode *tmp = NULL;while(j != NULL){tmp = j->next;j->next = i;i = j;j = tmp;}j = i; // 最后一个结点i = head;while(i != NULL && j != NULL){if(i->val != j ->val) return false;i = i->next;j = j->next;}return true;}
};int main(int argc, char *argv[]){ListNode *Node1 = new ListNode(1);ListNode *Node2 = new ListNode(2);ListNode *Node3 = new ListNode(2);ListNode *Node4 = new ListNode(1);Node1->next = Node2;Node2->next = Node3;Node3->next = Node4;Solution S1;bool res = S1.isPalindrome(Node1);if(res) std::cout << "true" << std::endl;else std::cout << "false" << std::endl;return 0;
}

6--链表调整

        将单向链表按某值划分成左边小、中间相等、右边大的形式;

        题目:给定一个单链表的头结点head,结点的值类型是整型,再给定一个整数pivot,实现一个调整链表的的函数,将链表调整为左部分都是值小于pivot的结点,中间部分都是值等于pivot的结点,右部分都是值大于pivot的结点;

        要求:调整后所有小于、等于或大于pivot的结点之间的相对顺序和调整前一样,时间复杂度为O(n),空间复杂度为O(1);

#include <iostream>struct ListNode {int val;ListNode *next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode *next) : val(x), next(next) {}
};class Solution {
public:ListNode* change(ListNode* head, int pivot) {if(head == NULL) return head;ListNode* SH = NULL; // small headListNode* ST = NULL; // small tailListNode* EH = NULL; // equal headListNode* ET = NULL; // equal tailListNode* LH = NULL; // large headListNode* LT = NULL; // large tailListNode* tmp;while(head != NULL){tmp = head->next; // 下一个结点head->next = NULL;// 抽每一个结点出来进行比较if(head->val < pivot){if(SH == NULL && ST == NULL){SH = head;ST = head;}else{ST->next = head;ST = ST->next;}}else if(head->val == pivot){if(EH == NULL && ET == NULL){EH = head;ET = head;}else{ET->next = head;ET = ET->next;}}else{if(LH == NULL && LT == NULL){LH = head;LT = head;}else{LT->next = head;LT = LT->next;}}head = tmp; // 比较下一个结点}// 首尾相连if(ST != NULL){// 有小于区域ST->next = EH;ET = ET == NULL ? ST : ET; // 没有等于区域,ET变成ST} if(ET != NULL) ET->next = LH;return SH != NULL ? SH : (EH != NULL ? EH : LH);}
};int main(int argc, char *argv[]){ListNode *Node1 = new ListNode(4);ListNode *Node2 = new ListNode(6);ListNode *Node3 = new ListNode(3);ListNode *Node4 = new ListNode(5);ListNode *Node5 = new ListNode(8);ListNode *Node6 = new ListNode(5);ListNode *Node7 = new ListNode(2);Node1->next = Node2;Node2->next = Node3;Node3->next = Node4;Node4->next = Node5;Node5->next = Node6;Node6->next = Node7;Solution S1;int pivot = 5;ListNode* res = S1.change(Node1, pivot);while(res != NULL){std::cout << res->val << " ";res = res->next;}return 0;
}

7--复制含有随机指针结点的链表

主要思路:

        笔试解法,利用哈希表存储结点,即 key 表示原来的结点,value 表示复制的结点;

        存储完毕后,遍历结点设置复制结点的 next 指针和 value 指针即可;

#include <iostream>
#include <unordered_map>class Node {
public:int val;Node* next;Node* random;Node(int _val) {val = _val;next = NULL;random = NULL;}
};class Solution {
public:Node* copyRandomList(Node* head) {std::unordered_map<Node*, Node*> hash;Node *tmp = head;while(tmp != NULL){hash[tmp] = new Node(tmp->val);tmp = tmp->next;}tmp = head;while(tmp != NULL){hash[tmp]->next = hash[tmp->next];hash[tmp]->random = hash[tmp->random];tmp = tmp->next;}return hash[head];}
};int main(int argc, char *argv[]){Node* Node1 = new Node(7);Node* Node2 = new Node(13);Node* Node3 = new Node(11);Node* Node4 = new Node(10);Node* Node5 = new Node(1);Node1->next = Node2;Node2->next = Node3;Node3->next = Node4;Node4->next = Node5;Node1->random = NULL;Node2->random = Node1;Node3->random = Node5;Node4->random = Node3;Node4->random = Node1;Solution S1;Node* res = S1.copyRandomList(Node1);while(res != NULL){std::cout << res->val << " ";res = res->next;}return 0;
}

主要思路:

        面试解法,将空间复杂度优化为 O(1);

        将原链表Ori_Node1 → Ori_Node2 → Ori_Node3 构造成 Ori_Node1 → New_Node1 → Ori_Node2 → New_Node2 → Ori_Node3 → New_Node3;

        接着一对一对地去遍历链表,构建 random 指针;

        最后将新旧链表分离,构建 next 指针即可;

#include <iostream>class Node {
public:int val;Node* next;Node* random;Node(int _val) {val = _val;next = NULL;random = NULL;}
};class Solution {
public:Node* copyRandomList(Node* head) {if (head == NULL) return NULL;Node* tmp = head;Node* next = NULL;while(tmp != NULL){next = tmp->next; // 原链表下一个结点tmp->next = new Node(tmp->val); // 创建新结点tmp->next->next = next; // 新结点指向原链表地下一个结点tmp = next; // 更新tmp}tmp = head; // 遍历构建random指针while(tmp != NULL){next= tmp->next->next; // 一对一对遍历tmp->next->random = tmp->random != NULL ? tmp->random->next : NULL;tmp = next;}// 分离链表并构建next指针tmp = head;Node *res = head->next;Node *copy;while(tmp != NULL){copy = tmp->next;next = tmp->next->next; // 一对一对分离tmp->next= next;copy->next = next != NULL ? next->next : NULL;tmp = next;}return res;}
};int main(int argc, char *argv[]){Node* Node1 = new Node(7);Node* Node2 = new Node(13);Node* Node3 = new Node(11);Node* Node4 = new Node(10);Node* Node5 = new Node(1);Node1->next = Node2;Node2->next = Node3;Node3->next = Node4;Node4->next = Node5;Node1->random = NULL;Node2->random = Node1;Node3->random = Node5;Node4->random = Node3;Node4->random = Node1;Solution S1;Node* res = S1.copyRandomList(Node1);while(res != NULL){std::cout << res->val << " ";res = res->next;}return 0;
}

8--两个单链表相交问题

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SD-MTSP:蜘蛛蜂优化算法SWO求解单仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)

一、蜘蛛蜂优化算法SWO 蜘蛛蜂优化算法&#xff08;Spider wasp optimizer&#xff0c;SWO&#xff09;由Mohamed Abdel-Basset等人于2023年提出&#xff0c;该算法模型雌性蜘蛛蜂的狩猎、筑巢和交配行为&#xff0c;具有搜索速度快&#xff0c;求解精度高的优势。蜘蛛蜂优化算…

Spring Gateway+Security+OAuth2+RBAC 实现SSO统一认证平台

背景&#xff1a;新项目准备用SSO来整合之前多个项目的登录和权限&#xff0c;同时引入网关来做后续的服务限流之类的操作&#xff0c;所以搭建了下面这个系统雏形。 关键词&#xff1a;Spring Gateway, Spring Security, JWT, OAuth2, Nacos, Redis, Danymic datasource, Jav…

竞赛项目 深度学习的口罩佩戴检测 - opencv 卷积神经网络 机器视觉 深度学习

文章目录 0 简介1 课题背景&#x1f6a9; 2 口罩佩戴算法实现2.1 YOLO 模型概览2.2 YOLOv32.3 YOLO 口罩佩戴检测实现数据集 2.4 实现代码2.5 检测效果 3 口罩佩戴检测算法评价指标3.1 准确率&#xff08;Accuracy&#xff09;3.2 精确率(Precision)和召回率(Recall)3.3 平均精…

ASP.NET Core中间件记录管道图和内置中间件

管道记录 下图显示了 ASP.NET Core MVC 和 Razor Pages 应用程序的完整请求处理管道 中间件组件在文件中添加的顺序Program.cs定义了请求时调用中间件组件的顺序以及响应的相反顺序。该顺序对于安全性、性能和功能至关重要。 内置中间件记录 内置中间件原文翻译MiddlewareDe…

【容器化】Oceanbase镜像构建及使用

通过该篇文章可以在国产X86-64或ARM架构上构建商业版oceanbase&#xff0c;只需要替换pkg安装包即可。下面截图主要以国产X86-64安装为例&#xff0c;作为操作截图&#xff1a; 镜像构建目录说明 pkg:用来存放安装包及脚本&#xff0c;抛出rpm其他是脚步&#xff0c;这些rpm包…

直接在html中引入Vue.js的cdn来实现Vue3的组合式API

Vue3的组合式API是使用setup函数来编写组件逻辑的。setup函数是Vue3中用于替代Vue2的选项API&#xff08;如data、methods等&#xff09;的一种方式。在setup函数中&#xff0c;你可以访问到一些特殊的响应式对象&#xff0c;并且可以返回一些可以在模板中使用的数据、方法等。…

Python编程——谈谈函数的定义、调用与传入参数

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 本文专栏&#xff1a;Python专栏 专栏介绍&#xff1a;本专栏为免费专栏&#xff0c;并且会持续更新python基础知识&#xff0c;欢迎各位订阅关注。 目录 一、理解函数 二、函数的定义 1、语法 2、定义一个…

【Linux】内核宏定义解释postcore_initcall,arch_initcall,subsys_initcall

postcore_initcall postcore_initcall(pcibus_class_init) 是一个宏&#xff0c;用于在Linux内核初始化过程中注册一个后期初始化函数。 这个宏的含义如下&#xff1a; postcore_initcall 是一个宏定义&#xff0c;用于指定注册的函数在内核初始化的哪个阶段执行。 pcibus_cl…

deleteDatabase失败处理

准备清理环境时发现deleteDatabase告警&#xff0c;如下图 SYSorcl> startup; ORACLE instance started. Total System Global Area 1.6106E10 bytes Fixed Size 8639712 bytes Variable Size 2449476384 bytes Datab…

CentOS-6.3安装MySQL集群

安装要求 安装环境&#xff1a;CentOS-6.3 安装方式&#xff1a;源码编译安装 软件名称&#xff1a;mysql-cluster-gpl-7.2.6-linux2.6-x86_64.tar.gz 下载地址&#xff1a;http://mysql.mirror.kangaroot.net/Downloads/ 软件安装位置&#xff1a;/usr/local/mysql 数据存放位…

HTTP代理授权方式介绍

在网络爬虫过程中&#xff0c;我们经常需要使用HTTP代理来实现IP隐藏、突破限制或提高抓取效率。而为了确保代理的正常使用&#xff0c;并避免被滥用&#xff0c;代理服务商通常会采用授权方式。在本文中&#xff0c;我们将介绍几种常见的HTTP代理授权方式&#xff0c;以帮助你…

Tomcat部署及优化

Tomcat概述 Tomcat 是 Java 语言开发的&#xff0c;Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器&#xff0c;是 Apache 软件基金会的 Jakarta 项目中的一个 核心项目&#xff0c;由 Apache、Sun 和其他一些公司及个人共同开发而成。在中小型系统和并发访问用户不是…

自建hexo博客并将原有的文章发布其上

1、保存粘贴到memo9中的博客文章&#xff0c;并将txt转换成word文档 varPowerShellPath, CommandLine: string; // , ScriptPath begin//save to txtMemo9.Lines.SaveToFile(test.txt);memo10.Lines.SaveToFile(txt2word.ps1);//save as docxPowerShellPath : powershell.exe…

企业有VR全景拍摄的需求吗?能带来哪些好处?

在传统图文和平面视频逐渐疲软的当下&#xff0c;企业商家如何做才能让远在千里之外的客户更深入、更直接的详细了解企业品牌和实力呢&#xff1f;千篇一律的纸质材料已经过时了&#xff0c;即使制作的再精美&#xff0c;大家也会审美疲劳&#xff1b;但是你让客户远隔千里&…

uniapp 微信小程序 订阅消息

第一步&#xff0c;需要先去小程序官方挑选一下订阅模板拿到模板id 订阅按钮在头部导航上&#xff0c;所以 <u-navbar :bgColor"bgColor"><view class"u-nav-slot" slot"left" click"goSubscribe"><image :src"g…

需要数电发票接口的,先熟悉下数电发票基本常识

最近有一些技术小伙伴来咨询数电发票接口的时候&#xff0c;对数电发票的一些常识不太了解&#xff0c; 导致沟通起来比较困难。比较典型的这三个问题&#xff1a; 一、开具数电票时&#xff0c;如何设置身份认证频次&#xff1f; 请公司的法定代表人或财务负责人登录江苏省电…

uni-app之app上传pdf类型文件

通过阅读官方文档发现&#xff0c;uni.chooseFile在app端不支持非媒体文件上传&#xff1b; 可以使用这个插件&#xff0c;验证过可以上传pdf&#xff1b;具体使用可以去看文档 插件地址 就是还是会出现相机&#xff0c;这个可能需要自己解决下 实现功能&#xff1a;上传只能上…

ejbca:8443报文跟踪

安装客户端证书后&#xff0c;访问管理员页面 :8443/ejbca/adminweb 同时在wireshark抓包 1、客户端向对端发出Client hello 在Server Hello看到一个颁发给客户端的证书&#xff0c;颁发给5be85c9c1df9&#xff08;客户端node hostname 5be85c9c1df9&#xff09;但没有在Clie…

MySQL索引优化分析

MySQL索引优化分析 为什么你写的sql查询慢&#xff1f;为什么你建的索引常失效&#xff1f;通过本章内容&#xff0c;你将学会MySQL性能下降的原因&#xff0c;索引的简介&#xff0c;索引创建的原则&#xff0c;explain命令的使用&#xff0c;以及explain输出字段的意义。助你…

综合技巧练习 - Packet Tracer 简介

1.7.1&#xff1a;综合技巧练习 - Packet Tracer 简介 拓扑图&#xff1a; 以基本完成的逻辑拓扑为起点。 设备 接口 IP 地址 子网掩码 默认网关 R1-ISP Fa0/0 192.168.254.253 255.255.255.0 不适用 S0/0/0 10.10.10.6 255.255.255.252 R2-Central Fa0/0 17…