单链表各种接口的实现(C)

news2024/9/28 0:28:02

顺序表的优缺点

顺序表的问题

  1. 头部和中部的插入删除效率都不行, O ( N ) O(N) O(N)
  2. 空间不够了,扩容有一定消耗(尤其是异地扩容)开新空间,拷贝数据,释放旧空间
  3. 扩容逻辑,可能还存在空间浪费
    1. 多扩,浪费空间
    2. 少扩,频繁扩容
      顺序表的优点
  4. 尾插尾删足够快
  5. 下标的随机访问和修改
    链表:按需申请释放

单链表

初始化

![[Pasted image 20240913213459.png]]

typedef int SLTDataType;
struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
};

typedef struct SListNode SLTNode;

typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;
  • SLTNode,节点
  • data,数据域
  • next,指针域,是一个结构体指针,不能是数据类型的指针,否则不能指向下一个节点
打印单链表
void PrintList(SLTNode* phead)
{
	SLTNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	
	printf("NULL\n");
}
  • phead存的是第一个节点的地址
  • 把第一个节点赋值给cur,cur指向第一个节点
  • 当cur不为空,访问cur
  • cur->next,取结构体里的值,存的是下一个节点的地址
  • 把cur->next赋给cur,cur指向下一个节点
  • 以此循环,直到cur指向NULL
  • 实际上cur没有动,只是值一直在变化而已
    ![[Pasted image 20240913221329.png]]
  1. 最开始将phead赋给cur
    ![[Pasted image 20240913221504.png]]
  2. cur不为NULL时,将cur->next,也就是下一个节点的地址赋给cur,cur指向下一个节点
    ![[Pasted image 20240913221615.png]]
  3. 直到cur指向NULL,结束
    ![[Pasted image 20240913221703.png]]
构建链表
int main()
{
	SLTNode* n1 = (SLTNode*)malloc(sizeof(SLTNode));
	n1->data = 10;
	
	SLTNode* n2 = (SLTNode*)malloc(sizeof(SLTNode));
	n2->data = 20;
	
	SLTNode* n3 = (SLTNode*)malloc(sizeof(SLTNode));
	n3->data = 30;
	
	n1->next = n2;
	n2->next = n3;
	n3->next = NULL;
	
	PrintSList(n1);
	
	return 0;
}
创建节点
SLTNode* BuySListNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror ("malloc fail");
		exit(-1);
	}

	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}
  • sizeof里是节点的类型,不是SLTDataType
  • 检查新malloc的节点地址是否为空
  • 初始化新节点
尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuySListNode(x);

	if (*pphead == NULL)
	{
		//改变的是结构体指针,要用二级指针
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		//改变的是结构体,用结构体的指针即可
		tail->next = newnode;
	}
}

先创建一个节点
如果单链表没有节点,为第一次插入

  • 将newnode赋给*pphead,也就是把newnode的地址给*pphead*pphead指向newnode。
    ![[Pasted image 20240914220033.png]]
    由于这里要修改的phead是结构体指针,在函数中要修改实参需要通过指针的指针也就是二级指针,再解引用来修改。
    *pphead就是phead
    当单链表中已经有节点
  1. *pphead头节点赋给tail,也就是把第一个节点的地址赋给tail,tail指向第一个节点
    ![[Pasted image 20240914214023.png]]
  2. 将tail->next赋给tail,也就是下一个节点的地址赋给tail,tail指向下一个节点
    ![[Pasted image 20240914214123.png]]
  3. 一直循环,直到tail->next指向NULL停止,也就是tail指向NULL的前一个节点
    ![[Pasted image 20240914214222.png]]
  4. 将newnode赋给tail->next,将next指向的NULL,改为指向newnode
    ![[Pasted image 20240914214348.png]]

尾插完成

  • 改变结构体,要用结构体指针
  • 改变结构体指针,要用结构体指针的指针
头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuySListnode(x);

	newnode->next = *pphead;
	*pphead = newnode;
}
  • newnode是一个结构体
  • *pphead是结构体指针,用结构体指针可以访问这个结构体的数据,也可以通过next找到下一个节点的地址
  1. 将phead赋给newnode->next,新节点的next指向phead
    ![[Pasted image 20240913232032.png]]
    phead存的是第一个节点的地址,等同于
    ![[Pasted image 20240913232203.png]]
  2. 将newnode赋给phead,phead指向newnode,也就是第一个节点
    ![[Pasted image 20240913232240.png]]

完成头插

尾删

不能直接删去最后一个节点,也得把前一个节点的next指向空,否则会造成野指针

void SLTPopBack(SLTNode** pphead)
{
	assert(*pphead);

	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* tailPrev = NULL;
		SLTNode* tail = *pphead;
		while (tail->next)
		{
			tailPrev = tail;
			tail = tail->next;
		}

		free(tail);
		tailPrev->next = NULL;
	
	}
}

如果phead直接是NULL
有可能是调用错误,用assert报错提醒。

当删到最后一个节点时
此时phead指向第一个节点,next指向下一个节点,指向NULL,表示链表只剩最后一个节点
![[Pasted image 20240914222135.png]]
直接free掉phead指针,将phead置为空

链表中还有其他节点时
用tail指针遍历,找最后一个节点
这里如果用一个tail指针,删除掉最后一个节点之后,前一个节点的next指针没有改变,所以需要两个指针跑
再设置一个tailPrev指针,每次tail往下遍历之前,把tail赋给tailPrev,也就是让tailPrev指向当前自己,自己再往后遍历

  1. phead赋给tail,tail指向第一个节点;将tailPrev初始化为NULL
    ![[Pasted image 20240914224531.png]]
  2. 两个指针开始往后遍历,当tail->next指向空结束
    ![[Pasted image 20240914225152.png]]
  3. free掉tail指针,将tailPrev->next置为空
    ![[Pasted image 20240914225227.png]]
    尾删完成

第二种写法

		SLTNode* tail = *pphead;
		while (tail->next->next)
		{
			tail = tail->next;
		}

		free(tail->next);
		tail->next = NULL;

使用一个tail节点,用tail->next->next找到最后一个节点指向的空,这样tail->next指向的就是最后一个节点,free掉最后一个节点也就是tail->next,然后将tail->next,也就是最后一个节点的上一个节点置为空
![[Pasted image 20240914231339.png]]

头删
void SLTPopFront(SLTNode** pphead)
{
	assert(*pphead);


	SLTNode* newhead = (*pphead)->next;
	free(*pphead);
	*pphead = newhead;
}

头删不需要找尾,找到下一个即可
一个节点和多个节点不需要分开讨论,都是将第一个节点删去,链接下一个,无非是一个节点的情况下一个节点是空而已,逻辑是一样的
先断言,phead如果是空,就报错,暴力检查

  1. 将phead->next,也就是第二个节点的地址赋给newhead,newhead指向第二个节点
    ![[Pasted image 20240915090509.png]]
  2. 释放掉phead
    ![[Pasted image 20240915090533.png]]
  3. 将newhead赋给phead,phead指向第二个节点
    ![[Pasted image 20240915090601.png]]
查找

查找只需要遍历链表即可,并不会修改头指针,因此不需要传二级指针

SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}

		cur = cur->next;
	}

	return NULL;
}

创建一个cur指针遍历链表

  1. 将phead赋给cur,cur指向第一个节点
    ![[Pasted image 20240915093541.png]]
  2. 将cur->next赋给cur,cur指向下一个节点,一直循环直到cur指向NULL;如果找到x。就直接返回cur
  3. 如果没有找到x,cur指向空遍历完毕后,就返回NULL
    查找还可以用作修改,用查找函数查找到目标data,然后用pos将返回值接收,再修改pos
    如果返回空的话,链表不会有变化
pos之前插入x

在pos位置之前插入一个值,pos可以是任意位置
pos有可能是头插,需要修改头节点,用二级指针
其余情况需要找到pos位置的前一个,来修改next,单链表中只能从头节点开始遍历整个链表

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pos);

	if (pos == *pphead)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SLTNode* newnode = BuySListNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}

当pos就是头节点,就相当于头插,直接复用之前的函数
当pos为后续节点

  1. 创建一个prev指针,遍历链表来找pos的前一个节点,假如pos是3
    ![[Pasted image 20240915100351.png]]
  2. 创建一个newnode节点,将newnode赋给prev->next,也就是prev->next存newnode的地址,指向newnode
    ![[Pasted image 20240915100529.png]]
  3. 将pos赋值给newnode->next,newnode->next指向pos
    ![[Pasted image 20240915100626.png]]
pos之后插入x

不可能是头插,pos是第一个节点,就是往第一个节点后面插入

void SLTInsertAfter(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

如果pos是NULL,则有可能是传错了,直接报错
复用之前的函数,创建一个节点

  1. 将pos->next赋给newnode->next,newnode->next指向pos的下一个节点
    ![[Pasted image 20240915102238.png]]
  2. 将newnode赋给pos->next,pos->next指向newnode,pos的下一个节点变为newnode
    ![[Pasted image 20240915102325.png]]
删除pos位置

需要找pos前一个节点来断开连接
头删需要处理,因为没有前一个节点
不需要特别处理尾删

void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pos);

	if (pos == *pphead)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
	}
}
  1. 假如pos是2,通过prev找到pos的上一个节点
    ![[Pasted image 20240915103351.png]]
  2. 将pos->next赋给prev->next,prev->next指向pos的下一个节点
    ![[Pasted image 20240915103501.png]]
    最后不需要将pos指针置空,因为函数返回以后,pos就是野指针
删除pos后一个位置

pos可以是任意节点
不能删除头节点
当pos是最后一个节点,没有意义

void SLTEraseAfter(SLTNode** pphead, SLTNode* pos)
{
	assert(pos);
	assert(pos->next);

	SLTNode* posNext = pos->next;
	pos->next = posNext->next;
	free(posNext);
	posNext = NULL;
}

通过断言检查上述两种情况

  1. 通过posNext节点存pos的下一个节点
    ![[Pasted image 20240915104223.png]]
  2. 将posNext->next赋给pos->next,pos->next指向posNext的下一个节点,将posNext断开连接
    ![[Pasted image 20240915104341.png]]
  3. 直接free掉posNext节点,可以置空

声明定义分离实现

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int SLTDataType;

typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

void SLTPrint(SLTNode* phead);

SLTNode* BuySListNode(SLTDataType x);

void SLTPushBack(SLTNode** pphead, SLTDataType x);
void SLTPushFront(SLTNode** pphead, SLTDataType x);
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在pos之前插入x
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//在pos之后插入x
void SLTInsertAfter(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//删除pos位置
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos的后一个位置
void SLTEraseAfter(SLTNode** pphead, SLTNode* pos);

#include"SList.h"

void SLTPrint(SLTNode* phead)
{
	SLTNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}

	printf("NULL\n");
}

SLTNode* BuySListNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror ("malloc fail");
		exit(-1);
	}

	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuySListNode(x);

	if (*pphead == NULL)
	{
		//改变的是结构体指针,要用二级指针
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		//改变的是结构体,用结构体的指针即可
		tail->next = newnode;
	}
}

void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuySListnode(x);

	newnode->next = *pphead;
	*pphead = newnode;
}

void SLTPopBack(SLTNode** pphead)
{
	assert(*pphead);

	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* tailPrev = NULL;
		SLTNode* tail = *pphead;
		while (tail->next)
		{
			tailPrev = tail;
			tail = tail->next;
		}

		free(tail);
		tailPrev->next = NULL;
	
	}
}

void SLTPopFront(SLTNode** pphead)
{
	assert(*pphead);


	SLTNode* newhead = (*pphead)->next;
	free(*pphead);
	*pphead = newhead;
}

SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}

		cur = cur->next;
	}

	return NULL;
}

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pos);

	if (pos == *pphead)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SLTNode* newnode = BuySListNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}

void SLTInsertAfter(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pos);

	if (pos == *pphead)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
	}
}

void SLTEraseAfter(SLTNode** pphead, SLTNode* pos)
{
	assert(pos);
	assert(pos->next);

	SLTNode* posNext = pos->next;
	pos->next = posNext->next;
	free(posNext);
	posNext = NULL;
}
#include"SList.h"

void TestSList1()
{
	int n;
	printf("请输入链表的长度:");
	scanf("%d", &n);
	printf("\n请依次输入每个节点的值");
	SLTNode* plist = NULL;

	for (size_t i = 0; i < n; i++)
	{
		int val;
		scanf("%d", &val);
		SLTNode* newnode = BuySListNode(val);

		//头插
		newnode->next = plist;
		plist = newnode;
	
		if (plist == NULL)
		{
			plist = newnode;
		}
		else
		{
			plist->next;
		}
	}
	SLTPrint(plist);
}

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

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

相关文章

Springboot项目总结

1.为了调用写在其他包里面的类的方法 但是不使用new来实现调用这个类里面的方法&#xff0c;这个时候我们就需要将这个类注入到ioc容器里面&#xff0c;通过ioc容器来实现自动生成一个对象。 对ioc容器的理解&#xff1a;自动将一个对象实现new. 考察了and 和 or组合使用&…

vscode技巧-eslint配置

开发环境 jsvue3axios 下载插件 Eslint、Prettfier 配置过程 1.配置eslint 进入settings&#xff0c;输入eslint&#xff0c;在settings.json中替换一下文件 // #每次保存的时候自动格式化 {"editor.codeActionsOnSave": {"source.fixAll.eslint": &…

海康威视摄像机和录像机的监控与回放

文章目录 海康威视摄像机和录像机的监控与回放1、海康威视监控设备简介1.1、摄像机二次开发1.1.1&#xff1a;协议选择1.1.2&#xff1a;ffmpeg软件转流 2、各种流媒体协议介绍2.1&#xff1a;流媒体协议介绍2.1.1&#xff1a;RTSP (实时流传输协议)2.1.2&#xff1a;RTMP (实时…

Java语言程序设计基础篇_编程练习题**18.26 (创建一个迷宫)

目录 题目&#xff1a;**18.26 (创建一个迷宫) 习题思路 代码示例 输出结果 题目&#xff1a;**18.26 (创建一个迷宫) 编写一个程序&#xff0c;在迷宫中寻找一条路径&#xff0c;如图18-13a所示。该迷宫由一个8 x 8 的棋盘表示。路径必须满足下列条件&#xff1a; 路径在迷…

日志收集工具 Fluentd vs Fluent Bit 的区别

参考链接&#xff1a; FluentdFluentd BitFluentd & Fluent Bit | Fluent Bit: Official Manual Fluentd 与 Fluent Bit 两者都是生产级遥测生态系统&#xff01; 遥测数据处理可能很复杂&#xff0c;尤其是在大规模处理时。这就是创建 Fluentd 的原因。 Fluentd 不仅仅是…

国产化中间件正在侵蚀开源中间件

开源中间件的发展趋势表明&#xff0c;它们将继续在技术创新和生态建设中发挥重要作用&#xff0c;尤其是在云计算、大数据等新兴技术领域。开源中间件如Apache Kafka、RabbitMQ、ActiveMQ和RocketMQ等在市场上有着广泛的应用。它们在技术社区中得到了良好的支持&#xff0c;并…

k8s中控制器的使用

目录 一、什么是控制器 二、控制器常用类型 三、replicaset控制器 1、replicaset功能 2、replicaset参数说明 3、replicaset示例 四、deployment控制器 1、deployment控制器的功能 2、deployment控制器示例 &#xff08;1&#xff09;版本迭代 &#xff08;2&#x…

MySql的基础讲解

一、初识MySql 数据库&#xff1a;按照数据结构来组织、存储和管理数据的仓库&#xff1b;是一个长期存储在计算机内的、有组织的、可共享 的、统一管理的大量数据的集合&#xff1b; OLTP&#xff1a;联机事务处理&#xff0c;主要是对数据库的增删改查。 OLTP 主要用来记录…

【研赛论文】数学建模2024华为杯论文word/latex模板

国赛结束&#xff0c;研究生瞩目的研赛马上就要来了&#xff0c;相信研究生同学也是在努力的准备当中&#xff0c;在这里祝愿大家能够获得一个好的名次。一举冲出重围&#xff0c;拿下国奖。在数模比赛当中&#xff0c;论文是参赛者唯一能够与评阅老师进行沟通的方式&#xff0…

【Python爬虫系列】_021.异步请求aiohttp

课 程 推 荐我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈

本地部署大模型并使用知识库Windows下Ollama+Docker+MaxKB安装的记录

概要 本文介绍本地部署大模型和知识库的小白方法&#xff0c;可以运行较多种类的大模型&#xff0c;使用的软件为docker和ollama以及MaxKb作为知识库前端。 下载 各安装包可以百度去官网或者github下载或使用&#xff0c;也可以点击下面的的链接和我下载相同的版本。 ollama…

uniapp child.onFieldChange is not a function

uni-forms // 所有子组件参与校验,使用 for 可以使用 awiatfor (let i in childrens) {const child childrens[i];let name realName(child.name);if (typeof child.onFieldChange function) {const result await child.onFieldChange(tempFormData[name]);if (result) {…

如何准备教师资格证科目三“学科知识与教学能力”的考试与面试?(理科导向:数学/物理)

如何准备教师资格证科目三“学科知识与教学能力”的考试与面试&#xff1f;&#xff08;理科导向&#xff1a;数学/物理&#xff09; ​ 目录 收起 1 前言 1.1 自身经历 1.2 教师资格证的作用 2 知识点题型分数的分布与学习建议 2.1 科目三的知识点分数分布&#xff1a; …

Python 全栈系列271 微服务踩坑记

说明 这个坑花了10个小时才爬出来 碰到一个现象&#xff1a;将微服务改造为并发后&#xff0c;请求最初很快&#xff0c;然后就出现大量的失败&#xff0c;然后过一会又能用。 过去从来没有碰到这个问题&#xff0c;要么是一些比较明显的资源&#xff0c;或者逻辑bug&#xff0…

Matlab simulink建模与仿真 第十三章(信号通路库)

参考视频&#xff1a;simulink1.1simulink简介_哔哩哔哩_bilibili 一、信号通路库中的模块概览 1、信号通路组 注&#xff1a;部分模块在第二章中有介绍&#xff0c;本章不再赘述。 2、信号存储和访问组 二、总线分配模块 Bus Assignment模块接受总线作为输入&#xff0c;并…

Python之NumPy超详细学习指南:从入门到精通(上篇)

文章目录 Python NumPy学习指南&#xff1a;从入门到精通第一部分&#xff1a;NumPy简介与安装1. 什么是NumPy&#xff1f;2. 安装NumPy使用pip安装&#xff1a;使用Anaconda安装&#xff1a; 第二部分&#xff1a;NumPy数组基础1. NumPy数组的创建从列表创建一维数组&#xff…

Proxyless Service Mesh:下一代微服务架构体系

一、项目背景及意义 在当今的微服务架构中&#xff0c;应用程序通常被拆分成多个独立的服务&#xff0c;这些服务通过网络进行通信。这种架构的优势在于可以提高系统的可扩展性和灵活性&#xff0c;但也带来了新的挑战&#xff0c;比如&#xff1a; 服务间通信的复杂性&#…

Cisco Modeling Labs (CML) 2.7.2 发布下载,新增功能概览

Cisco Modeling Labs (CML) 2.7.2 - 网络仿真工具 思科建模实验室 (CML) 请访问原文链接&#xff1a;https://sysin.org/blog/cisco-modeling-labs-2/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org Cisco Modeling Labs 是我…

Geneformer中文教程(2).huggingface transformers

Geneformer基于hugging face的transformers实现&#xff0c;具体模型是BertForSequenceClassification&#xff0c;本篇先熟悉该模型。 首先直观看Geneformer的模型架构&#xff0c;基于BERT构建一个文本分类模型&#xff0c;我们直接从预训练的Geneformer加载BERT&#xff0c…

Linux相关:在阿里云下载centos系统镜像

文章目录 1、镜像站2、下载方式一2.1、第一步打开镜像站地址2.2 下载地址: https://mirrors.aliyun.com/centos/2.3、选择7版本2.4、镜像文件在isos文件夹中2.5、选择合适的版本 3、下载镜像快捷方式 1、镜像站 阿里云镜像站地址 2、下载方式一 2.1、第一步打开镜像站地址 2…