【数据结构】——单链表(增删查改)

 

目录

前言:

一:单链表的特点

​编辑 二:单链表实现

单链表定义

2.1申请节点(初始化)

2.2单链表尾插 

​编辑 2.3单链表打印

2.4单链表头插

 2.5单链表尾删

2.6单链表头删

 2.7单链表查找

2.8在目标位置后面插入

 2.9删除目标位置后面的值

 2.10在目标位置前插入

2.11删除目标位置

2.12单链表销毁

总代码

test.c

SList.c

SList.h 


前言:

因为顺序进行插入删除时,有时候需要移动大量数据,造成不便,影响了运行效率。这时候引出了它的黄金搭档 单链表;

单链表:通过一组任意的存储单元来存储线性表中的数据元素,不需要使用地址连续的存储单元,因此它不要求在逻辑上相邻的两个元素在物理位置上也相邻。

一:单链表的特点

  1. 单链表不要求逻辑上相邻的两个元素在物理位置上也相邻,因此不需要连续的存储空间。
  2. 单链表是非随机的存储结构,即不能直接找到表中某个特定的结点。查找某个特定的结点时,需要从表头开始遍历,依次查找。
  3. 优点:支持动态内存分配。由于单链表不需要预先分配一段连续的空间,因此可以根据实际需求动态地申请、释放节点空间,避免浪费内存。支持高效的插入、删除操作。由于单链表中的节点是通过指针相连的,因此在插入、删除一个节点时,只需要修改其前驱节点或后继节点的指针即可,时间复杂度为O ( 1 )
  4. 缺点:不支持随机访问。由于单链表中的节点不是连续存储的,因此不能像数组一样通过下标来直接访问一个元素,需要从头节点开始遍历整个链表才能访问任意位置的元素。

 二:单链表实现

单链表定义

每个链表结点,除了存放元素自身的信息外,还需要存放一个指向其后继的指针

单链表功能实现中,需要考虑三种情况:链表为空,一个节点,多个节点

typedef int SLNDatatype;typedef struct SListNode //定义单链表结点类型
{struct SListNode* next;    //数据域,可以是别的各种数据类型SLNDatatype val;    //指针域}SLNode;

2.1申请节点(初始化)

malloc出来一块地址,将有效值赋给val,next给NULL

malloc动态开辟的地址,在程序结束前,都需要进行free释放;

然会该节点的地址

//申请一个节点
SLNode* CreateNode(SLNDatatype x)
{SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));if (newnode == NULL){perror("malloc fail");exit(-1);}newnode->val = x;newnode->next = NULL;return newnode;
}

2.2单链表尾插 

我们需要改变该链表,传的是地址,形参接受应该为二级指针;

单链表功能实现中,需要考虑三种情况:链表为空,一个节点,多个节点

如果是空,直接将新节点赋给第一个节点

如果是一个及以上节点,找到链表尾部后,指针域next链接新节点数据域data

// 单链表尾插
void SListPushBack(SLNode** pplist, SLNDatatype x)
{assert(pplist);SLNode* newnode = CreateNode(x);if (*pplist == NULL){*pplist = newnode;}else{//找尾SLNode* tail = *pplist;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;}
}

 2.3单链表打印

在【C】系列中,讲过结构体不管是修改还是打印,最好都传地址来操作,这样不需要额外开辟空间

assert():

断言判断中,其实pplist这个不会为NULL,因为*pplist是地址,哪怕这个地址指向的也是NULL,但是该pplist不为NULL;

assert():

断言是判断不允许为NULL的情况,比如链表为空,还要删除的这类情况;

在打印中:

将下一个地址赋给当前地址,进行遍历操作,和之前的自增++这类不同,因为链表空间不是连续存放的

//打印单链表
void SListPrint(SLNode** pplist)
{assert(pplist);SLNode* cur = *pplist;//遍历打印while (cur){printf("%d->", cur->val);cur = cur->next;}printf("NULL\n");
}

2.4单链表头插

头部插入不管是空链表还是多个节点,将新链表链接到第一个节点即可

// 单链表的头插
void SListPushFront(SLNode** pplist, SLNDatatype x)
{assert(pplist);SLNode* phead = *pplist;SLNode* newnode = CreateNode(x);newnode->next = *pplist;*pplist = newnode;
}

 

 2.5单链表尾删

需要考虑两种情况

一个节点:将该节点删除释放即可;

两个及以上节点:循环找到下下个节点为空的节点,将其删除释放;

        也可以定义一个指针 prev:该指针作用是 当cur的下一个节点不等于空时, 记录此位置,如此循环直到找到下一个节点为空,将其cur释放删除,再将prev定义为新的尾,next置NULL;

// 单链表的尾删
void SListPopBack(SLNode** pplist)
{assert(pplist);assert(*pplist);SLNode* cur = *pplist;//1.一个节点if ((*pplist)->next == NULL){free(*pplist);*pplist = NULL;}//2.一个以上的节点else{// 找尾/*SLNode* prev = NULL;SLNode* tail = *pphead;while (tail->next != NULL){prev = tail;tail = tail->next;}free(tail);tail = NULL;prev->next = NULL;*/while (cur->next->next != NULL){cur = cur->next;}free(cur->next);cur->next = NULL;}
}

 

2.6单链表头删

检查断言后,记录第一个节点位置,将第二个节点赋给第一个节点,再释放记录的位置;

可满足一个节点和多个节点

// 单链表头删
void SListPopFront(SLNode** pplist)
{assert(pplist);assert(*pplist);SLNode* cur = *pplist;*pplist = (*pplist)->next;free(cur);cur = NULL;
}

 

 2.7单链表查找

查找单链表是否存在此val,存在返回该指针,不存在返回null;

需要注意的是返回的是该指针,而不是该值;后面功能用指针传递更好,在C++库中也是这样定义的,我们可以统一

// 单链表查找
SLNode* SListFind(SLNode* plist, SLNDatatype x)
{assert(plist);SLNode* cur= plist;while (cur)	//遍历查找{	if (cur->val == x){return cur;}else{cur= cur->next;}}return NULL;
}

2.8在目标位置后面插入

创建新节点空间后,将newnode链接到原链表尾,这里需要顺序关系,先链接尾部,再将newnode地址链接到原链表尾部


// 单链表在pos位置之后插入x
void SListInsertAfter(SLNode* pos, SLNDatatype x)
{assert(pos);SLNode* newnode = CreateNode(x);newnode->next = pos->next;pos->next = newnode;
}

 

 2.9删除目标位置后面的值

删除pos后面,将pos的next记录,再将链表跨过链接,释放记录值

// 单链表删除pos位置之后的值
void SListEraseAfter(SLNode* pos)
{assert(pos);pos位置后还有两个及以上值//if (pos->next->next != NULL)//{//	SLNode* cur = pos->next;	//cur是要删除的位置//	SLNode * next = pos->next->next;	//pos链接下一个位置//	//	pos->next = next;//	free(cur);//	cur = NULL;//}pos位置后只有一个或者没有值//else//{//	free(pos->next);//	pos->next = NULL;//}SLNode* cur = pos->next;pos->next = pos->next->next;free(cur);cur = NULL;}

 

 2.10在目标位置前插入

精确断言判定后,分成两种情况;

pos为第一个节点:       该操作类似 单链表头插入,调用该函数即可;

pos在链表其他位置:先循环next找,与上同理,注意链接的先后顺序;

这里其实还有一种方式,就是将新节点插入到pos位置后,然后将pos的val值和newnode的val值进行交换即可;

// 在pos的前面插入
void SLTInsert(SLNode** pphead, SLNode* pos, SLNDatatype x)
{assert(pos);assert(pphead);assert(*pphead);SLNode* cur = *pphead;SLNode* newnode = CreateNode(x);//pos在头节点if (pos == cur){SListPushFront(pphead, x);}while (cur){if (cur->next == pos)	//找到pos位置 前{newnode->next = pos;cur->next = newnode;return;}else{cur = cur->next;}}}

 

2.11删除目标位置

与上同理分两种情况:

pos为第一个节点:类似头删除;

pos在其他位置:记录覆盖即可

// 删除pos位置
void SLTErase(SLNode** pphead, SLNode* pos)
{assert(pos);assert(pphead);assert(*pphead);//SLNode* cur = *pphead;//while (cur)
//{
//	if (pos == cur)
//	{
//		cur = cur->next;
//		free(pos);
//		pos = NULL;
//		return;
//	}
//	if (cur->next == pos)
//	{
//		cur->next = cur->next->next;
//		free(pos);
//		pos = NULL;
//		return;
//	}
//	else
//	{
//		cur = cur->next;
//	}
//}if (pos == *pphead){//头删SListPopFront(pphead);}else{while (cur->next != pos){cur = cur->next;}cur->next = cur->next->next;free(pos);pos = NULL;}	
}

 

2.12单链表销毁

因为链表是动态开辟空间,在最后需要释放置NULL;

void SLTDestroy(SLNode** pphead)
{assert(pphead);SLNode* cur = *pphead;while (cur){SLNode* next = cur->next;free(cur);cur = next;}*pphead = NULL;
}

总代码

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"void test1()
{SLNode* s = NULL;SListPushBack(&s, 1);SListPushBack(&s, 2);SListPushBack(&s, 3);SListPrint(&s);SListPushFront(&s, 5);SListPrint(&s);
}void test2()
{SLNode* s = NULL;SListPushBack(&s, 1);SListPushBack(&s, 2);SListPushBack(&s, 3);SListPrint(&s);SListPopBack(&s);SListPrint(&s);SListPopFront(&s);SListPrint(&s);SListPopFront(&s);SListPrint(&s);
}void test3()
{SLNode* s = NULL;SListPushBack(&s, 1);SListPushBack(&s, 2);SListPushBack(&s, 3);SListPrint(&s);SLNode* pos = SListFind(s, 1);SListInsertAfter(pos, 4);SListPrint(&s);
}void test4()
{SLNode* s = NULL;SListPushBack(&s, 1);SListPushBack(&s, 2);SListPushBack(&s, 3);SListPushBack(&s, 4);SListPushBack(&s, 5);SListPrint(&s);SLNode* pos = SListFind(s, 2);SListEraseAfter(pos);SListPrint(&s);}void test5()
{SLNode* s = NULL;SListPushBack(&s, 1);SListPushBack(&s, 2);SListPushBack(&s, 3);SListPrint(&s);SLNode* pos = SListFind(s, 2);SLTInsert(&s,pos,6);SListPrint(&s);SLTErase(&s,pos);SListPrint(&s);}
int main()
{//test1();//test2();//test3();//test4();test5();return 0;
}

SList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"//申请一个节点
SLNode* CreateNode(SLNDatatype x)
{SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));if (newnode == NULL){perror("malloc fail");exit(-1);}newnode->val = x;newnode->next = NULL;return newnode;
}// 单链表尾插
void SListPushBack(SLNode** pplist, SLNDatatype x)
{assert(pplist);SLNode* newnode = CreateNode(x);if (*pplist == NULL){*pplist = newnode;}else{//找尾SLNode* tail = *pplist;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;}
}//打印单链表
void SListPrint(SLNode** pplist)
{assert(pplist);SLNode* cur = *pplist;//遍历打印while (cur){printf("%d->", cur->val);cur = cur->next;}printf("NULL\n");
}// 单链表的头插
void SListPushFront(SLNode** pplist, SLNDatatype x)
{assert(pplist);SLNode* phead = *pplist;SLNode* newnode = CreateNode(x);newnode->next = *pplist;*pplist = newnode;
}// 单链表的尾删
void SListPopBack(SLNode** pplist)
{assert(pplist);assert(*pplist);SLNode* cur = *pplist;//1.一个节点if ((*pplist)->next == NULL){free(*pplist);*pplist = NULL;}//2.一个以上的节点else{// 找尾/*SLNode* prev = NULL;SLNode* tail = *pphead;while (tail->next != NULL){prev = tail;tail = tail->next;}free(tail);tail = NULL;prev->next = NULL;*/while (cur->next->next != NULL){cur = cur->next;}free(cur->next);cur->next = NULL;}
}// 单链表头删
void SListPopFront(SLNode** pplist)
{assert(pplist);assert(*pplist);SLNode* cur = *pplist;*pplist = (*pplist)->next;free(cur);cur = NULL;
}// 单链表查找
SLNode* SListFind(SLNode* plist, SLNDatatype x)
{assert(plist);SLNode* cur = plist;while (cur)	//遍历查找{	if (cur->val == x){return cur;}else{cur = cur->next;}}return NULL;
}// 单链表在pos位置之后插入x
void SListInsertAfter(SLNode* pos, SLNDatatype x)
{assert(pos);SLNode* newnode = CreateNode(x);newnode->next = pos->next;pos->next = newnode;
}// 单链表删除pos位置之后的值
void SListEraseAfter(SLNode* pos)
{assert(pos);pos位置后还有两个及以上值//if (pos->next->next != NULL)//{//	SLNode* cur = pos->next;	//cur是要删除的位置//	SLNode * next = pos->next->next;	//pos链接下一个位置//	//	pos->next = next;//	free(cur);//	cur = NULL;//}pos位置后只有一个或者没有值//else//{//	free(pos->next);//	pos->next = NULL;//}SLNode* cur = pos->next;pos->next = pos->next->next;free(cur);cur = NULL;}// 在pos的前面插入
void SLTInsert(SLNode** pphead, SLNode* pos, SLNDatatype x)
{assert(pos);assert(pphead);assert(*pphead);SLNode* cur = *pphead;SLNode* newnode = CreateNode(x);//pos在头节点if (pos == cur){SListPushFront(pphead, x);}while (cur){if (cur->next == pos)	//找到pos位置 前{SLNode* prev = cur;newnode->next = pos;cur->next = newnode;return;}else{cur = cur->next;}}}// 删除pos位置
void SLTErase(SLNode** pphead, SLNode* pos)
{assert(pos);assert(pphead);assert(*pphead);//SLNode* cur = *pphead;//while (cur)
//{
//	if (pos == cur)
//	{
//		cur = cur->next;
//		free(pos);
//		pos = NULL;
//		return;
//	}
//	if (cur->next == pos)
//	{
//		cur->next = cur->next->next;
//		free(pos);
//		pos = NULL;
//		return;
//	}
//	else
//	{
//		cur = cur->next;
//	}
//}if (pos == *pphead){//头删SListPopFront(pphead);}else{while (cur->next != pos){cur = cur->next;}cur->next = cur->next->next;free(pos);pos = NULL;}	
}void SLTDestroy(SLNode** pphead)
{assert(pphead);SLNode* cur = *pphead;while (cur){SLNode* next = cur->next;free(cur);cur = next;}*pphead = NULL;
}

SList.h 

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLNDatatype;typedef struct SListNode        //链表定义
{struct SListNode* next;SLNDatatype val;}SLNode;// 动态申请一个节点
SLNode* CreateNode(SLNDatatype x);// 单链表尾插
void SListPushBack(SLNode** pplist, SLNDatatype x);//打印单链表
void SListPrint(SLNode** phead);// 单链表的头插
void SListPushFront(SLNode** pplist, SLNDatatype x);// 单链表的尾删
void SListPopBack(SLNode** pplist);// 单链表头删
void SListPopFront(SLNode** pplist);// 单链表查找
SLNode* SListFind(SLNode* plist, SLNDatatype x);// 单链表在pos位置之后插入x
void SListInsertAfter(SLNode* pos, SLNDatatype x);// 单链表删除pos位置之后的值
void SListEraseAfter(SLNode* pos);// 在pos的前面插入
void SLTInsert(SLNode** pphead, SLNode* pos, SLNDatatype x);// 删除pos位置
void SLTErase(SLNode** pphead, SLNode* pos);//销毁单链表
void SLTDestroy(SLNode** pphead);

以上就是我对单链表的理解和功能实现介绍,身为初学者,作者能力有限,文中不对的地方,需要改进的地方,还望各位指点,感激不尽!!! 

 

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

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

相关文章

通用结构化剪枝DepGraph

文章目录 0. 前言一. 第一部分: Torch-Pruning1.1 传统的剪枝流程 - ResNet-18结构化剪枝1.2 Torch-Pruning剪枝 - ResNet-18结构化剪枝1.3 Torch-Pruning剪枝 - 遍历所有分组1.4 Torch-Pruning剪枝 - 剪枝器 High-level Pruners1.5 Torch-Pruning剪枝 - 拓展到更复杂的神经网…

基于入侵杂草算法优化概率神经网络PNN的分类预测 - 附代码

基于入侵杂草算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于入侵杂草算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于入侵杂草优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

Python机器学习、深度学习提升气象、海洋、水文领域实践应用

Python是功能强大、免费、开源&#xff0c;实现面向对象的编程语言&#xff0c;能够在不同操作系统和平台使用&#xff0c;简洁的语法和解释性语言使其成为理想的脚本语言。除了标准库&#xff0c;还有丰富的第三方库&#xff0c;Python在数据处理、科学计算、数学建模、数据挖…

【Apifox】国产测试工具雄起

在开发过程中&#xff0c;我们总是避免不了进行接口的测试&#xff0c; 而相比手动敲测试代码&#xff0c;使用测试工具进行测试更为便捷&#xff0c;高效 今天发现了一个非常好用的接口测试工具Apifox 相比于Postman&#xff0c;他还拥有一个非常nb的功能&#xff0c; 在接…

vue-组件通信(动态组件)

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来vue篇专栏内容:vue-组件通信|动态组件 目录 组件通信 1.父传子 2.子传父 3.ref 4.兄弟组件 5.跨层级 provid…

Xilinx Zynq 7000系列中端FPGA解码MIPI视频,基于MIPI CSI-2 RX Subsystem架构实现,提供5套工程源码和技术支持

目录 1、前言免责声明 2、我这里已有的 MIPI 编解码方案3、本 MIPI CSI2 模块性能及其优缺点4、详细设计方案设计原理框图OV5640及其配置权电阻硬件方案MIPI CSI-2 RX SubsystemSensor Demosaic图像格式转换Gammer LUT伽马校正VDMA图像缓存AXI4-Stream toVideo OutHDMI输出 5、…

【JavaEE】Servlet(创建Maven、引入依赖、创建目录、编写及打包、部署和验证、smart Tomcat)

一、什么是Servlet&#xff1f; Servlet 是一种实现动态页面的技术. 是一组 Tomcat 提供给程序猿的 API, 帮助程序猿简单高效的开发一个 web app 1.1 Servlet能干什么&#xff1f; &#x1f695;允许程序猿注册一个类, 在 Tomcat 收到某个特定的 HTTP 请求的时候, 执行这个类…

P3371 【模板】单源最短路径(弱化版)

【模板】单源最短路径&#xff08;弱化版&#xff09; 题目背景 本题测试数据为随机数据&#xff0c;在考试中可能会出现构造数据让SPFA不通过&#xff0c;如有需要请移步 P4779。 题目描述 如题&#xff0c;给出一个有向图&#xff0c;请输出从某一点出发到所有点的最短路…

Kotlin基础——接口和类

接口 使用 : 表示继承关系&#xff0c;只能继承一个类&#xff0c;但可以实现多个接口override修饰符表示重写可以有默认方法&#xff0c;若父类的默认方法冲突&#xff0c;则需要子类重写&#xff0c;使用super<XXX>.xxx()调用某一父类方法 interface Focusable {fun …

SQL学习之增删改查

文章目录 数据库数据类型建表create table插入数据insert into查询数据select from修改数据update set删除数据delete from备份ctas结果插入iis截断表 truncate table修改表结构alter table添加注释 注&#xff1a;本文的SQL语法是基于Oracle数据库操作的&#xff0c;但是基本的…

开源软件 FFmpeg 生成模型使用图片数据集

本篇文章聊聊&#xff0c;成就了无数视频软件公司、无数在线视频网站、无数 CDN 云服务厂商的开源软件 ffmpeg。 分享下如何使用它将各种视频或电影文件&#xff0c;转换成上万张图片数据集、壁纸集合&#xff0c;来让下一篇文章中的模型程序“有米下锅”&#xff0c;这个方法…

⑨【MySQL事务】事务开启、提交、回滚,事务特性ACID,脏读、幻读、不可重复读。

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ MySQL事务 ⑨【事务】1. 事务概述2. 操作事务3…

若依Linux与Docker集群部署

若依Linux集群部署 1. 若依2.MYSQL Linux环境安装2.1 MYSQL数据库部署和安装2.2 解压MYSQL安装包2.3 创建MYSQL⽤户和⽤户组2.4 修改MYSQL⽬录的归属⽤户2.5 准备MYSQL的配置⽂件2.6 正式开始安装MYSQL2.7 复制启动脚本到资源⽬录2.8 设置MYSQL系统服务并开启⾃启2.9 启动MYSQL…

ubuntu小技巧30--23.10桌面版安装钉钉启动报错undefined symbol: FT_Get_Color_Glyph_Layer

ubuntu小技巧30-- 23.10桌面版安装钉钉启动报错undefined symbol: FT_Get_Color_Glyph_Layer 介绍解決方法说明 介绍 近期在电脑上安装了 ubuntu 23.10桌面版本, 安装最新版钉钉后无法正常打开软件&#xff0c;报错 undefined symbol: FT_Get_Color_Glyph_Layer &#xff0c;具…

手把手带你学习 JavaScript 的 ES6 ~ ESn

文章目录 一、引言二、了解 ES6~ESn 的新特性三、掌握 ES6~ESn 的用法和实现原理四、深入挖掘和拓展《深入理解现代JavaScript》编辑推荐内容简介作者简介精彩书评目录 一、引言 JavaScript 是一种广泛使用的网络编程语言&#xff0c;它在前端开发中扮演着重要角色。随着时间的…

基于opencv+tensorflow+神经网络的智能银行卡卡号识别系统——深度学习算法应用(含python、模型源码)+数据集(一)

目录 前言总体设计系统整体结构图系统流程图 运行环境Python环境TensorFlow 环境OpenCV环境 相关其它博客工程源代码下载其它资料下载 前言 本项目基于从网络获取的多种银行卡数据集&#xff0c;采用OpenCV库的函数进行图像处理&#xff0c;并通过神经网络进行模型训练。最终实…

6.jvm中对象创建流程与内存分配

目录 概述对象的创建流程对象的内存分配方式对象怎样才会进入老年代大对象直接进入老年代内存担保 jvc 相关指令查看jdk默认使用的gc查看当前jdk支持的有哪些gc查看指定进程当前正在使用的gc 结束 概述 相关文章在此总结如下&#xff1a; 文章地址jvm基本知识地址jvm类加载系…

国际阿里云:提高CDN缓存命中率教程!!!

CDN缓存命中率低会导致源站压力大&#xff0c;静态资源访问效率低。您可以根据导致CDN缓存命中率低的具体原因&#xff0c;选择对应的优化策略来提高CDN的缓存命中率。 背景信息 CDN通过将静态资源缓存在CDN节点上实现资源访问加速。当客户端访问某资源时&#xff0c;如果CDN节…

算不上最全,但都是必备——Spring这些不会不行啊

Spring 篇 Spring框架中的单例bean是线程安全的吗&#xff1f; 不是线程安全的 Spring bean并没有可变的状态(比如Service类和DAO类)&#xff0c;所以在某种程度上说Spring的单例bean是线程安全的。 Spring框架中有一个Scope注解&#xff0c;默认的值就是singleton&#xff0…

Windows如何正确设置PHP环境变量以在Git Bash中运行命令

1、随便找一个目录&#xff0c;鼠标右键打开git bash here 2、cd的根目录 3、找到php安装目录 4、 在根目录下打开 vim .bash_profile &#xff0c;添加环境变量&#xff0c;php地址根据自己的本地地址而定 PATH$PATH:/d/phpstudy_pro/Extensions/php/php7.3.4nts 添加后保存…