网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
这段代码维护了两个节点指针prev和curr,标准的教科书写法——删除当前结点时,需要一个previous的指针,并且还要这里还需要做一个边界条件的判断——curr是否为链表头。于是,要删除一个节点(不是表头),只要将前一个节点的next指向当前节点的next指向的对象,即下一个节点(即:prev->next = curr->next),然后释放当前节点。
但在Linus看来,这是不懂指针的人的做法。
三、代码示例
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//s一般表示新生节点,p表示扫描指针
/\* 结构体定义 \*/
struct ListNode
{
int value;
ListNode \*next;
};
/\* 链表头 \*/
ListNode\* head = NULL;
/\*尾插法插入值\*/
void insertNode(int val)
{
if (head == NULL)
{
ListNode \*s = (ListNode\*)malloc(sizeof(ListNode));
s->value = val;
s->next = NULL;
head = s;
return;
}
else
{
//查找尾结点
ListNode \*p = head;
while (p->next != NULL)
{
p = p->next;
}
ListNode \*s = (ListNode\*)malloc(sizeof(ListNode));
s->value = val;
s->next = NULL;
//插入新生节点
s->next = p->next;
p->next = s;
}
}
/\* 删除第一个value=val的链表节点 \*/
void deleteNode(int val)
{
ListNode \*curr = head;
ListNode \*prev = NULL;
while (curr != NULL)
{
if (curr->value == val)
{
/\* 如果待删除的节点是链表头 \*/
if (curr == head)
{
head = head->next;
}
else
{
prev->next = curr->next;
}
free(curr);
return;
}
//存储previous指针并遍历所有节点
prev = curr;
curr = curr->next;
}
}
/\*根据头结点打印(不需要修改头结点地址,因此一级指针)\*/
void printNode(ListNode \*myhead)
{
if (myhead == NULL) return;
while (myhead)
{
printf("%d ", myhead->value);
myhead = myhead->next;
}
printf("--\n");
}
int main()
{
//插入
for (int i = 0; i < 3; ++i)
{
insertNode(i);
}
//打印
printNode(head);
//删除
deleteNode(2);
printNode(head);
deleteNode(1);
printNode(head);
deleteNode(0);
printNode(head);
return 0;
}
运行效果:
四、使用二级指针
在Linus看来,这是不懂指针的人的做法。那么,什么是core low-level coding呢?那就是有效地利用二级指针,将其作为管理和操作链表的首要选项。代码如下:
/\* 删除value=val的链表节点 \*/
int delete_from_list(int val)
{
ListNode ** curr = &head; //正在遍历的节点的指针
ListNode * entry; //正在遍历的节点
while (*curr)
{
entry = *curr; //注2
if (entry->value == val)
{
/\* 删除entry节点 \*/
*curr = entry->next; //注3
free(entry);
return 0;
}
/\* 遍历所有节点的指针 \*/
curr = &(entry->next); //注1
}
return -1;
}
使用二级指针,我们可以把头结点和其他节点等效对待。
同上一段代码有何改进呢?我们看到:不需要prev指针了,也不需要再去判断是否为链表头了,但是,curr变成了一个指向指针的指针。这正是这段程序的精妙之处。(注意,我所highlight的那三行代码)
让我们来人肉跑一下这个代码,对于——
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新