004——双向链表和循环链表

news2024/11/26 0:50:53

目录

双向链表

双向链表的初始化(与单链表类似)

增:

Ⅰ)头插法

Ⅱ)尾插法

Ⅲ)中间插入

整体代码示例:

 循环链表

循环单链表

​编辑 循环双链表


双向链表

不同于单链表,双向链表不仅可以往后指向,还可以往前指向,则双向链表是在单链表的基础上,每个结点增加一个指针域,这个指针域保存上一个结点的地址

pre指针域

(保存前一个结点的地址)

  数据域

    data

next指针域

(保存后一个结点的地址)

//双向链表的结构体
typedef struct Node {
	struct Node* pre;
	int data;
	struct Node* next;
}Node,*LinkList;

 由003——单链表可知,单链表分为带头结点的不带头结点的,双向链表也是同理(上图的是带头结点的)

双向链表的初始化
(与单链表类似)

LinkList InitLinkList() {
	Node* p = (Node*)malloc(sizeof(Node));//申请头结点
	if (p == NULL) {
		printf("空间分配失败\n");
	}
	else {
		//p->data	脏数据,不用管
		p->pre=p->next = NULL;
		//注意:该语句的执行方向是从右往左
		/*
		p->pre = NULL;
		p->next = NULL;
		*/
	}
	return p;
}
int main() {
	LinkList L = InitLinkList();
}

增:

双向链表中增加一个结点(数据)

Ⅰ)头插法

固定在头结点和首元结点之间插入一个结点(头结点之后)如下图的例子

为了方便分析,我们为示意图进行编号 

注意,在这里对数据进行处理时,我们不能使得这个线(单向的,无论是正向还是负向)断掉,比如像下面这种情况,就是错误

正确的顺序应该是先处理③和④,然后再处理①和②(顺序并不唯一)

 (下面代码并不完整)

//头插法:
LinkList HeadInsert(LinkList L, int k) {
	//先申请一个新的结点用来保存数据k
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL) {
		printf("空间分配失败/n");
	}
	else {
		s->data = k;//将数据传给新申请的结点s
		
		s->pre = L;//3
		s->next = L->next;//4
		L->next= s;//1
		s->next->pre = s;//2

	}
	return L;
}

或者可以写成3421(还有其他写法)

        s->pre = L;
        s->next = L->next;
        L->next->pre = s;
        L->next = s;

此时还要考虑L为空的情况,因为这个时候的②是不存在的

所以在我们更改②这条线之前,需要进行一个判断

//头插法:
LinkList HeadInsert(LinkList L, int k) {
	//先申请一个新的结点用来保存数据k
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL) {
		printf("空间分配失败/n");
	}
	else {
		s->data = k;//将数据传给新申请的结点s
		s->pre = L;//3
		s->next=L->next;//4
		L->next = s;//1
		if (s->next != NULL) {
			s->next->pre = s;//2
		}
	}
	return L;
}

Ⅱ)尾插法

从头结点开始遍历找到尾结点,在尾结点的后面插入新的结点(需要多维护一个pre)

//尾插法
LinkList RearInsert(LinkList L, int k) {
	Node* p = L;	//指针指p向头结点
	while (p->next != NULL) {
		p = p->next;
	}
	//循环结束后指针p指向最后一个结点
	//先申请一个新的结点用来保存数据k
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL) {
		printf("空间分配失败\n");
		return L;
	}
	else {
		s->data = k;//将数据传给新申请的结点s
		s->next = p->next;
		s->pre = p;
		p->next = s;

	}
	return L;
}

Ⅲ)中间插入


//中间插入
//首先需要一个查找函数,并且返回该结点的地址
Node* find(LinkList L, int k) {
	Node* p = L->next;
	while (p != NULL && p->data != k) {
		//出现NULL->data!=k会报错,所以这两项的顺序不可以颠倒
		p = p->next;
	}
	return p;//要么为空,要么保存所要数据
}
//中间插入的函数
Node* MidInsert(LinkList L, int x, int k) {
	//在元素x后面插入数据k
	Node* p = find(L, x);
	if (p == NULL) {
		printf("数据%d不存在,无法找到插入位置,插入失败\n", x);
		return L;
	}
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL) {
		printf("空间分配失败,插入失败\n");
		return L;
	}
	else {
		s->data = k;
		s->next = p->next;
		p->next = s;
		if (s->next != NULL) {
			s->next->pre = s;
		}
	}
	return L;
}

删除如下面图示

修改后的结果

 

//删除
LinkList Delete(LinkList L, int k) {
	if (L->next == NULL) {
		printf("空链表,删除失败\n");
		return L;
	}
	//找到k所在的结点p
	Node* p = find(L, k);
	if (p == NULL) {
		printf("数据%d不存在,删除失败\n");
		return L;
	}
	//删除
	p->pre->next = p->next;
	if (p->next != NULL) {
		p->next->pre = p->pre;
	}
	//防止p成为空指针
	free(p);
	p = NULL;
	return L;
	
}

修改代码与单链表是相同的

//修改
LinkList Replace(LinkList L, int x, int k) {
	Node* p = find(L, x);
	if (p == NULL) {
		printf("数据%d不存在,无法找到修改位置,修改失败\n", x);
		return L;
	}
	else {
		p->data = k;
	}
	return L;
}

查找代码与单链表是相同的

Node* find(LinkList L, int k) {
	Node* p = L->next;
	while (p != NULL && p->data != k) {
		//出现NULL->data!=k会报错,所以这两项的顺序不可以颠倒
		p = p->next;
	}
	return p;//要么为空,要么保存所要数据
}

整体代码示例:

#include<stdio.h>
#include<stdlib.h>
//双向链表的结构体
typedef struct Node {
	struct Node* pre;
	int data;
	struct Node* next;
}Node,*LinkList;

LinkList InitLinkList() {
	Node* p = (Node*)malloc(sizeof(Node));//申请头结点
	if (p == NULL) {
		printf("空间分配失败\n");
	}
	else {
		//p->data	脏数据,不用管
		p->pre=p->next = NULL;
		//注意:该语句的执行方向是从右往左
		/*
		p->pre = NULL;
		p->next = NULL;
		*/
	}
	return p;
}

//头插法:
LinkList HeadInsert(LinkList L, int k) {
	//先申请一个新的结点用来保存数据k
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL) {
		printf("空间分配失败/n");
	}
	else {
		s->data = k;//将数据传给新申请的结点s
		s->pre = L;//3
		s->next=L->next;//4
		L->next = s;//1
		if (s->next != NULL) {
			s->next->pre = s;//2
		}
	}
	return L;
}

//尾插法
LinkList RearInsert(LinkList L, int k) {
	Node* p = L;	//指针指p向头结点
	while (p->next != NULL) {
		p = p->next;
	}
	//循环结束后指针p指向最后一个结点
	//先申请一个新的结点用来保存数据k
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL) {
		printf("空间分配失败\n");
		return L;
	}
	else {
		s->data = k;//将数据传给新申请的结点s
		s->pre = p;//3
		s->next = p->next;//4
		p->next = s;//1
		if (s->next != NULL) {
			s->next->pre = s;//2
		}

	}
	return L;
}


//中间插入
//首先需要一个查找函数,并且返回该结点的地址
Node* find(LinkList L, int k) {
	Node* p = L->next;
	while (p != NULL && p->data != k) {
		//出现NULL->data!=k会报错,所以这两项的顺序不可以颠倒
		p = p->next;
	}
	return p;//要么为空,要么保存所要数据
}
//中间插入的函数
Node* MidInsert(LinkList L, int x, int k) {
	//在元素x后面插入数据k
	Node* p = find(L, x);
	if (p == NULL) {
		printf("数据%d不存在,无法找到插入位置,插入失败\n", x);
		return L;
	}
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL) {
		printf("空间分配失败,插入失败\n");
		return L;
	}
	else {
		s->data = k;
		s->next = p->next;
		p->next = s;
		if (s->next != NULL) {
			s->next->pre = s;
		}
	}
	return L;
}

//修改
LinkList Replace(LinkList L, int x, int k) {
	Node* p = find(L, x);
	if (p == NULL) {
		printf("数据%d不存在,无法找到修改位置,修改失败\n", x);
		return L;
	}
	else {
		p->data = k;
	}
	return L;
}

//删除
LinkList Delete(LinkList L, int k) {
	if (L->next == NULL) {
		printf("空链表,删除失败\n");
		return L;
	}
	//找到k所在的结点p
	Node* p = find(L, k);
	if (p == NULL) {
		printf("数据%d不存在,删除失败\n");
		return L;
	}
	//删除
	p->pre->next = p->next;
	if (p->next != NULL) {
		p->next->pre = p->pre;
	}
	//防止p成为空指针
	free(p);
	p = NULL;
	return L;
	
}


void show(LinkList L) {
	Node* p = L->next;
	while (p != NULL)
	{
		printf("%d\t", p->data);
		p = p->next;
	}
}

int main() {
	LinkList L = InitLinkList();
	L = HeadInsert(L, 10);
	L = HeadInsert(L, 22);
	L = HeadInsert(L, 16);
	L = HeadInsert(L, 45);
	L = RearInsert(L, 77);
	L = MidInsert(L, 77,99);
	L = Delete(L, 10);
	show(L);
	return 0;

}

运行结果

 循环链表

循环单链表

循环链表只需要让最后一个结点的指针域指向头结点

 那么循环链表和单链表几乎没有太大差异,只是在为空的一些位置改成头结点

#include<stdio.h>
#include<stdlib.h>
typedef struct Node {
	int data;		//该节点的数据
	struct Node* next;		
}Node,*LinkList;


//初始化一个带头结点的空的循环链表
LinkList InitLinkList() {
	Node* s = (Node*)malloc(sizeof(Node));//申请头结点
	if (s == NULL) {
		printf("空间分配失败\n");
	}
	else {
		//s->data	脏数据,不用管
		s->next = s;//改变。。。。。。。。。。。。
	}
	return s;
}


//头插法:
LinkList HeadInsert(LinkList L, int k) {
	//先申请一个新的结点用来保存数据k
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL) {
		printf("空间分配失败/n");
	}
	else {
		s->data = k;//将数据传给新申请的结点s
		s->next = L->next;
		L->next = s;
	}
	return L;
}

//尾插法
LinkList RearInsert(LinkList L, int k) {
	Node* p = L;	//指针指p向头结点
	while (p->next != L) {//改变。。。。。。。。。。。。
		p = p->next;
	}
	//循环结束后指针p指向最后一个结点
	//先申请一个新的结点用来保存数据k
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL) {
		printf("空间分配失败\n");
		return L;
	}
	else {
		s->data = k;//将数据传给新申请的结点s
		s->next = p->next;//改变。。。。。。。。。。。。
		p->next = s;
	}
	return L;
}

//中间插入
//首先需要一个查找函数,并且返回该结点的地址
Node* find(LinkList L, int k) {
	Node* p = L->next;
	while (p!=L && p->data != k) {//改变。。。。。。。。。。。。
//出现NULL->data!=k会报错,所以这两项的顺序不可以颠倒
		p = p->next;
	}
	return p;//要么为空,要么保存所要数据
}
//中间插入的函数
Node* MidInsert(LinkList L, int x, int k) {
	//在元素x后面插入数据k
	Node* p = find(L, x);
	if (p == L) {//改变。。。。。。。。。。。。
		printf("数据%d不存在,无法找到插入位置,插入失败\n",x);
		return L;
	}
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL) {
		printf("空间分配失败,插入失败\n");
		return L;
	}
	else {
		s->data = k;
		s->next = p->next;
		p->next = s;
	}
	return L;
}

//修改
LinkList Replace(LinkList L, int x, int k) {
	Node* p = find(L, x);
	if (p == L) {//改变。。。。。。。。。。。。
		printf("数据%d不存在,无法找到修改位置,修改失败\n", x);
		return L;
	}
	else {
		p->data = k;
	}
	return L;
}

//删除
LinkList Delete(LinkList L, int k) {
	if (L->next == L) {//改变。。。。。。。。。。。。
		printf("数据%d不存在,删除失败\n", k);
		return L;
	}
	//找到k所在的结点p和上一个结点
	Node* pre = L;
	Node* p = L->next;
	while (p!=L&&p->data!=k)//改变。。。。。。。。。。。。
	{
		pre = p;
		p = p->next;
	}
	if (p == L) {//改变。。。。。。。。。。。。
		printf("数据%d不存在,删除失败\n", k);
		return L;
	}
	pre->next = p->next;
	free(p);
	p = NULL;//防止p成为野指针
	return L;
}

void show(LinkList L) {
	Node* p = L->next;
	while (p!= L)//改变。。。。。。。。。。。。
	{
		printf("%d\t", p->data);
		p = p->next;
	}
}
int main() {
	LinkList L = NULL;
	L = InitLinkList();
	L=HeadInsert(L,10);
	L = HeadInsert(L, 8);
	L = RearInsert(L, 15);
	L = MidInsert(L, 5, 55);
	L=Replace(L, 8, 88);
	L = Delete(L, 8);
	show(L);
	return 0;
}

运行结果:

 循环双链表

循环双链表与之同理


#include<stdio.h>
#include<stdlib.h>
//双向链表的结构体
typedef struct Node {
	struct Node* pre;
	int data;
	struct Node* next;
}Node, * LinkList;

LinkList InitLinkList() {
	Node* p = (Node*)malloc(sizeof(Node));//申请头结点
	if (p == NULL) {
		printf("空间分配失败\n");
	}
	else {
		//p->data	脏数据,不用管
		//	p->next=p->pre=p;
		p->next = p;
		p->pre = p;
	}
	return p;
}

//头插法:
LinkList HeadInsert(LinkList L, int k) {
	//先申请一个新的结点用来保存数据k
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL) {
		printf("空间分配失败/n");
	}
	else {
		s->data = k;//将数据传给新申请的结点s
		s->pre = L;//3
		s->next = L->next;//4
		L->next = s;//1
		s->next->pre = s;//2
	}
	return L;
}

//尾插法
LinkList RearInsert(LinkList L, int k) {
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL)
	{
		printf("空间分配失败\n");
		return L;
	}
	s->data = k;

	//找尾节点
	Node* p = L;
	while (p->next != L)
	{
		p = p->next;
	}
	s->next = p->next;
	s->pre = p;
	p->next = s;
	s->next->pre = s;
	return L;
}


//中间插入
//首先需要一个查找函数,并且返回该结点的地址
Node* find(LinkList L, int k) {
	//查找数据k所在的节点,并且返回该节点的地址 
	Node* p = L->next;
	while (p != L && p->data != k)
	{
		p = p->next;
	}
	return p;
}
//中间插入的函数
Node* MidInsert(LinkList L, int x, int k) {
	//数据x后插入数据k 
	Node* s = (Node*)malloc(sizeof(Node));
	if (s == NULL)
	{
		printf("空间分配失败\n");
		return L;
	}
	s->data = k;
	//找x所在节点 
	Node* p = find(L, x);
	if (p == L)
	{
		printf("数据%d不存在,插入失败\n", x);
		return L;
	}
	s->pre = p;//3
	s->next = p->next;//4
	p->next = s;//1
	s->next->pre = s;//2
	return L;

}

//修改
LinkList Replace(LinkList L, int x, int k) {
	Node* p = find(L, x);
	if (p == L) {
		printf("数据%d不存在,无法找到修改位置,修改失败\n", x);
		return L;
	}
	else {
		p->data = k;
	}
	return L;
}

//删除
LinkList Delete(LinkList L, int k) {
	if (L->next == L)
	{
		printf("空链表,删除失败\n");
		return L;
	}
	//找k所在的节点p
	Node* p = find(L, k);
	if (p == L)
	{
		printf("数据%d不存在,删除失败\n", k);
		return L;
	}
	//删除:
	p->pre->next = p->next;
	p->next->pre = p->pre;

	free(p);
	p = NULL;
	return L;
}


void show(LinkList L) {
	Node* p = L->next;
	while (p != L)
	{
		printf("%d\t", p->data);
		p = p->next;
	}
}

int main() {
	LinkList L = InitLinkList();
	L = HeadInsert(L, 10);
	L = HeadInsert(L, 22);
	L = HeadInsert(L, 16);
	L = HeadInsert(L, 45);
	L = RearInsert(L, 77);
	L = MidInsert(L, 77, 99);
	L = Delete(L, 10);
	show(L);
	return 0;

}

 运行结果:

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

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

相关文章

亲测可用导航网站源码分享 – 幽络源

幽络源为大家分享一套经过亲测可用的导航网站源码。初看这套PHP源码时&#xff0c;其数据库结构更像是商城系统源码&#xff0c;但经过某位小天才的修改&#xff0c;它已变成一个功能完备的导航网站。经过站长的测试&#xff0c;该源码运行良好&#xff0c;简单部署即可使用&am…

基于springboot的在线租房系统设计与实现

项目描述 这是一款基于springboot的在线租房系统 截图

438.找到字符串中所有字母异位词

题目 链接&#xff1a;leetcode链接 思路分析&#xff08;滑动窗口&#xff09; 很容易想到&#xff0c;这个题目要求我们在字符串s中找到一个定长的窗口让窗口里面出现异位词。 OK&#xff0c;先思考一下怎么快速判断两个字符串是否是异位词&#xff1f; 比较简单的方法是…

AV1 Bitstream Decoding Process Specification:约定

原文地址&#xff1a;https://aomediacodec.github.io/av1-spec/av1-spec.pdf没有梯子的下载地址&#xff1a;AV1 Bitstream & Decoding Process Specification摘要&#xff1a;这份文档定义了开放媒体联盟&#xff08;Alliance for Open Media&#xff09;AV1视频编解码器…

ubuntu配置tftp、nfs

tftp配置 tftp是简单文件传输协议&#xff0c;基于udp实现传输。这里的简单文件&#xff0c;指的是不复杂、开销不大的文件。 先在ubuntu中安装tftp&#xff0c;输入命令&#xff1a;sudo apt-get install tftp-hpa tftpd-hpa。 接着配置tftp。 输入命令&#xff1a;sudo v…

div内英文不换行问题以及解决方案

div内英文不换行问题以及解决方案 div盒子中文字换行问题&#xff1a;div中放中文的代码&#xff1a;div中放英文的代码&#xff1a; 解决办法注意 div盒子中文字换行问题&#xff1a; div设置宽度以后&#xff0c;如果div中放的是中文&#xff0c;默认文字超过div宽度会自动换…

GAF-PCNN-BiLSTM、GASF-CNN-BiLSTM、GADF-CNN-BiLSTM的多特征分类预测/故障诊断

GAF-PCNN-BiLSTM、GASF-CNN-BiLSTM、GADF-CNN-BiLSTM的多特征分类预测/故障诊断 目录 GAF-PCNN-BiLSTM、GASF-CNN-BiLSTM、GADF-CNN-BiLSTM的多特征分类预测/故障诊断分类效果格拉姆矩阵图 基本介绍程序设计参考资料 分类效果 格拉姆矩阵图 基本介绍 1.Matlab实现GAF-PCNN-Bi…

Kerberos:更安全的网络认证协议

简介 Kerberos 是一种网络认证协议&#xff0c;主要用于特定的场景下&#xff0c;代替传统的token方式&#xff0c;以一种更繁琐&#xff0c;但更安全的方式来认证用户信息。它通过票据 (ticket) 机制&#xff0c;确保用户在网络中与服务之间进行加密通信&#xff0c;并且避免…

【云备份】可视化客户端----QT开发➕QT数据库编程

文章目录 一、 需求分析二、 概念结构设计三、逻辑结构设计1. 用户表 (users)2. 客户端本地文件信息表 (upload_files)3. 备份记录表 (backup_records)4. 服务端备份文件信息表 (backup_files) 四、 开发工具五、具体实现&#xff08;一&#xff09; 客户端程序运行演示 一、 需…

7.科学计算模块Numpy(4)ndarray数组的常用操作(二)

引言 书接上回&#xff0c;numpy能作为python中最受欢迎的数据处理模块&#xff0c;脱离不了它最核心的部件——ndarray数组。那么&#xff0c;我们今天就来了解一下numpy中对ndarray的常用操作。 通过阅读本篇博客&#xff0c;你可以&#xff1a; 1.掌握ndarray数组的分割 …

shader 案例学习笔记之smoothstep函数

参考&#xff1a;smoothstep 用来生成0-1的平滑过渡值 smoothstep函数源码实现&#xff1a; float smoothstep(float t1, float t2, float x) {// Scale, bias and saturate x to 0..1 rangex clamp((x - t1) / (t2 - t1), 0.0, 1.0); // Evaluate polynomialreturn x * x *…

@rem和rem用法和区别

在Windows的命令提示符&#xff08;cmd&#xff09;中&#xff0c;rem和rem都是用来注释批处理脚本的。 用法&#xff1a; rem&#xff1a;在一行的开头使用&#xff0c;注释只对当前行有效。rem&#xff1a;也在一行的开头使用&#xff0c;注释会一直持续到下一行。 区别&a…

基于SpringBoot的在线汽车租赁信息管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的在线汽车租赁信息…

STM32 HAL freertos零基础(五) STM32CubeMX配置完成后自定义二值信号量 解决二值信号量初始值为1问题

1、简介 通过上文虽然实现了二值信号量实战&#xff0c;但每次配置STM32CubeMX二值信号量都恢复默认值1&#xff0c;为了解决该问题&#xff0c;对于二值信号量通过CubeMX配置完成后&#xff0c;在程序内自定义二值信号量。 2、文件建立 建立BinarySem文件夹添加BinarySem.c…

Selenium自动化测试网页加载太慢如何解决(超详细)

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 遇到网页加载慢&#xff0c;selenium运行效率降低&#xff0c;可以通过修改页面加载策略提升自动化效率。 selenium加载很慢 通过URL导航到新页面时&#xff0c;…

利用平板电脑和谷歌浏览器进行在线教育学习

在数字化时代&#xff0c;教育的形式越来越多样化&#xff0c;特别是在线教育的兴起为学习带来了前所未有的便利。对于经常在平板电脑上进行学习的用户来说&#xff0c;谷歌浏览器提供了强大的功能&#xff0c;帮助用户更有效地学习。本文将指导您如何在使用平板电脑和谷歌浏览…

系统工程建模MBSE

################################# ############# 片段一 ############## ################################# 下图采用“V”模式显示了集成的基于模型的系统/嵌入式软件开发流程Harmony。左侧描述了自顶向下的设计流程,而右侧显示了自底而上的从单元测试到最终系统验收测试…

‌语音控制小夜灯的实现方案介绍

‌语音控制小夜灯的实现方案组成部分‌ 语音控制小夜灯的实现方案主要包括硬件组装和软件编程两个部分。‌ ‌硬件组装‌涉及将语音声控模块、灯泡、USB连接线等组件正确连接。首先&#xff0c;使用螺丝刀和螺丝将四个隔离柱固定在底板四个拐角处&#xff0c;同时将语音声控模…

Linux CentOS更换阿里云源解决Could not retrieve mirrorlist http://mirrorlist.centos.org

Linux CentOS7 更新yum 操作的时候出现这个问题&#xff1a; Loading mirror speeds from cached hostfile Could not retrieve mirrorlist http://mirrorlist.centos.org 然后我执行 grep -nr "mirrorlist.centos.org" /etc/yum.repos.d/* 出现 这个问题时可以…

2023下半年软考网络规划

【考情分析】2023下半年软考网络规划设计师机考考情分析-真题解析公开课视频&#xff01;_哔哩哔哩_bilibili2023年11月软考网络规划设计师案例分析解析与考后复盘_哔哩哔哩_bilibili全网首发&#xff01;2023年下半年软考【高级】网规真题试卷--案例分析&#xff08;部分回忆版…