数据结构—单链表

1、链表的概念及结构

1.1链表的概念

链表是一种物理存储结构上非连续、非顺序的存储结构,但在逻辑上确是连续、顺序的,而数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

1.2链表的结构

如下图:

逻辑上的链表,pList是指向头个元素的指针 

物理上的链表

有人可能会有疑问,不是说链表只是在逻辑结构上是连续的,在物理存储结构上是不连续的,那为什么上图中一个个结点明明是挨在一起的,那么它在物理存储结构上肯定是连续的呀,其实不然,上图是为了方便大家理解,才用线条连接了结点,实际上在内存中,每个结点可能会隔得很远,仔细观察每个结点上面的红色文字,那就是这个结点的地址,而蓝色文字是下一个结点的地址,很明显能看到这两个结点并不是相邻的,因此也验证了顺序表在逻辑结构上确实是连续的,但在物理存储结构上确实是不连续的。

2、链表的实现

2.1 定义结点

介绍一下单链表的英文名——single linked list,我们简写成SL(区别于顺序表的SeqList或者SQL)。

注意:next指针的类型是SListNode*,千万不要写成SLTDataType*,因为next指针是结构体指针,是用来指向下一个结点的

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

2.2链表的功能

链表要实现那些功能呢?其实这些功能我们都很熟悉,数据结构无非是对数据进行管理,要实现数据的增删查改,因此链表的基本功能也都是围绕着数据的增删查改展开。

注意:链表是不需要初始化的

//打印单链表
void SLTPrint(SLTNode* phead);
//创建一个结点
SLTNode* BuyLTNode(SLTDataType x);
//销毁单链表
void SLTDestroy(SLTNode** pphead);
//头插
void SLPushFront(SLTNode** pphead, SLTDataType x);
//尾插
void SLPushBack(SLTNode** pphead, SLTDataType x);
//头删
void SLPopFront(SLTNode** pphead);
//尾删
void SLPopBack(SLTNode** pphead);
// 单链表查找
SLTNode* STFind(SLTNode* phead, SLTDataType x);// 在pos之前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//在pos之后插入
void SLInsertAfter(SLTNode* pos, SLTDataType x);// 删除pos位置的值
void SLErase(SLTNode** pphead, SLTNode* pos);// 删除pos位置后面的值
void SLEraseAfter(SLTNode* pos);// 单链表结点修改
void SLTModify(SLTNode* phead, SLTNode* pos, SLTDataType x);

2.3链表功能实现

2.3.1打印单链表

注意:链表和顺序不同的是,顺序表传过来的指针是肯定不会为空的,而链表传过来的指针是可能为空的,比如说当链表中没有元素时,头指针所指向的就是NULL,如果在第一行写上断言就会有问题。

当cur指向空的时候就可以停止打印了。

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

2.3.2 创建一个新结点

后面我们要在单链表中进行头插和尾插,此时插入的不再是像顺序表一样简单的SLDataType数据了,而是一个结点,这个结点是包括SLTDataType数据以及SLTDataType*的指针,因此,为了方便和减少代码的重复度,我们另写一个函数用来专门创建新结点

SLTNode* BuyLTNode(SLTDataType x)
{SLTNode * newnode=(SLTNode*)malloc(sizeof(SLTNode));if(newnode==NULL){perror("malloc fail");return NULL;}newnode->data=x;newnode->next=NULL;//初始化return newnode;
}

2.3.3 单链表尾插

注意:在创建结点时,已经让 结点.next=NULL,所以不需要在插入完结点后,再让新结点的next指针为NULL。

有人可能会有疑问,为什么之前打印链表的时候不用断言指针,而在尾插时就要断言指针,以及为什么函数的形参是二级指针,而不使用一级指针。

因为,尾插分为两种情况(下面有写),当链表为空时,头指针phead指向NULL,尾插相当于头插,此时要改变phead的指向,让phead指向这个新结点,此时就需要二级指针来改变一级指针的值(如果我们用一级指针做形参,形参的改变不会影响实参,那么一级指针phead就不会被改变)。

至于这个什么时候要断言指针,什么时候不用断言指针:一级指针也就是phead,当链表为空的时候,phead就是为NULL,而二级指针永远指向phead,phead的地址是永远存在的,那么pphead就一定不可能为空,所以需要断言pphead。

//尾插
//第一个尾插需要二级指针,接下来就不用二级指针
//第一次是改变结构的指针plist
//第二次是改变结构体尾结点
void SLPushBack(SLTNode** pphead, SLTDataType x)
{SLTNode *newnode= BuyLTNode(x);//是否为空链表if(*pphead==NULL)*pphead=newnode;//改变结构的指针plistelse{SLTNode *tail=*pphead;while(tail->next!=NULL)//找到链表最后一位,当tail->为空时,就把新开辟的链表节点接上去tail=tail->next;tail->next=newnode;//改变结构体尾结点//就是把newnode存放的新结点地址给tail->next,然后在存放在之前最后一个结点的struct SListNode* next;中,这样next指向的地址不是NULL,而是新加的结点的位置//不能用tail=newnode,因为tail和newnode是局部变量,当这函数结束后就释放了}
}

2.2.4 单链表尾删

要想删除链表中的元素,就必须保证原链表就有元素,因此要断言assert(*pphead)

尾删需要分情况去讨论

//尾删
void SLPopBack(SLTNode** pphead)
{//当没有结点(空链表)//暴力检查assert(*pphead);//温柔检查
//    if(*pphead==NULL)
//        return;//当只有一个结点时if((*pphead)->next==NULL){free(*pphead);*pphead=NULL;}else{SLTNode *prev = NULL;//用来指向倒数第二个结点SLTNode *tail = *pphead;//用来释放最后一个指针空间//找尾while (tail->next) {prev = tail;tail = tail->next;}free(tail);//把最后一个指针空间释放掉prev->next = NULL;//把最后一个的前一个结点指针设为空//如果直接tail=NULL的话,倒数第二个结点就指向一个NULL,就成为了一个野指针//while(tail->next->next)//找到倒数第二个//    tail=tail->next;//free(tail->next);//把倒数第二个结点指向的结构体释放掉//tail->next=NULL;//把倒数第二个结点置为空}
}

2.2.5  单链表头删

头删没什么好说的,记住要断言*pphead,保证链表内容不为空。

//头删
void SLPopFront(SLTNode** pphead)
{//空链表assert(*pphead);//    //一个结点
//    if((*pphead)->next==NULL)
//    {
//        free(*pphead);
//        *pphead=NULL;
//    }
//    //多个结点
//    else
//    {
//        SLTNode *del=*pphead;
//        //*pphead=del->nest;
//        *pphead=(*pphead)->next;
//        free(del);
//    }SLTNode* del = *pphead;*pphead = (*pphead)->next;free(del);}

 2.2.6 单链表头插

现在是不是觉得头插很简单了啊!

//头插
void SLPushFront(SLTNode** pphead, SLTDataType x)
{SLTNode *newnode= BuyLTNode(x);newnode->next= *pphead;*pphead=newnode;//都需要二级指针
}

2.2.7 查找某个结点

这个函数返回值不再是void,而是SLTNode*,把找到的结点的地址返回去,这个函数一般会跟结点修改之类的函数一起使用。

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

2.2.8 删除某个节点

// 删除pos位置的值
void SLErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(pos);//如果只有一个结点if(pos==*pphead)SLPopFront(pphead);else{SLTNode *p1=*pphead;while(p1->next!=pos)p1=p1->next;p1->next=pos->next;free(pos);}
}

注意:

  1. pos也要断言,pos可不能为空呀!
  2. cur->next也要断言,因为当cur->next为NULL时,说明整个链表的结点都排查完了,最后还是没有找到地址为pos的结点,证明pos传值有误。

 2.2.9单链表结点修改

// 单链表结点修改
void SLTModify(SLTNode* phead, SLTNode* pos, SLTDataType x)
{SLTNode* cur=phead;while(cur!=pos){cur=cur->next;assert(cur);}pos->data=x;
}

2.2.10 单链表在pos位前插入结点

// 在pos之前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead);assert(pos);//如果只有一个结点if(*pphead==pos)SLPushFront(pphead,x);else{SLTNode *p1=*pphead;while(p1->next!=pos){p1=p1->next;}SLTNode *newnode= BuyLTNode(x);p1->next=newnode;newnode->next=pos;}
}

2.2.11单链表在pos位后插入结点

//在pos之后插入
void SLInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode *newnode= BuyLTNode(x);newnode->next=pos->next;pos->next=newnode;
}

2.2.12销毁链表

销毁链表这一块,咱可不敢直接free(phead),因为链表在物理结构上是不连续存储的,销毁链表必须要一个结点一个结点去销毁!!!!最后不要忘记把phead置为NULL。

//单链表销毁
void SListDesTroy(SLTNode** pphead)
{assert(pphead && *pphead );SLTNode *pcur=*pphead;while(pcur){SLTNode *next=pcur->next;free(pcur);pcur=next;}*pphead=NULL;}

3、总代码

3.1 SList.h

#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);
//头插
void SLPushFront(SLTNode** pphead, SLTDataType x);
//尾插
void SLPushBack(SLTNode** pphead, SLTDataType x);
//头删
void SLPopFront(SLTNode** pphead);
//尾删
void SLPopBack(SLTNode** pphead);
// 单链表查找
SLTNode* STFind(SLTNode* phead, SLTDataType x);// 在pos之前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//在pos之后插入
void SLInsertAfter(SLTNode* pos, SLTDataType x);// 删除pos位置的值
void SLErase(SLTNode** pphead, SLTNode* pos);// 删除pos位置后面的值
void SLEraseAfter(SLTNode* pos);//单链表销毁
void SListDesTroy(SLTNode** pphead);// 单链表结点修改
void SLTModify(SLTNode* phead, SLTNode* pos, SLTDataType x);

3.2 SList.c

#include "SList.h"void SLTPrint(SLTNode* phead)
{SLTNode* cur=phead;while(cur!=NULL){printf("%d->",cur->data);cur=cur->next;}printf("NULL\n");}//创建一个新的动态内存
SLTNode* BuyLTNode(SLTDataType x)
{SLTNode * newnode=(SLTNode*)malloc(sizeof(SLTNode));if(newnode==NULL){perror("malloc fail");return NULL;}newnode->data=x;newnode->next=NULL;//初始化return newnode;
}//头插
void SLPushFront(SLTNode** pphead, SLTDataType x)
{SLTNode *newnode= BuyLTNode(x);newnode->next= *pphead;*pphead=newnode;//都需要二级指针
}//尾插
//第一个尾插需要二级指针,接下来就不用二级指针
//第一次是改变结构的指针plist
//第二次是改变结构体尾结点
void SLPushBack(SLTNode** pphead, SLTDataType x)
{SLTNode *newnode= BuyLTNode(x);//是否为空链表if(*pphead==NULL)*pphead=newnode;//改变结构的指针plistelse{SLTNode *tail=*pphead;while(tail->next!=NULL)//找到链表最后一位,当tail->为空时,就把新开辟的链表节点接上去tail=tail->next;tail->next=newnode;//改变结构体尾结点//就是把newnode存放的新结点地址给tail->next,然后在存放在之前最后一个结点的struct SListNode* next;中,这样next指向的地址不是NULL,而是新加的结点的位置//不能用tail=newnode,因为tail和newnode是局部变量,当这函数结束后就释放了}
}//头删
void SLPopFront(SLTNode** pphead)
{//空链表assert(*pphead);//    //一个结点
//    if((*pphead)->next==NULL)
//    {
//        free(*pphead);
//        *pphead=NULL;
//    }
//    //多个结点
//    else
//    {
//        SLTNode *del=*pphead;
//        //*pphead=del->nest;
//        *pphead=(*pphead)->next;
//        free(del);
//    }SLTNode* del = *pphead;*pphead = (*pphead)->next;free(del);}//尾删
void SLPopBack(SLTNode** pphead)
{//当没有结点(空链表)//暴力检查assert(*pphead);//温柔检查
//    if(*pphead==NULL)
//        return;//当只有一个结点时if((*pphead)->next==NULL){free(*pphead);*pphead=NULL;}else{SLTNode *prev = NULL;//用来指向倒数第二个结点SLTNode *tail = *pphead;//用来释放最后一个指针空间//找尾while (tail->next) {prev = tail;tail = tail->next;}free(tail);//把最后一个指针空间释放掉prev->next = NULL;//把最后一个的前一个结点指针设为空//如果直接tail=NULL的话,倒数第二个结点就指向一个NULL,就成为了一个野指针//while(tail->next->next)//找到倒数第二个//    tail=tail->next;//free(tail->next);//把倒数第二个结点指向的结构体释放掉//tail->next=NULL;//把倒数第二个结点置为空}
}// 单链表查找
SLTNode* STFind(SLTNode* phead, SLTDataType x)
{SLTNode *cur=phead;while (cur){if(cur->data==x){return cur;}cur=cur->next;}return NULL;
}// 在pos之前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead);assert(pos);//如果只有一个结点if(*pphead==pos)SLPushFront(pphead,x);else{SLTNode *p1=*pphead;while(p1->next!=pos){p1=p1->next;}SLTNode *newnode= BuyLTNode(x);p1->next=newnode;newnode->next=pos;}
}//在pos之后插入
void SLInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode *newnode= BuyLTNode(x);newnode->next=pos->next;pos->next=newnode;
}// 删除pos位置的值
void SLErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(pos);//如果只有一个结点if(pos==*pphead)SLPopFront(pphead);else{SLTNode *p1=*pphead;while(p1->next!=pos)p1=p1->next;p1->next=pos->next;free(pos);}
}// 删除pos位置后面的值
void SLEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next);SLTNode *newnode=pos->next;pos->next=newnode->next;free(newnode);
}//单链表销毁
void SListDesTroy(SLTNode** pphead)
{assert(pphead && *pphead );SLTNode *pcur=*pphead;while(pcur){SLTNode *next=pcur->next;free(pcur);pcur=next;}*pphead=NULL;}
// 单链表结点修改
void SLTModify(SLTNode* phead, SLTNode* pos, SLTDataType x)
{SLTNode* cur=phead;while(cur!=pos){cur=cur->next;assert(cur);}pos->data=x;
}

3.3 text.c

测试函数可以根据大家的想法进行测试,下面是我的测试函数以及输出情况

#include"SList.h"void TestSList1()
{SLTNode* plist = NULL;SLPushFront(&plist, 1);SLPushFront(&plist, 2);SLPushFront(&plist, 3);SLPushFront(&plist, 4);SLTPrint(plist);
}void TestSList2()
{SLTNode *plist=NULL;SLPushFront(&plist, 1);SLPushFront(&plist, 2);SLPushFront(&plist, 3);SLPushFront(&plist, 4);SLPushBack(&plist, 5);SLPushBack(&plist, 6);SLPushBack(&plist, 7);SLPushBack(&plist, 8);SLTPrint(plist);SLTNode *pos= STFind(plist,3);if(pos){SLInsert(&plist,pos,30);}SLTPrint(plist);pos= STFind(plist,6);if(pos){SLInsertAfter(plist,88);}SLTPrint(plist);pos= STFind(plist,7);if(pos){SLErase(&plist,pos);}SLTPrint(plist);pos= STFind(plist,1);if(pos){SLEraseAfter(pos);}SLTPrint(plist);SListDesTroy(&plist);
}void Swapi(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}void Swappi(int** pp1, int** pp2)
{int* tmp = *pp1;*pp1 = *pp2;*pp2 = tmp;
}int main()
{
//    TestSList1();TestSList2();
//    int a = 0, b = 1;
//    Swapi(&a, &b);
//
//    int* px = &a, * py = &b;
//    Swappi(&px, &py);return 0;
}

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

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

相关文章

中断的设备树修改及上机实验(按键驱动)流程

写在前面的话&#xff1a;对于 GPIO 按键&#xff0c;我们并不需要去写驱动程序&#xff0c;使用内核自带的驱动程序 drivers/input/keyboard/gpio_keys.c 就可以&#xff0c;然后你需要做的只是修改设备树指定引脚及键值。 根据驱动文件中的platform_driver中的.of_match_tabl…

gemini国内能用吗

gemini国内能用吗 虽然 Gemini 的具体功能和性能还未完全公开&#xff0c;但基于 Google 在 AI 领域的强大背景和技术实力&#xff0c;已经火出圈了&#xff0c;很多小伙伴已经迫不及待想了解一下它有什么优势以及如何快速使用上 首先我们来讲一下gemini的优势 多模态能力&a…

Python之Excel公式与注释处理秘籍

在日常工作中&#xff0c;我们经常需要处理Excel表格&#xff0c;无论是读取数据、编辑公式还是添加注释。Python中的xlrd和xlwt库就是我们的得力助手。今天&#xff0c;我们就来一起探索如何使用这两个库优雅地应对带有公式和注释的Excel文件。 一、xlrd&#xff1a;读取Exce…

Springboot配置文件(application.yml)的加载顺序

spring boot 启动会扫描一下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件 file…/config/ file…/ classpath:/config classpath:/ 以上是按照优先级从高到低的顺序&#xff0c;所有位置的文件都会被加载&#xff0c;高优先级配置内容会…

C++-命名空间

C 命名空间是一种用于组织代码的机制&#xff0c;可以帮助避免命名冲突&#xff0c;提高代码的可读性和可维护性。命名空间将代码分组到逻辑单元中&#xff0c;允许在不同的代码单元中使用相同的名称而不会产生冲突。 命名空间通过将代码放置在一个命名空间内部来实现。在 C 中…

边缘计算、联邦学习、语义通信、知识蒸馏等,这些在科研方面有什么联系?

在科研领域中&#xff0c;边缘计算、联邦学习、语义通信和知识蒸馏等概念之间存在一定的联系和交叉点。这些概念通常在人工智能、机器学习、计算机视觉等领域中被广泛讨论和应用。 1. **边缘计算**&#xff1a;边缘计算是一种分布式计算架构&#xff0c;旨在将数据处理和存储功…

算法-反转单向链表

需求 思路 链表必有节点&#xff0c;节点两要素&#xff1a;当前元素值&#xff0c;下一个节点地址 import java.util.Scanner;// 定义一个单向链表 public class MyLinkedList<E> {int size 0;// 顶一个私有的内部类&#xff0c;表示链表的节点public class Node {E da…

第十四届蓝桥杯ABD题

A、阶乘求和&#xff1a; 【问题描述】 令 S 1! 2! 3! ... 202320232023! &#xff0c;求 S 的末尾 9 位数字。 提示&#xff1a;答案首位不为 0 。 【答案提交】 这是一道结果填空的题&#xff0c;你只需要算出结果后提交即可。本题的结果为一 个整数&#xff0c;在…

JavaSE 有这一篇就够(呕心狂敲41k字,只为博君一点赞!)

目录 一. 基础语法 1. 数据类型 2. 基本数据类型转换 3. 运算符 3. 循环语句 5. 定义方法 6. 数组 二. 面向对象 1. 类和对象 2. 构造方法 3. 方法的重载 4. this关键字 5. static关键字 6. 代码块 7. 访问权限修饰符 8. 面向对象的三大特征 封装 继承…

你会写SAP技术规格说明书(Specification)吗

有些小伙伴可能还在发愁技术规则说明书应该写什么&#xff0c;做了张思维导图&#xff0c;包含了所有RICEFW。 R - Report - 报表 I - Interface - 接口 C - Conversion - 数据转换 E - Enhancement - 增强 F - Form - 表单 W - Workflow - 工作流

代码随想录算法训练营第四十五天|57.爬楼梯、322.零钱兑换、279.完全平方数

文档链接&#xff1a;https://programmercarl.com/ LeetCode57.爬楼梯 题目链接&#xff1a;https://kamacoder.com/problempage.php?pid1067 思路&#xff1a;每个物品能用多次——完全背包。求排列&#xff0c;遍历顺序要先背包后物品。 动规&#xff1a; #include<…

使用Python实现交叉验证与模型评估

交叉验证是一种评估机器学习模型性能的常用方法&#xff0c;它可以更准确地估计模型在未知数据上的性能。在本文中&#xff0c;我们将介绍交叉验证的原理和常见的几种交叉验证方法&#xff0c;并使用Python来实现这些方法&#xff0c;并展示如何使用交叉验证来评估模型的性能。…

华为OD机试:30 找出通过车辆最多颜色

package a_od_test;import java.util.Arrays; import java.util.Scanner;/* 找出通过车辆最多颜色 知识点滑奩 时间限制&#xff1a;1S空间限制&#xff1a;256MB限定语言&#xff1a;不限 题目描述&#xff1a; 在一个狭小的路口&#xff0c;每秒只能通过一辆车&#xff0c;假…

蓝桥杯刷题-包子凑数

1226. 包子凑数 - AcWing题库 #include <bits/stdc.h>using namespace std;const int N 110; int n , d 0; int a[N]; bool dp[N][10005];int gcd(int a,int b) {return b ? gcd(b , a % b) : a; }int main() {cin >> n;for(int i 1 ;i < n;i ){cin >&g…

【机器学习】数据变换---小波变换特征提取及应用案列介绍

引言 在机器学习领域&#xff0c;数据变换是一种常见且重要的预处理步骤。通过对原始数据进行变换&#xff0c;我们可以提取出更有意义的特征&#xff0c;提高模型的性能。在众多数据变换方法中&#xff0c;小波变换是一种非常有效的方法&#xff0c;尤其适用于处理非平稳信号和…

OpenHarmony网络协议通信c-ares [交叉编译]异步解析器库

简介 c-ares是异步解析器库&#xff0c;适用于需要无阻塞地执行 DNS 查询或需要并行执行多个 DNS 查询的应用程序。 下载安装 直接在OpenHarmony-SIG仓中搜索c-ares并下载。 使用说明 以OpenHarmony 3.1 Beta的rk3568版本为例 将下载的c-ares库代码存在以下路径&#xff1a;…

AI大模型日报#0416:李飞飞《2024年人工智能指数报告》、Sora加入Adobe、李彦宏聊百度大模型之路

​导读&#xff1a; 欢迎阅读《AI大模型日报》&#xff0c;内容基于Python爬虫和LLM自动生成。目前采用“文心一言”生成了每条资讯的摘要。标题: 刚刚&#xff0c;李飞飞团队发布《2024年人工智能指数报告》&#xff1a;10大趋势&#xff0c;揭示AI大模型的“喜”与“忧” 摘…

代码随想录打卡—day27—【回溯】— 回溯基础练习 4.15+4.16

1 39. 组合总和 39. 组合总和 我的AC代码&#xff1a; class Solution { public:vector<vector<int>> ans;vector<int> path;void dfs(int sum,vector<int>& candidates,int target,int start_idx){if(sum > target)return;if(sum target){a…

将 Notepad++ 添加到右键菜单

目录 方式一&#xff1a;添加注册表&#xff08;手动&#xff09; 方式二&#xff1a;添加注册表&#xff08;一键添加&#xff09; 有时安装了notepad后&#xff0c;在txt文件上右键&#xff0c;在弹出的菜单栏中没有【通过 Notepad 打开】&#xff0c;如下&#xff1a; 这…

【面经】2024春招-云计算后台研发工程师1(3个问题,移动TW等)

【面经】2024春招-云计算后台研发工程师1&#xff08;3个问题&#xff0c;移动&TW等&#xff09; 文章目录 岗位与面经基础1&#xff1a;数据库 & 网络&#xff08;3个问题&#xff09;基础2&#xff1a;系统 & 语法模板3&#xff1a;算法 & 项目&#xff08;移…