实现接口:
尾删
任意插入,在pos的前面插入x
任意删除,删除pos位置的值
释放空间
如果有兴趣不妨点进主页更多精彩内容呈现哦😘
尾删
首先按照套路来,我们先画出示意图或者说原理图来。
![](https://i-blog.csdnimg.cn/blog_migrate/fad28949521bc68c7653ed47f2bcb769.png)
这里考虑的是数据大于1的情况
这样我们再来实现代码:
//尾删
void SListPopBack(SListNote** pphead)
{
SListNote* prev = NULL;
SListNote* tail = *pphead;
//找尾
while (tail->next != NULL)
{
prev = tail;
//下一个
tail = tail->next;
}
free(tail);
//把前一个制成空
prev = NULL;
}
但是我们很快认识到这应该是不行的——如果只有1个数据或者干脆没有数据呢?
这里其实涉及到一个套路,我们要用极限的思维方式去思考这个问题。随着我们写的工程文件越来越多就会发现其中的奥妙之处。
我们再来画一下只有一个数据的情况:
![](https://i-blog.csdnimg.cn/blog_migrate/578a228caa4e35f227353f1540494a99.png)
直接free就行了
那我们再来思考如果是没有数据呢?是不是直接return就行了呢?
现在我们再来修改一下代码
//尾删
void SListPopBack(SListNote** pphead)
{
//1.如果链表为空
if (*pphead == NULL)
{
return;
}
//2、只有一个节点
else if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
//3、一个以上的节点
else
{
SListNote* prev = NULL;
SListNote* tail = *pphead;
//找尾
while (tail->next != NULL)
{
prev = tail;
//下一个
tail = tail->next;
}
free(tail);
//把前一个制成空
prev = NULL;
}
}
如此我们再思考还有没有遗漏的地方呢?如果没有我们就直接写入主函数中,进行调试代码。详见顺序表(三),感兴趣的可以看看。建议大家写一步,完成一个函数,就调试一个函数。
任意插入,在pos的前面插入x
这里我们因为要在任意位置插入,所以我们首先要找到这个节点,考虑到我们接下来还要写一个任意位置删除,所以我们最好先写一个查找函数。
//查找
SListNote* SListFind(SListNote* phead, SLTDateType x)
{
SListNote* cur = phead;
while (cur)
{
if (cur->data == x)
{
//找到了
return cur;
}
else
{
//下一个
cur = cur->next;
}
}
//找不到
return NULL;
}
但是我们发现其实用查找函数去实现这个函数并不靠谱,因为我们不知道上一个值,就很尴尬。但是我们通过实现查找函数可以让我们的接口更加丰富。
还是一样的先画出原理图
![](https://i-blog.csdnimg.cn/blog_migrate/3d11a613872f863010db0328fa1c77b4.png)
这里还是只考虑了大于1的情况
根据尾删的套路我们又要思考了——只有一个的情况呢?或者干脆没有的情况呢?
这里我们可以取巧吧,当遇上小于等于1的情况时我们可以直接调用头插,这个套路在之前我写的顺序表(四)中有很好的体现,感兴趣的可以看一下哦!
将思想转化为代码就是这样:
//任意插入,在pos的前面插入x
void SListInsert(SListNote** pphead, SListNote* pos, SLTDateType x)
{
if (pos == *pphead)
{
//头插
SListPushFront(pphead, x);
}
else
{
//申请一块空间
SListNote* newnote = SListBuyNote(x);
SListNote* prev = *pphead;
while (prev->next != pos)
{
//下一个
prev = prev->next;
}
prev->next = newnote;
newnote->next = pos;
}
}
任意删除,删除pos位置的值
我们可以推测一下,这里的套路应该时和上一个函数的套路应该是差不多的吧。还是要先找到pos,然后cur->next指向pos->next,最后free掉就行了
还不懂的可以看一下原理图:
![](https://i-blog.csdnimg.cn/blog_migrate/f6e437fdc6e8b922ed3ba0c3bfa01033.png)
这里考虑的情况是不是和刚才的一样
思考一下是不是还有其他情况呢?熟悉套路以后我们这里一样可以取巧吧,调用头删。
将思想转化为代码就是这样:
//任意删除,删除pos位置的值
void SListErase(SListNote** pphead, SListNote* pos)
{
if (pos == *pphead)
{
//头删
SListPopFront(pphead);
}
else
{
SListNote* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
每次当我们写完代码以后一定要多总结套路与思想,这样我们才能有长远的进步与成长。
接下来实现释放空间
释放空间
这里还是更之前一样的,调用头删函数,全部删完就行了,这是其中一种比较简单的实现方式,大家也可以自己尝试一下有没有别的实现方式。
//释放空间
void SListListDistory(SListNote** pphead)
{
while(*pphead)
{
SListPopFront(pphead);
}
}
其实有兴趣的小伙伴可以再实现一个打印函数看看自己是否真的掌握了单链表的思想和套路
这个代码大家可以做个参考
//打印
void SListPrint(SListNote* phead)
{
//cur当前位置
SListNote* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->data);
//下一个位置
//cur是当前位置的地址,cur->next存的是下一个位置的地址
cur = cur->next;
}
//表示打印完了
printf("NULL\n");
}
下期内容更加精彩哦
都看到这里了不妨点个赞吧,你们的赞和留言就是对我最大的鼓励!