前几天我们的算法老师对我们开展了惨无人道的压迫模式,所以虽然不带头结点的链表在前几天已经完成了,但是以为一直在写头歌,就一直没有更新这边。
链表结点的删除
尾删
对于没有头结点的单链表,删除的逻辑其实也是比较简单的,但我这里介绍的这种删除就是单纯的一个个删除,不能指定删除,也就是说不能选择,从尾删到头or从头删到尾。那么,想要实现删除,很明显我们要做到什么呢?尾删法:首先,我们得找到最后那个结点,怎么找呢?前面提过了就是先让tail指向phead然后再tail = tail->next直到tail==null为止,这样就找到了单链表得最后一个结点,再找到它之后我们直接free(tail)就可以把tail给删除了,但是这样很明显我们删除最后面的结点,那么他的数据域和指针域都没有了,但是它前面结点还是保存着被删除的结点的地址啊,这样一来不就可能回去访问一个位置的地址了吗?所以我们引入了prev,我们记住了前面的结点这样一来在删除一个结点的时候再让被删除的前面的那个结点去指向空,这样我们就可以实现循环删除啦!
同样的,删除我们也要注意2个点,那就是这个链表有没有 结点,如果没有结点就直接返回就🆗,如果只有一个结点,那直接free就行,也不需要什么prev。
/*
delete_list : 从后面开始删除链表节点
@*phead : 第一个结点的指针的地址
返回值 : 无
*/
void delete_list(Node*phead)
{
if(phead->next == NULL)
{
free(phead);
phead = NULL;
}
else
{
Node* tail = phead;
Node* prev = tail;
while (tail->next)
{
prev = tail;
tail = tail->next;
}
free(tail);
tail = NULL;//为了安全,详情看内存方面的知识
prev->next = NULL;
}
}
头删
我们前面就已经了解到了,单链表来说,头指针是很重要的,你看我们写的函数基本上来说都是传头指针,因为头指针是让我们来定位的,我们只有有了头指针,打印什么的才方便实现,所以头删法我们还是得引入一个新东西last,怎么操作呢?我们不用再去遍历找头,因为头指针直接传我们就可以直接用了,那么未来避免头指针被删除,我就给它找了个替死鬼last,在删除之前,我们先last = phead;phead = phead->next;然后直接free(last),就行了。
/*
delete_listT : 从前面开始删除链表节点
@*phead : 第一个结点的指针的地址
返回值 :
返回现在的头结点!
*/
Node* delete_listT(Node*phead)
{
Node* last = phead->next;
if(phead->next == NULL)
{
free(phead);
phead = NULL;
}
else
{
last = phead;
phead = phead->next;
free(last);
last = NULL;
//为了安全,详情看内存方面的知识
}
return phead;
}
查找
查找本质上就是一直遍历,当然,有很多算法可以去 可以去优化,但是在这里先不说,查找首先我们需要有个查找的对象,那这个对象就是我们查找的依据,如果我们是查找一个值,那么只需要找到数据域和这个值相等的,然后输出就行了
/*
Slist_find : 查找值为x的一个结点
@*phead : 第一个结点的指针的地址
@x : 要查找的值
返回值 :
指向要查找的结点的指针
*/
Node*Slist_find(Node*phead,ElemType x)
{
Node*cur = phead;
while (cur)
{
if(cur->data == x)
{
return cur;
}
else
{
cur = cur->next;
}
}
return NULL;
}
int main()
{
printf("请输入要查找的值\n");
scanf("%d",&x);
Node*p = Slist_find(phead,x);
if(p!=NULL)
{
printf("要查找的值为:%d",p->data);
}
else
{
printf("链表中没有这个数");
}
printf("\n");
}
替换
替换就是只需要把我查找到的那个data给换成你想要的数字就行了,所以只需要在main函数里面添加就行了。
完整代码
我全部放在gitcode里面了,直接进去复制就ok了。