就四个部分 增 删 查 改
第一要明确 动态顺序表底层时数组,所以也是通过下标来进行实现运算
c
#define SLtype int
上面宏定义 替换 顺序没关系
c
typedef struct Seqlist {
SLtype* arr; // 指向动态数组的指针
int size; // 当前存储的元素个数
int capacity; // 当前数组的总容量
} SL;
所以需要得有个参数 是 指向数组首元素的地址 第一个
然后还要记录有效元素个数 就是size ,肯定要有个参数记录整个数组得总容量
size作为句柄,就是一个分界线得意思,就是区分有效数据和垃圾数据的分界线,根据
0下标开始原理 可以得出 arr[size] 指向最后有效元素的下一个
此图中 size 有效个数是 4 arr[size - 1] 才是最后一个元素
注: 这里0下标是标准,且实用,如果你开发出一种新语言也可以,启用你的规则 ,语法规定而已

所以 将下标和size结合起来 进行增删查改 起始也是数组的运算
先来新增吧,因为书接上集,我们在初始化的时候并没有赋值,而是,置为空 ,还有就是将size = capacity 都为 0 复习一下
这里整个数组的容量被指为0,需要后期去realloc增容


注意:由于我们初始化为空,没有空间容量capacity==0,所以在 插入(增加)/ 删除 之前都要 检测空间容量是否够用 我们显然不够用 所以要用realloc去增容,这是最开始没容量,还有就是在使用过程中也会容量不足,比方注册的客户比较多,需要判断,在每个用户使用时,避免出现问题,很严重,丢失一个数据,就要 等着卷铺盖走人吧 所以要检测是否有足够大的空间去使用而且去扩容 写个函数吧?
传过来的参数就是整个结构体指针变量?由于size总小于等于capacity所以就是说,当有效个数等于最大容量时就是满了,就要扩容,或者时本来就是0 没有容量的情况都统一扩容
首先理解两个判断的逻辑 (仅个人理解)
第一个 if 是判断是否有空间
第二个是判断realloc是否开辟扩容成功 也可以说是上保险 每个动态内存开辟的函数就基本都要这样判断,保证代码的健壮性
void CheckCapacity(SL* psl) {
if (psl->capacity == psl->size)//这里size<=capacity
{
//realloc(SLtype * arr, Newcapacity * sizeof(SLtype));
if ( tmp == NULL)
{
perror("realloc error!");
exit(1);
}
psl->arr = tmp;
psl->capacity = Newcapacity;
}
}
int Newcapacity = (psl->capacity == 0) ? 4 : 2 * psl->capacity;翻译就是 如果没有容量了,就把容量赋值为4,反之就是将容量翻倍 变成两倍 这里你会问问什么不是其他倍数?3倍,4倍?and stuff. but 最好就是 2倍 ???
不问为什么 问什么? 本自具足,不假外求
三目操作符 就是简化的if-else
大白话语法 : 表达式 + ? + 语句1 + :+语句2;
如果说表达式结果为真 就执行语句1 否则 就语句 2;
SLtype * tmp = (SLtype*)realloc(psl->arr, Newcapacity * sizeof(SLtype));
(SLtype*) 类型名 之前替换的是Int 指向那个数组的起始地址
SLtype * tmp(临时变量名)
(SLtype*) ------------------强制转化类型 暴力管用???
为社么呢? realloc 的返回值 是void *的类型 要转化为需要的
realloc (psl->arr, Newcapacity * sizeof(SLtype));
通过官网查询 图片可知,他的第一个参数是需要操作的空间的地址,第二个参数是 字节数 所以要用到 sizeof(类型 ) * 需要的数量 over? nonono
只是单方面的申请了,开辟指令,不一定会成功,也不一定会有足够的空间来给你 ,这是少数情况,但是就是要考虑极限,或者说是边界的情况 ,因为你永远也不会知道你的用户会有多逆天,你就要i把用户当作最没脑子,脾气还很爆的,性子还很急躁的250就好 所以还没完 要去判断是否开辟成功了
接下来就跟着我调试一下 看看结果
看到吗test01 那一行打个断点观察一下 然后 F5 开始调试 然后 F11 逐语句
第一个是 逐语句 看图标就知道 箭头指进去 就是 会进入到函数里一步一步的 一条语句的运行
第二个是逐过程
不管这一行写了多少条语句、多少个函数、多复杂,逐过程(Step Over)都一整行直接跑完,不进任何函数。 最关键结论
逐过程 = 执行当前行的全部内容,作为一个整体,不进入任何函数内部

下面就是刚打开的监视窗口 根据你的变量名来写
看左边的箭头 执行到这里啦 就是完成了初始化 不错 继续

调试完了 不错哦 很棒 终于初始化且检查空间完成
下一步 来个简单的销毁吧 SLdestroy

销毁两步走 必须两步缺一不可
1. free 释放空间 参数要求 地址
大白话语法 : free( 要释放的空间的地址/指针 )
free只是将内存空间释放 不会改变指针变量free 不改变指针,只释放空间;地址还在,但空间不归你了。
2. 改变指向 尽管这块空间被释放了但是 SLtype * arr的指向并没有改变 ,会让其指向已经释放的空间,就是野指针 就是一条野狗会乱咬人的 很危险 缺一不可


调试 可知确实销毁了
这里两个注释都和附近的代码是一种可以替换的关系 等价

这就是尾插代码
psl->arr[psl->size] = x; 解释一下 红色 表示地址 + 【偏移量(下标/索引)】 将下标和有效元素个数联系起来
psl->size++; <==> (psl->size)++;就是下标加一,向后空出一个位置 下标是最后一个有效元素的后一个
头插代码

你要想如果直接把他赋值给0号下标 ,肯定不行原来的数据就会被覆盖,明显不可以
如图所示,就是一个一个往后移动,但有个思考点? 是 1到2 2到3 and stuff no no no
明显会覆盖后面的数据 所以就好的方法就是 先把最后一个有效数据 往后移一下 就会腾出一个位置 (就是本来的位置),
一次移动后又会腾出一个空位 所以 最后会使得最开始 留出一个位置 ,用于头插 原理懂了 就可以写伪代码 接下来就是 代码的实现
1。循环移动后一位
2。将首位赋值为插入值
- 最后size++ ,插入了一个呀

