目录
1>>闲话
2>>头删
3>>查找
4>>在指定位置之前插入
5>>删除指定结点
6>>指定位置之后插入
7>>删除指定位置之后的结点
特别思考:
8>>销毁单链表
Slist.h
Slist.c
test.c
9>>总结
1>>闲话
单链表其实也不是很难对吧,学会了,认真去学了都比没学强了,就好像你看了这篇文章,获取到知识,你就比之前强了一点点,希望大家再接再厉,那么话不多说,继续后续章节。
附:单链表难?带你速通!-CSDN博客
2>>头删
头删的声明也很简单,只需要传首结点地址即可。函数名front前面表示头部。
进入函数的实现,首先断言判断传进来的是不是空指针,并且判断是不是传进来了一个空结点。
接着思考,我们删除了头节点,那么头节点对应的phead也就是*pphead需要更改,直接删就不知道下一个结点地址在哪里,所以需要一个临时地址存储,那么实现:
创建一个新节点next提前存储第二个结点地址,也就是*pphead->next,然后便可以释放(free)原来结点,并让头部*pphead=第二个结点,此时头节点为原来的第二个结点。完成操作。
3>>查找
查找的声明需要注意,返回的是一个结点的地址,那么就需要用结构体指针(SLN*)接收,这里只需要传递一级指针phead,为什么?因为不需要更改单链表里的结点,只需要查找,所以用形参就可以,x表示要查找的数据,sldatetype在前面说过,方便更改所自定义的类型名称,此时为int类型。
assert每个都是类似的,就不过多赘述啦~不懂的欢迎评论区提出来,小编都会回答的,查找需要遍历一遍单链表,只要有结果符合x,那么就返回这个结点的地址,不符合就返回空指针。
4>>在指定位置之前插入
声明有三个参数,原来的单链表头结点,指定位置(结点)pos,和插入数值x
思考:指定位置之前插入,分三个步骤:
1:新建结点
2:pos之前结点的下一个地址为新建结点
3:新建结点的地址下一个地址为pos
下面详细代码:
首先进来就要判断,这个“位置”是不是头节点,如果是的话那就是头插,直接调用头插代码就好,如果不是,那么就要新建一个结点,然后遍历单链表,注意:这里的循环判断条件和之前不一样,如果下一个地址为pos的话就退出循环,这样得到的pcur就是pos之前的结点地址,然后pcur->next等于新结点,新结点的下一个地址为pos就结束。
5>>删除指定结点
声明如上,与之前类似,不多嗦啦~!
思考:与指定位置之前插入代码是否相似?少了什么?
代码如下:
相信聪明的宝宝们已经看粗来了,当pos为头结点的时候不就是进行头删吗?回答正确,奖励互三!然后还是需要找到pos之前的结点,然后另前一个结点的next为pos的next就好,注意!!所有的删除,都有free,然后把pos置为空指针就好啦!
6>>指定位置之后插入
‘
这里代码比较简单,因为单链表往后找结点容易,往前找结点难,因此,只需要创建新节点,并且让新节点的next为pos的next,再让pos的next为新节点就好,注意:这里顺序一定不能调换,否则pos就会找不到下一个结点
7>>删除指定位置之后的结点
这里也比较简单只需要得知pos指向的下一个结点的下一个地址就简单了。这里不多说啦,大家看看代码。
特别思考:
在学习了时间复杂度和空间复杂度后,大家对这两有一定认识,那么请问:在指定位置之前插入和后插入时间复杂度是多少?删除指定位置和之后的时间复杂度是多少?答案写在最后啦。
8>>销毁单链表
ptail表示销毁到的结点,pcur遍历单链表,销毁(free)每一个结点,最后让*pphead也就是phead等于空指针,不然phead就会成为野指针。
结束啦,感谢观看,这里附上三个文件代码,希望对大家有所帮助!
Slist.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
typedef int sldatetype;
typedef struct SLnode {
sldatetype date;
struct SLnode* next;
}SLN;
void SLprint(SLN* phead);
void SLtailc(SLN** pphead, sldatetype x);//尾插,尾部tail+插入c
void SLtaild(SLN** pphead);//尾删,尾部tail+删除d
void SLfrontc(SLN** pphead, sldatetype x);//头插
void SLfrontd(SLN** pphead);//头删
SLN* SLfind(SLN* phead,sldatetype x);//查找
void SLinsert(SLN** pphead, SLN* pos,sldatetype x);//指定位置之前插入
void SLinsertd(SLN** pphead, SLN* pos); //删除指定结点
void SLinsertafter(SLN* pos, sldatetype x);//指定位置之后插入
void SLinsertafterd(SLN* pos); //删除指定位置后的结点
void SLruin(SLN** pphead);//销毁链表
Slist.c
#include"Slist.h"
void SLprint(SLN* phead) {
SLN* pcur = phead;
while (pcur) {
printf("%d -> ", pcur->date);
pcur = pcur->next;
}
printf("NULL\n");
}
SLN* buynode(sldatetype x) {
SLN* node = (SLN*)malloc(sizeof(SLN));
if (node == NULL) {
perror("malloc");
exit(1);
}
node->date = x;
node->next = NULL;
return node;
}
void SLtailc(SLN** pphead, sldatetype x) {
assert(pphead);
SLN* newnode = buynode(x);
if (*pphead == NULL) {
*pphead = newnode;
}
else {
SLN* ptail = *pphead;
while (ptail->next) {
ptail = ptail->next;
}
ptail->next = newnode;
}
}
void SLtaild(SLN** pphead) {
assert(pphead && *pphead);
if ((*pphead)->next == NULL) {
free(*pphead);
*pphead = NULL;
}
else {
SLN* pcur = *pphead;
SLN* pend = NULL;
while (pcur->next) {
pend = pcur;
pcur = pcur->next;
}
pend->next = NULL;
free(pcur);
pcur = NULL;
}
}
void SLfrontc(SLN** pphead, sldatetype x) {
assert(pphead);
SLN* newnode = buynode(x);
newnode->next = *pphead;
*pphead = newnode;
}
void SLfrontd(SLN** pphead) {
assert(pphead && *pphead);
SLN* next = (*pphead)->next;
free(*pphead);
*pphead = next;
}
SLN* SLfind(SLN* phead, sldatetype x) {
assert(phead);
SLN* pcur = phead;
while (pcur) {
if (pcur->date == x) {
return pcur;
}
pcur = pcur->next;
}
return NULL;
}
void SLinsert(SLN** pphead, SLN* pos, sldatetype x) {
assert(pphead && pos);
if (pos == *pphead) {
SLfrontc(pphead, x);
}
else {
SLN* newnode = buynode(x);
SLN* pcur = *pphead;
while (pcur->next != pos) {
pcur = pcur->next;
}
pcur->next = newnode;
newnode->next = pos;
}
}
void SLinsertd(SLN** pphead, SLN* pos) {
assert(pphead && *pphead && pos);
if (pos == *pphead) {
SLfrontd(pphead);
}
else {
SLN* pcur = *pphead;
while (pcur->next != pos) {
pcur = pcur->next;
}
pcur->next = pos->next ;
free(pos);
pos = NULL;
}
}
void SLinsertafter(SLN* pos, sldatetype x) {
assert(pos);
SLN* newnode = buynode(x);
newnode->next = pos->next;
pos->next = newnode;
}
void SLinsertafterd(SLN* pos) {
assert(pos && pos->next);
SLN* posnext = pos->next;
pos->next = posnext->next;
free(posnext);
posnext = NULL;
}
void SLruin(SLN** pphead) {
assert(pphead);
SLN* pcur = *pphead;
SLN* ptail = *pphead;
while (pcur) {
pcur = pcur->next;
free(ptail);
ptail = pcur;
}
*pphead = NULL;
}
test.c
#include"Slist.h"
void test() {
SLN* phead = NULL;
SLtailc(&phead, 1);
SLprint(phead); SLtailc(&phead, 2);
SLprint(phead); SLtailc(&phead, 3);
SLprint(phead); SLtailc(&phead, 4);
SLprint(phead);
SLN* find = SLfind(phead, 3);
SLruin(&phead);
SLprint(phead);
}
int main() {
test();
return 0;
}
9>>总结
数据结构单链表篇到此结束,今天讲了单链表的各项功能实现包括:尾插、尾删、头插、头删、查找、指定位置前插/删、指定位置后插/删、销毁。希望对大家有所帮助,一起加油,一起进步!