数据结构与算法学习笔记一---线性表的实现(C语言)

目录

2.线性表的实现

1.线性表的顺序存储表示

1.定义

2.初始化

3.判断是否为空表

4.求表长

5.查找

6.查询直接前驱节点

7.查询直接后继节点

8. 插入顺序表插入

9.删除节点

10.遍历顺序表

11.完整代码

2.线性表的链式存储表示

1.定义

2.初始化

3.判断是否为空表

4.求表长

5.查找

6.查询直接前驱节点

7.查询直接后继节点

8. 插入

9.删除节点

10.遍历顺序表

11.完整代码


    由n(n≥0)个数据特性相同的元素构成的有限序列称为线性表。线性表中元素的个数n(n≥0)定义为线性表的长度,n=0时称为空表。对于非空的线性表或线性结构,其特点是:
(1)存在唯一的一个被称作“第一个”的数据元素;
(2)存在唯一的一个被称作“最后一个”的数据元素;
(3)除第一个之外,结构中的每个数据元素均只有一个前驱;
(4)除最后一个之外,结构中的每个数据元素均只有一个后继

2.线性表的实现

        线性表有顺序存储和链式存储两种表示方法。

1.线性表的顺序存储表示

        顺序表是一种线性表的存储结构,它用一组地址连续的存储单元依次存储线性表的数据元素。顺序表中的元素在物理位置上是连续存储的,这使得顺序表在存取元素时具有良好的随机访问性能。

        在 C 语言中,顺序表通常通过数组来实现。每个元素在数组中的下标可以作为该元素在顺序表中的位置,因此可以直接通过下标访问或修改元素,具有较高的访问效率。

1.定义

#define MAXSIZE 100 //顺序表的最大长度
#define ElementType int

typedef struct {
    ElementType *element; // 存储空间基地址
    int length;           // 当前长度
} SeqList;

2.初始化

        初始化线性表的时候,我们需要先给线性表分配存储空间,然后把线性表的表长置空。

// 初始化
int initSeqList(SeqList *seqList) {
    seqList->element = (ElementType *)malloc(sizeof(ElementType) * MAXSIZE);
    if (seqList->element == NULL) { // 初始化失败
        printf("初始化分配空间失败!\n");
        return 0;
    }
    seqList->length = 0;
    return 1;
}

3.判断是否为空表

int seqListIsEmpty(SeqList *seqList){
    return seqList->length == 0;
}

4.求表长

int seqListLength(SeqList *seqList){
    int length = seqList->length;
    return length;
}

5.查找

        一个是根据下标查找,这种查找结构是唯一的。还有就是根据元素查找,这里返回的是第一个和要查找的元素相同的元素下标。

int getElement(SeqList *seqList,int location,int * element){
    if (location < 1 || location > seqList->length) {
        printf("非法位置\n");
        return 0;
    }
    if (seqList->length < 1) {
        printf("非法顺序表");
        return 0;
    }
    * element = seqList->element[location-1];
    return 1;
}
int getLocate(SeqList *seqList,ElementType element){
    for (int i = 0; i<seqList->length; i++) {
        if (seqList->element[i] == element) {
            return i;
        }
    }
    return -1;
}

6.查询直接前驱节点

        遍历顺序表,先查看节点是否存在,在查看前驱节点。

// 查询直接前驱节点
int priorElement(SeqList *seqList,ElementType element, ElementType * previousLlement){
    int hasExistElement = 0;
    int index = -1;
    for (int i = 0; i < seqList->length ; i++) {
        if (seqList->element[i] == element) {
            index = i;
            hasExistElement = 1;
        }
    }
    if (hasExistElement) {
        if (index <= 0) {//第1个元素没有前驱节点
            return 0;
        } else {
            * previousLlement = seqList->element[index - 1];
            return 1;
        }
    } else {
        return 0;
    }
}

7.查询直接后继节点

        遍历顺序表,先查看节点是否存在,在判断是否有后继节点。

// 查询直接后继节点
int nextElement(SeqList *seqList,ElementType element, ElementType * nextElement){
    int hasExistElement = 0;
    int index = -1;
    for (int i = 0; i < seqList->length ; i++) {//判断后继节点是否存在
        if (seqList->element[i] == element) {
            index = i;
            hasExistElement = 1;
        }
    }
    if (hasExistElement) {
        if (index >= seqList->length-1) {//最后一个节点没有后继节点
            return 0;
        } else {
            * nextElement = seqList->element[index + 1];
            return 1;
        }
    } else {
        return 0;
    }
}

8. 插入顺序表插入

        判断下要插入的位置是否合法以及存储空间是否已经满了。

// 插入顺序表插入
void insertSeqList(SeqList *seqList, int location, ElementType  element) {
    if (location < 1 || location > seqList->length + 1) {
        printf("插入位置非法,insertSeqList方法插入❎\n");
        return;
    }
    if (seqList->length == MAXSIZE) {//存储空间已满
        printf("数组存储已满");
        return ;
    }
    for (int j = seqList->length; j >= location; j--) {
        seqList->element[j] = seqList->element[j - 1];
    }
    seqList->element[location - 1] = element;
    seqList->length++;
    printf("insertSeqList方法插入✅\n");
}

9.删除节点

        遍历顺序表,根据下标找到要删除掉元素,表长减一。

// 删除节点
int deleteElement(SeqList *seqList,int position){
    if (position < 1 || position > seqList->length) {//非法位置
        return 0;
    }
    for (int i = position - 1; i<seqList->length -1; i++) {
        seqList->element[i] = seqList->element[i+1];
    }
    seqList->length--;
    return 1;
}

10.遍历顺序表

        我们使用for循环遍历顺序表。

// 遍历顺序表
void traverseList(SeqList *seqList){
    for (int i = 0; i < seqList->length; i++) {
        printf("%d\t", seqList->element[i]);
    }
    printf("\n");
}

11.完整代码

        在这里。

2.线性表的链式存储表示

        线性表的链式存储表示使用链表来实现。链表是一种数据结构,由一系列节点组成,每个节点包含数据元素和指向下一个节点的指针(或链接)。在链表中,每个节点的地址不一定是连续的,而是通过指针相互链接起来。

        线性表的链式存储表示具有动态的内存分配特性,可以根据需要动态地分配和释放内存,因此可以有效地利用内存空间,并且不受固定大小的限制。此外,链式存储结构支持高效的插入和删除操作,但访问元素时需要遍历链表,效率较低。

1.定义

#define ElementType int

typedef struct LNode{
    ElementType data;//数据域
    struct LNode * next; //指针域
}LNode,*LinkList; //LinkList为指向结构体LNode的指针

2.初始化

        初始化线性表的时候,我们需要先给线性表分配存储空间,然后把线性表的表长置空。

// 初始化
int initSeqList(SeqList *seqList) {
    seqList->element = (ElementType *)malloc(sizeof(ElementType) * MAXSIZE);
    if (seqList->element == NULL) { // 初始化失败
        printf("初始化分配空间失败!\n");
        return 0;
    }
    seqList->length = 0;
    return 1;
}

3.判断是否为空表

int LinkListEmpty(LinkList linkList){
    if (linkList->next == NULL) {
        return 1;
    }
    return 0;
}

4.求表长

int linkListLength(LinkList list){
    LNode * head = list;//头结点
    int length = 0;

    while (head->next != NULL) {
        head = head->next;
        length++;
    }
    return length;
}

5.查找

        一个是根据下标查找,这种查找结构是唯一的。还有就是根据元素查找,这里返回的是第一个和要查找的元素相同的元素下标。

//
int getElement(LinkList linkList,int i,int * element){
    LNode *current = linkList->next; // 从头结点的下一个节点开始遍历
    int j = 1;
    while (current != NULL && j< i) {
        printf("第%d个元素的值为:%d \n",j, current->data);
        current = current->next;
        j++;
    }
    if (!current || j > i) {//第i个元素不存在
        return 0;
    }
    * element = current->data;
    
    return 1;
}

6.查询直接前驱节点

        遍历单链表,先查看节点是否存在,在查看前驱节点。

// 查找单链表中的元素的前驱节点
int getPriorElement(LinkList linkList,int element,int * previousElement){
    LNode * previous = linkList;      // 头结点
    LNode * current = linkList->next; // 头结点的下一个节点
    while (current != NULL &&current->data != element) {
        previous  = current;
        current = current-> next;
    }
    if (previous->next == NULL) {
        return 0;
    }else{
        * previousElement = previous->data;
        return 1;
    }
}

7.查询直接后继节点

        遍历单链表,先查看节点是否存在,在判断是否有后继节点。

// 查找单链表中的元素的后继节点
int getNextElement(LinkList linkList,int element,int * nextElement){
    LNode * current = linkList->next; // 头结点的下一个节点
    while (current != NULL &&current->data != element) {
        current = current-> next;
    }
    if (current->next == NULL) {
        return 0;
    }else{
        * nextElement = current->next->data;
        return 1;
    }
}

8. 插入

        申请一个新的节点,修改要插入的节点的位置的指针域。

// 向链表中插入一个新的节点(在链表头部插入)
void insertLinkList(LinkList L, int value) {
    LNode *newNode = (LNode *)malloc(sizeof(LNode));
    if (!newNode) {
        exit(1); // 分配内存失败则退出
    }
    newNode->data = value;
    newNode->next = L->next; // 新节点的next指向原头结点后面的节点
    L->next = newNode; // 头结点的next指向新节点
}

9.删除节点

        我们需要找到要删除的节点的前驱节点,然后修改前驱节点的指针域。

// 删除单链表
void deleteLinkList(LinkList linkList, int value) {
    LNode * current = linkList; // 头结点的下一个节点
    int j = 0;
    while (current != NULL && j < value -1) {//找到要删除节点的前驱节点
        current = current-> next;
        ++j;
    }
    //生成一个新节点
    LNode *newNode = (LNode *)malloc(sizeof(LNode));
    if (newNode == NULL) {//内存分配失败
        return;
    }
    if (!(current->next)|| j > value-1) {
        return ;
    }
    newNode = current->next;//指向要删除的节点
    current->next = newNode->next;
    free(newNode);
}

10.遍历顺序表

        我们使用for循环遍历顺序表。

// 打印链表中的所有元素
void printLinkList(LinkList L) {
    LNode *current = L->next; // 从头结点的下一个节点开始遍历
    while (current != NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}

11.完整代码

#include <stdio.h>
#include <stdlib.h>
  
// 定义链表节点的结构体
typedef struct LNode {
    int data;                // 数据域
    struct LNode *next;     // 指针域,指向下一个节点
} LNode, *LinkList;
  
// 初始化链表,创建一个空链表
void inintLinkList(LinkList * linkList) {
    * linkList = (LinkList)malloc(sizeof(LNode));
    if (!*linkList) {
        exit(1); // 分配内存失败则退出
    }
    (*linkList)->next = NULL; // 初始化头结点的指针域为空
}
int LinkListEmpty(LinkList linkList){
    if (linkList->next == NULL) {
        return 1;
    }
    return 0;
}
int linkListLength(LinkList list){
    LNode * head = list;//头结点
    int length = 0;

    while (head->next != NULL) {
        head = head->next;
        length++;
    }
    return length;
}
// 查找单链表中的元素
int getElement(LinkList linkList,int i,int * element){
    LNode *current = linkList->next; // 从头结点的下一个节点开始遍历
    int j = 1;
    while (current != NULL && j< i) {
        printf("第%d个元素的值为:%d \n",j, current->data);
        current = current->next;
        j++;
    }
    if (!current || j > i) {//第i个元素不存在
        return 0;
    }
    * element = current->data;
    
    return 1;
}
// 查找单链表中的元素的前驱节点
int getPriorElement(LinkList linkList,int element,int * previousElement){
    LNode * previous = linkList;      // 头结点
    LNode * current = linkList->next; // 头结点的下一个节点
    while (current != NULL &&current->data != element) {
        previous  = current;
        current = current-> next;
    }
    if (previous->next == NULL) {
        return 0;
    }else{
        * previousElement = previous->data;
        return 1;
    }
}

// 查找单链表中的元素的后继节点
int getNextElement(LinkList linkList,int element,int * nextElement){
    LNode * current = linkList->next; // 头结点的下一个节点
    while (current != NULL &&current->data != element) {
        current = current-> next;
    }
    if (current->next == NULL) {
        return 0;
    }else{
        * nextElement = current->next->data;
        return 1;
    }
}
  
// 向链表中插入一个新的节点(在链表头部插入)
void insertLinkList(LinkList L, int value) {
    LNode *newNode = (LNode *)malloc(sizeof(LNode));
    if (!newNode) {
        exit(1); // 分配内存失败则退出
    }
    newNode->data = value;
    newNode->next = L->next; // 新节点的next指向原头结点后面的节点
    L->next = newNode; // 头结点的next指向新节点
}
// 删除单链表
void deleteLinkList(LinkList linkList, int value) {
    LNode * current = linkList; // 头结点的下一个节点
    int j = 0;
    while (current != NULL && j < value -1) {//找到要删除节点的前驱节点
        current = current-> next;
        ++j;
    }
    //生成一个新节点
    LNode *newNode = (LNode *)malloc(sizeof(LNode));
    if (newNode == NULL) {//内存分配失败
        return;
    }
    if (!(current->next)|| j > value-1) {
        return ;
    }
    newNode = current->next;//指向要删除的节点
    current->next = newNode->next;
    free(newNode);
}

  
// 打印链表中的所有元素
void printLinkList(LinkList L) {
    LNode *current = L->next; // 从头结点的下一个节点开始遍历
    while (current != NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}
  
// 释放链表占用的内存
void FreeList(LinkList L) {
    LNode *current = L, *temp;
    while (current != NULL) {
        temp = current;
        current = current->next;
        free(temp);
    }
}
 
void printDebugInformation(char * string){
    printf("\n********** %s **********\n",string);

}
int main(int argc, const char *argv[]) {
    LinkList linkList;
    inintLinkList(&linkList); // 初始化链表
  //测试链表是否为空
    if (LinkListEmpty(linkList)) {
        printf("链表为空!\n");
    }else{
        printf("链表不为空!\n");
    }
    // 插入一些节点到链表中
    insertLinkList(linkList, 1);
    insertLinkList(linkList, 2);
    insertLinkList(linkList, 3);
    insertLinkList(linkList, 4);
    insertLinkList(linkList, 5);

    if (LinkListEmpty(linkList)) {
        printf("链表为空!\n");
    }else{
        printf("链表不为空!\n");
        int length = linkListLength(linkList);
        printf("链表长度:%d\n",length);
    }
    // 打印链表
    printLinkList(linkList);
    //测试查找方法
    int element;
    if (getElement(linkList, 1, &element)) {
        printf("链表第%d个元素为:%d\n",1,element);
    }else{
        printf("链表元素查找失败\n");
    }
    //测试前驱节点查找方法
    printDebugInformation("测试前驱节点");
    if (getPriorElement(linkList, 1, &element)) {//头结点
        printf("链表中1的前驱节点为:%d\n",element);
    }else{
        printf("没有前驱节点\n");
    }
    if (getPriorElement(linkList, 3, &element)) {//头结点
        printf("链表中3的前驱节点为:%d\n",element);
    }else{
        printf("没有前驱节点\n");
    }
    //测试后继节点
    printDebugInformation("测试后继节点");
    if (getNextElement(linkList, 5, &element)) {//头结点
        printf("链表中5的后继节点为:%d\n",element);
    }else{
        printf("5没有后继节点\n");
    }
    if (getNextElement(linkList, 4, &element)) {//头结点
        printf("链表中4的后继节点为:%d\n",element);
    }else{
        printf("4没有后继节点\n");
    }
    if (getNextElement(linkList, 3, &element)) {//头结点
        printf("链表中3的后继节点为:%d\n",element);
    }else{
        printf("没有后继节点\n");
    }
    if (getNextElement(linkList, 2, &element)) {//头结点
        printf("链表中2的前驱节点为:%d\n",element);
    }else{
        printf("2没有后继节点\n");
    }
    if (getNextElement(linkList, 1, &element)) {//头结点
        printf("链表中1的前驱节点为:%d\n",element);
    }else{
        printf("1没有后继节点\n");
    }
    
    printDebugInformation("测试删除节点");
    printf("删除之前的单链表:\n");
    printLinkList(linkList);
    deleteLinkList(linkList, 3);
    printf("删除之后的单链表:\n");
    printLinkList(linkList);
    
    

//    // 释放链表内存
    FreeList(linkList);
  
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis 核心配置讲解(上)

大家好&#xff0c;我是王有志&#xff0c;一个分享硬核 Java 技术的互金摸鱼侠。 前两篇的文章中我们分别介绍了 MyBatis 和 MyBaits 的应用组成&#xff0c;到这里基础篇的内容就结束了。 从今天开始&#xff0c;我们正式进入 MyBatis 学习的第二阶段&#xff1a;MyBatis 的…

【QT学习】9.绘图,三种贴图,贴图的转换,不规则贴图(透明泡泡),简单绘图工具制作

一。绘图的解释 Qt 中提供了强大的 2D 绘图系统&#xff0c;可以使用相同的 API 在屏幕和绘图设备上进行绘制&#xff0c;它主要基于QPainter、QPaintDevice 和 QPaintEngine 这三个类。 QPainter 用于执行绘图操作&#xff0c;其提供的 API 在 GUI 或 QImage、QOpenGLPaintDev…

maya blendshape

目录 shape编辑器 maya创建blendshape python 脚本 添加形变动画 查看顶点个数 shape编辑器 打开方式&#xff1a; 窗口-动画编辑器-形变编辑器 maya创建blendshape python 脚本 import maya.cmds as cmds# 创建基础网格 - 球体 baseMesh cmds.polySphere(name"bas…

Postman 工具发送请求的技巧与实践

在开发和测试 API 时&#xff0c;发送 JSON 格式的请求是一个常见需求。 在 Postman 中构建和发送 JSON 请求 创建一个新的请求 首先&#xff0c;在 Postman 启动界面上找到并点击 “New” 按钮&#xff0c;选择 “HTTP Request” 来开始新建一个请求。这一步骤允许你定义请…

Unity射击游戏开发教程:(7)Powerup的使用

确定 PowerUp 效果应持续多长时间 我在游戏中放置的第一个道具是三重射击。当玩家收集三重射击能量时,他们可以一次发射 3 束激光,而正常情况下只能发射 1 束激光。在实施道具时,您需要考虑它们的功能以及它将如何影响游戏玩法。至于三连射&

Linux-缓冲区(简单理解)

1. 缓冲区是什么 缓冲区就是一段内存空间。 2. 为什么要有缓冲区 IO写入有两种&#xff1a; 写透模式&#xff08;WT&#xff09; 成本高&#xff0c;效率低写回模式&#xff08;WB&#xff09; 成本低&#xff0c;效率高 写透模式&#xff1a;每次的文件写入都要立即刷新…

海外仓WMS管理系统:标准化海外仓管理模式,效率和管理模式双提升

就目前的跨境电商发展速度和体量来看&#xff0c;标准化海外仓管理的模式不再是一个选项&#xff0c;而是必走之路。 今天会重点和大家聊一下&#xff0c;海外仓企业应该如何利用好WMS管理系统&#xff0c;快速的标准化仓库管理的模式&#xff0c;以及大家比较关心的&#xff0…

JAVA读取文件完成词频统计

词频统计原数据和结果数据地址&#xff1a;https://download.csdn.net/download/LiHaoHang6/88845654?spm1001.2014.3001.5501 运行效果展示&#xff1a; 原数据展示&#xff1a; 词频统计思路&#xff1a; 1&#xff1a;先通过BufferedReader来读取本地文本文件,之后将文本…

excel 按照姓名日期年月分组求和

excel 需要按照 姓名 日期的年份进行金额求和统计&#xff0c;采用sumifs 进行统计 注意&#xff1a;sumifs 不支持 合并列拆分计算&#xff0c;合并列只会计算一个值 表格数据大概如下&#xff1a;(sheet) ABC姓名日期金额A2023/01/01500A2023/01/151500B2023/01/01200B202…

基于SpringBoot开发的同城租房系统租房软件APP小程序源码

项目背景 一、市场前景 随着城市化进程的加快和人口流动性的增强&#xff0c;租房市场正逐渐成为一个不可忽视的巨大市场。传统的租房方式往往存在着信息不对称、效率低下等问题&#xff0c;而同城租房软件的出现&#xff0c;则有效地解决了这些问题&#xff0c;为租房市场注…

云计算时代,企业面临的云安全风险

如今&#xff0c;随着云计算等新兴科技的发展&#xff0c;不同类型企业间的关联越来越多&#xff0c;它们之间的业务边界已被打破&#xff0c;企业上云成为了大势所趋。云计算应用帮助企业改变了IT资源不集中的状况&#xff0c;同时&#xff0c;数据中心内存储的大量数据信息&a…

Mediator 中介者

意图 使用一个中介者对象来封装一系列的对象交互。中介者使各个对象不需要显式地互相引用&#xff0c;从而使其耦合松散&#xff0c;而且可以独立的改变他们之间的交互。 结构 Mediator&#xff08;中介者&#xff09;定义一个接口用于各同事&#xff08;Colleague&#xff0…

数值积分——复化梯形求积公式 | 北太天元

复化求积法的思想&#xff1a; 将区间 [ a , b ] [a,b] [a,b]进行 n n n等分&#xff0c;步长 h b − a n h\frac{b-a}{n} hnb−a​&#xff0c;等分点 x k a k h , k 0 , 1 , 2 , ⋯ , n x_{k}akh,k0,1,2,\cdots,n xk​akh,k0,1,2,⋯,n, 先在每个子区间 [ x k , x k 1 ] …

普惠金融淘金热:抢占‘高成长‘企业,抓住下一个十年的财富机遇!

官.网地址&#xff1a;合合TextIn - 合合信息旗下OCR云服务产品 2013年&#xff0c;十八届三中全会正式提出“发展普惠金融”&#xff0c;普惠金融自此上升为国家战略&#xff1b;十年来&#xff0c;我国普惠金融取得了长足发展&#xff0c;逐步构建了多层次、广覆盖的中国特…

文件上传漏洞-白名单检测

如何确认是否是白名单检测 上传一张图片与上传一个自己构造的后缀&#xff0c;如果只能上传图片不能上传其它后缀文件&#xff0c;说明是白名单检测。 绕过技巧 可以利用 00 截断的方式进行绕过&#xff0c;包括 %00 截断与 0x00 截断。除此之外如果网站存在文件包含漏洞&…

《环阳宗海逍遥游》

第一天:《六十八道拐》五月二日游兴浓&#xff0c;大观公园门囗逢。海埂西门再集合&#xff0c;蓝光城里意无穷。呈贡过后松茂过&#xff0c;阳宗镇上心欢融。宜良城中暂歇脚&#xff0c;六十八拐路难通。宜良住宿赏夜色&#xff0c;期待明朝再接龙。 第二天:《情人岛苗王峡行》…

【正点原子Linux连载】 第三十四章 Linux USB驱动实验 摘自【正点原子】ATK-DLRK3568嵌入式Linux驱动开发指南

1&#xff09;实验平台&#xff1a;正点原子ATK-DLRK3568开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id731866264428 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/docs/boards/xiaoxitongban 第三十…

模块化 手写实现webpack

模块化 common.js 的导入导出方法&#xff1a; require \ export 和 module.exports export 和 module.export nodejs 内存1.4G -> 2.8G cjs ESModule 主要区别&#xff1a; require属于动态类型&#xff1a;加载执行 同步 esmodul是静态类型&#xff1a;引入时并不会真的去…

mysql事故复盘: 单行字节最大阈值65535字节(原创)

背景 记得还在银行做开发&#xff0c;投产上线时&#xff0c;项目发版前&#xff0c;要提DDL的sql工单&#xff0c;mysql加1个字段&#xff0c;因为这张表为下游数据入湖入仓用的&#xff0c;长度较大。在测试库加字段没问题&#xff0c;但生产库字段加不上。 先说结论 投产…

[前端]NVM管理器安装、nodejs、npm、yarn配置

NVM管理器安装、nodejs、npm、yarn配置 NVM管理器安装 nvm(Node.js version manager) 是一个命令行应用&#xff0c;可以协助您快速地 更新、安装、使用、卸载 本机的全局 node.js 版本。 nvm下载地址&#xff1a;https://github.com/coreybutler/nvm-windows/releases 1.全部…