【数据结构】顺序表的学习
前言:在之前我们学习了C语言的各种各样的语法,因此我们今天开始学习数据结构这一个模块,因此我们就从第一个部分来开始学习"顺序表"。
💖 博主CSDN主页:卫卫卫的个人主页 💞
👉 专栏分类:C程序设计谭浩强版本 👈
💯代码仓库:卫卫周大胖的学习日记💫
💪关注博主和博主一起学习!一起努力!
目录
- 顺序表
- 动态顺序表
- 顺序表的初始化
- 顺序表的销毁
- 顺序表的空间容量检查
- 顺序表的打印
- 顺序表的尾增
- 顺序表的头增
- 顺序表的头删
- 顺序表的尾删
- 顺序表的选择插入
- 顺序表的删除数据
- 顺序表数据的查找
- 练习
顺序表
- 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
- 顺序表一般可以分为两个部分,静态顺序表(使用定长数组存储元素)和动态顺序表(使用动态开辟的数组存储)。
- 静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。
动态顺序表
首先我们创建一个结构体,去实现数据的动态存储。

代码如下:
typedef int SLDataype;//定义整型,方便后面进行数据的更改typedef struct SeqList //动态顺序表的开辟
{SLDataype* a;int size; //记录多少个有效数据int capacity; //记录空间有多大
}SL;
接下来我们就实现一个个接口来实现顺序表的基本功能
顺序表的初始化
顺序表的初始化十分简单,只需要将开辟的指针置为空指针,有效数据清零,空间容量清零即可。
代码如下:
void SLInit(SL* ps1)//顺序表的初始化
{assert(ps1);ps1->a = NULL;//将指针置为空指针ps1->size = 0;//数据清零ps1->capacity = 0;//容量清零
}
顺序表的销毁
同理,顺序表的销毁,只需要判断所开辟的空间是否已经是被释放了,和被置为空指针了,如果不是,就把所开辟的空间释放和数据清零即可。
代码如下:
void SLDestory(SL* ps1)//顺序表的销毁
{if (ps1->a != NULL)//判断该指针是否为空指针{free(ps1->a);//释放该指针所开辟的空间ps1->a = NULL;//置为空指针ps1->size = 0;//数据清零ps1->capacity = 0;//容量清0}
}
顺序表的空间容量检查
我们想要实现在所开辟的空间中,增加数据,就不可避免的需要去检查所开辟的空间的容量是否充足,如果不充足,我们就需要去增容,那该增加多少呢?增加太多,会导致空间的浪费,太少又会导致不断的扩容,这是一个双向的问题,因此这也没有什么十分固定的答案,通常来讲,一般增容一倍即可。
代码思路:在检查空间的时候,我们应该考虑传过来的指针是否是空指针,即是否是初始化后的顺序表,但realloc函数是可以对空指针进行扩容的,但是我们为了防止扩容失败,应该开辟一个新的结构体指针来接收这块空间,在开辟成功后重新覆盖回去。
代码实现:
void SLCheckCapacity(SL* ps1)//检查空间
{if (ps1->size == ps1->capacity)//判断记录的数据个数,与空间容量释放相同,相同的时候即空间满了,需要增容{int newCapacity = ps1->capacity == 0 ? 4 : ps1->capacity * 2;//判断开辟的空间是否是初始化的空间,如果是就让他容量为4,如果不是就开辟当前空间的两倍SLDataype* tmp = (SLDataype*)realloc(ps1->a, sizeof(SLDataype) * newCapacity);//创建一个新的结构体指针,在他的后面扩容,放在开辟失败后原本的数据也不见了//realloc 可以对空指针进行扩容if (tmp == NULL){perror("realloc fail");return;}ps1->a = tmp;//将开辟后面的指针传给原本的地址ps1->capacity = newCapacity;//更新容量}
}
顺序表的打印
void SLPrint(SL* ps1)
{for (int i = 0; i < ps1->size; i++)//变量开辟的数据{printf("%d ", ps1->a[i]);//直接打印}printf("\n");
}
顺序表的尾增
代码思路:因为前面我们提到了size是有效数据的个数,也是指向的数组的最后一个元素的后一个的位置,因此只需要在此位置赋值即可,然后再让size往后偏移一位。
代码实现:
void SLPushBack(SL* ps1, SLDataype x)//尾增
{SLCheckCapacity(ps1);//检查空间容量ps1->a[ps1->size] = x;//因size指向的是数组最后一个元素的后一个元素,因此只需要直接在此位置赋值即可ps1->size++;//size继续指向后一个元素
}
现在我们实现了四个小的接口,忙活了这么久,我们来见一下效果,好歹听个响是吧。
效果图:
void TestSL1()//测试函数
{SL s1;//创建动态顺序表SLInit(&s1);//初始化顺序表SLPushBack(&s1, 2);//尾增数据SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPrint(&s1);//打印数据SLPushBack(&s1, 5);SLPushBack(&s1, 6);SLPrint(&s1);//打印数据SLDestory(&s1);//销毁顺序表
}int main()
{TestSL1();return 0;
}

顺序表的头增
代码实现思路:我们记录数据的最后一个位置为end,最后一个数据后面的一个数据位置为end+1,让end依次往后覆盖,然后end–直到end到起始位置即停止循环,具体思路如下图:

代码实现:
void SLPushFront(SL* ps1, SLDataype x)//头增
{SLCheckCapacity(ps1);//先检查数据//挪动数据int end = ps1->size - 1;//记录最后一个位置while (end >= 0)//end到起始位置时即覆盖完成{ps1->a[end + 1] = ps1->a[end];//将数据依次往后覆盖--end;}ps1->a[0] = x;//将数据赋值给起始位置就可以实现头增ps1->size++;//size++
}
当然了,不能白忙活,我们来测试一下这个函数,来看看效果如何
void TestSL2()
{SL s1;//创建动态顺序表SLInit(&s1);//初始化顺序表SLPushBack(&s1, 2);//尾增数据SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPrint(&s1);//打印尾增的数据printf("上面是尾增的数据\n");printf("------------------------------\n");printf("下面是头增的数据\n");SLPushFront(&s1, 20);//头增的数据SLPushFront(&s1, 10);SLPushFront(&s1, 0);SLPushFront(&s1,9);SLPrint(&s1);//打印头增的数据SLDestory(&s1);//销毁顺序表
}int main()
{//TestSL1();TestSL2();return 0;
}

顺序表的头删
代码思路:我们记录一个起始位置即数组的第二个元素记录为begin,让他往前面一个数据begin-1覆盖,然后再放入循环中不断覆盖,当运行到size的位置的时候停止循环具体思路如下图:

代码如下:
void SLPopFront(SL* ps1)//头删
{assert(ps1->size > 0);//判断传过来是是不是为空数据int begin = 1;//将起始位置置为1while (begin < ps1->size)//再起始位置等于size时即覆盖完成{ps1->a[begin - 1] = ps1->a[begin];//后面覆盖前面++begin;}ps1->size--;//size减减
}
当然,我们依然来听个响,听听声音,效果图如下:
void TestSL3()
{SL s1;//创建动态顺序表SLInit(&s1);//初始化顺序表SLPushBack(&s1, 2);//尾增数据SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPushFront(&s1, 20);//头增的数据SLPushFront(&s1, 10);SLPushFront(&s1, 0);SLPushFront(&s1, 9);SLPrint(&s1);//打印原本的数据printf("上面是原本的数据\n");printf("--------------------------------------\n");printf("下面是删除后的数据\n");SLPopFront(&s1);//头删数据SLPopFront(&s1);SLPopFront(&s1);SLPrint(&s1);//打印删除后的数据SLDestory(&s1);//销毁顺序表
}int main()
{//TestSL1();//TestSL2();TestSL3();return 0;
}

顺序表的尾删
代码思路:我们可以通过前面的打印函数可以知道,我们是通过打印到size前面的一个下标来访问所有的元素,因此我们只需要让size往前面走一个,就可以把尾部的元素删除,可以看下图思路:

代码实现:
void SLPopBack(SL* ps1)//尾删
{//空if (ps1->size == 0)//判断删除的是否为空{return;}ps1->size--;//size--即可
}
我们依然来测试一下我们函数,看看效果是否成功实现,代码和效果图如下:
void TestSL4()
{SL s1;//创建动态顺序表SLInit(&s1);//初始化顺序表SLPushBack(&s1, 2);//尾增数据SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPushFront(&s1, 20);//头增的数据SLPushFront(&s1, 10);SLPushFront(&s1, 0);SLPushFront(&s1, 9);SLPrint(&s1);//打印原本的数据printf("上面是原本的数据\n");printf("--------------------------------------\n");printf("下面是删除后的数据\n");SLPopBack(&s1);//尾删数据SLPopBack(&s1);SLPrint(&s1);//打印删除后的数据SLDestory(&s1);//销毁顺序表
}int main()
{//TestSL1();//TestSL2();//TestSL3();TestSL4();return 0;
}

顺序表的选择插入
代码思路:选择插入,即将一个值,任意插入到顺序表中的范围内,当然了口头总是不太好说清,我们对着下图来进行一一分析,我们可以记录一个end坐标记录数据的尾部,然后将值一一覆盖,pos为我们想要出入数据的位置,例如下图,当end走到pos的位置的时候,即可停止覆盖,这有点类似与我们前面的头删,将值pos之后的值全部往后挪动了一位,然后将最后重复的值被想插入的值覆盖即可。

代码实现:
void SLInsert(SL* ps1, int pos, SLDataype x)//插入数据
//pos是下标,size是数据个数,看作下标的话,他是最后一个数的下一个位置
{assert(ps1);//判断传来的值是否是空指针assert(pos >= 0 && pos <= ps1->size);//插入的值必须是再范围内(可以包括尾增)SLCheckCapacity(ps1);//检查空间// 挪动数据int end = ps1->size - 1;//找到尾坐标while (end >= pos){ps1->a[end + 1] = ps1->a[end];//将值一一覆盖,类似于头删--end;}ps1->a[pos] = x;//赋值ps1->size++;
}
我们依然来看看函数的效果是否实现,测试代码和效果图如下:
void TestSL5()
{SL s1;//创建动态顺序表SLInit(&s1);//初始化顺序表SLPushBack(&s1, 2);//尾增数据SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPushFront(&s1, 20);//头增的数据SLPushFront(&s1, 10);SLPushFront(&s1, 0);SLPushFront(&s1, 9);SLPrint(&s1);//打印原本的数据printf("上面是原本的数据\n");printf("--------------------------------------\n");printf("下面是选择插入后的数据\n");SLInsert(&s1, 3, 99);SLInsert(&s1, 1, 2);SLPrint(&s1);//打印选择插入后的数据SLDestory(&s1);//销毁顺序表
}
int main()
{//TestSL1();//TestSL2();//TestSL3();//TestSL4();TestSL5();return 0;
}

顺序表的删除数据
代码思路:删除数据和选择插入的概念其实大差不差,首先也应当判断传过来的数是否是空指针,删除的数据在不在数据范围内,然后我们再通过图文来进行分析,如下图,先把删除的位置记录下来,当然了,和前面同理依次往前面覆盖,再打印的时候直接将size往前移一位即可把最后重复的值给去掉,达到顺序表的删除的功能。

函数代码:
void SLErase(SL* ps1, int pos)//删除数据
{assert(ps1);assert(pos >= 0 && pos < ps1->size);int begin = pos + 1;//记录删除数据后的位置while (begin < ps1->size){ps1->a[begin - 1] = ps1->a[begin];//依次覆盖++begin;}ps1->size--;
}
代码实现和函数实现效果图如下:
void TestSL6()
{SL s1;//创建动态顺序表SLInit(&s1);//初始化顺序表SLPushBack(&s1, 2);//尾增数据SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPushFront(&s1, 20);//头增的数据SLPushFront(&s1, 10);SLPushFront(&s1, 0);SLPushFront(&s1, 9);SLPrint(&s1);//打印原本的数据printf("上面是原本的数据\n");printf("--------------------------------------\n");printf("下面是选择插入后的数据\n");SLErase(&s1, 3);//删除数据SLErase(&s1, 1);//删除数据SLPrint(&s1);//打印选择插入后的数据SLDestory(&s1);//销毁顺序表}int main()
{//TestSL1();//TestSL2();//TestSL3();//TestSL4();//TestSL5();TestSL6();return 0;
}

顺序表数据的查找
代码思路:顺序表数据的查找就过于简单了,我们只需要遍历数据,看看是否有对应的值,有则返回该数的下标,没有则返回**-1**。代码如下:
int SLFind(SL* ps1, SLDataype x)//顺序表数据的查找
{assert(ps1);//判断传来的数据是否是空指针for (int i = 0; i < ps1->size; i++)//遍历数组{if (ps1->a[i] == x)return i;//找到即返回坐标i}return -1;//没找到返回-1
}
函数测试与效果图:
void TestSL7()
{SL s1;//创建动态顺序表SLInit(&s1);//初始化顺序表SLPushBack(&s1, 2);//尾增数据SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPushFront(&s1, 20);//头增的数据SLPushFront(&s1, 10);SLPushFront(&s1, 0);SLPushFront(&s1, 9);SLPrint(&s1);//打印原本的数据printf("上面是原本的数据\n");printf("--------------------------------------\n");printf("下面是选择插入后的数据\n");printf("该数的下标是:%d\n",SLFind(&s1, 2));SLDestory(&s1);//销毁顺序表
}
int main()
{//TestSL1();//TestSL2();//TestSL3();//TestSL4();//TestSL5();//TestSL6();TestSL7();return 0;
}

讲到这里,关于顺序表的基本内容实现全部讲完了,接下来我们来看一题目练习一下把!
练习
题目链接:

思路分析:看到这个题,大家都会想到一个很通俗易懂的方法,就是开辟一个辅助数组,将所有的数放进去,然后进去排序,当然我们今天是不讲这个方法的,因为这个方法的时间复杂度过于高。我们看到这个是一个非递减顺序,可以知道最大的数都放在了后面,因此我们可以将两个数中最后的元素拿出来依次比较,然后将较大的放在nums1中的最后面,依次类推,放到最后自然而然的可以将所有数进行排序,那怎么去实现它呢?看图说话,如下图,我们记录一个坐标i1和i2分别记录下两个数组中的最后一个元素,然后依次进行比较,如果i1中的数较大就放在下标j的位置,反之则把i2放进去,且如果nums1中走完了,nums2还没有,就只需要将nums2中的数据单独拿出来,放再j所在的位置即可。

代码实现如下:
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{int i1 = m - 1;//记录第一个数组的尾坐标int i2 = n - 1;//第二个数组尾坐标int j = m + n - 1;//记录总元素的坐标while(i1 >= 0 && i2 >= 0){if(nums1[i1] > nums2[i2]){nums1[j--] = nums1[i1--]; }else{nums1[j--] = nums2[i2--];}}while(i2 >= 0){nums1[j--] = nums2[i2--];}
}
运行结果:

结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。
相关文章:
【数据结构】顺序表的学习
前言:在之前我们学习了C语言的各种各样的语法,因此我们今天开始学习数据结构这一个模块,因此我们就从第一个部分来开始学习"顺序表"。 💖 博主CSDN主页:卫卫卫的个人主页 💞 👉 专栏分类:C程序设计谭浩强版本…...
在NISQ小型计算机上执行大型并行量子计算的可能性
简介 Steve White提出了密度矩阵重整化群(DMRG)的基本思想,即纠缠是一种有价值的资源,可以用来精确或近似地描述大量子系统。后来,这一思想被理解为优化矩阵积状态(MPS)的算法,支持…...
考虑时空相关性的风电功率预测误差MATLAB代码
微❤关注“电气仔推送”获得资料(专享优惠) 风电功率预测置信区间误差分析拟合 1.风电功率预测误差--时空相关性 展示第一一个时间段的风电功率预测与实际风电功率值的比较。填充区域表示预测的不确定性,显示了95%置信区间内预测可能的范围…...
ASP.NET WebApi 极简依赖注入
文章目录 环境服务类启动项注入使用依赖注入的优点 环境 .NET Core 7.0ASP.NET CoreVisual Studio 2022 服务类 public class T_TempService {public T_TempService(){}public void Test(){}}启动项注入 #region 依赖注入 builder.Services.AddTransient<T_TempService&g…...
解决proteus仿真stm32,IIC通讯,IIC DEBUG无法显示从机应答信号的问题(问题情况为在8位数据后应答位显示?)
1、错误现象 错误现象如下,在IIC数据传输8位数据后,IIC DEBUG的应答位无法显示应答位 2、错误原因 我们打开信号传输的示波器,直接去查看IIC从机校验位的数据波形,可以看到从机示波器显示的的波形为半高ACK,那错误原…...
PHP判断闰年
闰年的规则 1.能被4整除且不能被100整除 (普通闰年) 2.能被400整除,公历年份是整百数的,必须是400的倍数才是闰年(世纪闰年) 代码 function isLeapYear($year) {if($year%40 && $year%100!0){r…...
证照之星XE专业版下载专业证件照制作工具
值得肯定的是智能背景替换功能,轻松解决背景处理这一世界难题。不得不提及的是新增打印字体设置,包含字体选择、字号大小、字体颜色等。不同领域的应用证明了万能制作,系统支持自定义证照规格,并预设了17种常用的证件照规格。人所…...
VR全景图片如何制作?揭秘VR全景图片制作全流程
引言: VR全景图片是一种以全景视角为基础的图片制作技术,能够呈现出更为真实、立体的视觉体验。通过VR全景图片,观众可以360环顾四周,仿佛身临其境,提供了一种全新的感官体验,那么如何制作出令人满意的全景…...
vue element el-table-column 循环示例代码
如果你想循环生成多个el-table-column,可以使用v-for指令。以下是一个示例: <template><el-table :data"tableData"><el-table-column v-for"column in columns" :key"column.prop" :label"column.l…...
R语言生物群落(生态)数据统计分析与绘图实践技术应用
R 语言作的开源、自由、免费等特点使其广泛应用于生物群落数据统计分析。生物群落数据多样而复杂,涉及众多统计分析方法。以生物群落数据分析中的最常用的统计方法回归和混合效应模型、多元统计分析技术及结构方程等数量分析方法为主线,通过多个来自经典…...
有了 GPT,还需要付费咨询吗?
之前写过一篇文章《在创业公司,我靠它续命 …》,提到现在写代码基本靠 GPT。现在这种状况不仅没有改变,反而依赖更深。公司立项开发产品的 Linux 版本,全靠我一个人。我之前虽然一直使用 Linux 开发环境,对 Linux 系统…...
如何搭建一台服务器?
一.准备工作 1. 确定服务器类型:根据需求选择适合的服务器类型,如网站服务器、数据库服务器、文件服务器等。 2. 选择操作系统:根据服务器类型选择合适的操作系统,如Linux(如Ubuntu、CentOS)、Windows Se…...
[转载]C++序列化框架介绍和对比
Google Protocol Buffers Protocol buffers 是一种语言中立,平台无关,可扩展的序列化数据的格式,可用于通信协议,数据存储等。 Protocol buffers 在序列化数据方面,它是灵活的,高效的。相比于 XML 来说&…...
分类预测 | Matlab实现KOA-CNN-BiLSTM-selfAttention多特征分类预测(自注意力机制)
分类预测 | Matlab实现KOA-CNN-BiLSTM-selfAttention多特征分类预测(自注意力机制) 目录 分类预测 | Matlab实现KOA-CNN-BiLSTM-selfAttention多特征分类预测(自注意力机制)分类效果基本描述程序设计参考资料 分类效果 基本描述 1…...
浮点数和定点数(上):怎么用有限的Bit表示尽可能多的信息?
目录 背景 浮点数的不精确性 定点数的表示 浮点数的表示 小结 背景 在我们日常的程序开发中,不只会用到整数。更多情况下,我们用到的都是实数。比如,我们开发一个电商 App,商品的价格常常会是 9 块 9;再比如&…...
一文详解汽车电子LIN总线
0.摘要 汽车电子LIN总线不同于CAN总线。 LIN总线基本上是CAN总线的廉价补充,相比于CAN总线,它提供较低的可靠性和性能。同时LIN总线也是一个应用非常广泛的网络协议,并且越来越受欢迎。 再一次,我们准备了一个关于LIN总线的简要…...
论文阅读——GPT3
来自论文:Language Models are Few-Shot Learners Arxiv:https://arxiv.org/abs/2005.14165v2 记录下一些概念等。,没有太多细节。 预训练LM尽管任务无关,但是要达到好的效果仍然需要在特定数据集或任务上微调。因此需要消除这个…...
星环科技分布式向量数据库Transwarp Hippo正式发布,拓展大语言模型时间和空间维度
随着企业、机构中非结构化数据应用的日益增多以及AI的爆发式增长所带来的大量生成式数据,所涉及的数据呈现了体量大、格式和存储方式多样、处理速度要求高、潜在价值大等特点。但传统数据平台对这些数据的处理能力较为有限,如使用文件系统、多类不同数据…...
滚动条默认是隐藏的只有鼠标移上去才会显示
效果 在设置滚动条的类名中写 /* 滚动条样式 */.content-box::-webkit-scrollbar {width: 0px; /* 设置纵轴(y轴)轴滚动条 */height: 0px; /* 设置横轴(x轴)轴滚动条 */}/* 滚动条滑块(里面小方块) */.…...
Go学习第十五章——Gin参数绑定bind与验证器
Go web框架——Gin(参数绑定bind与验证器) 1 bind参数绑定1.1 JSON参数1.2 Query参数1.3 Uri绑定动态参数1.4 ShouldBind自动绑定 2 验证器2.1 常用验证器2.2 gin内置验证器2.3 自定义验证的错误信息2.4 自定义验证器 1 bind参数绑定 在Gin框架中&#…...
51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

