深圳幻海软件技术有限公司 欢迎您!

舍友打游戏的时候,我学会了单链表

2023-04-15

🎉🎉🎉哈喽!!!大家好,这里是禾子日月🎆欢迎各位小伙伴关注➕点赞➕留言➕收藏🎆我坚信努力奔跑才能与幸运不期而遇。目录1、为什么要学链表2.链表的定义3、链表的插入①尾插②头插③其他位置插入4、链表的删除①尾删②头删③其他位置删除5、打印链表6、销毁链表写在最后🎇🎇🎇上篇文章我们用顺序

🎉🎉🎉哈喽!!!大家好,这里是禾子日月

🎆欢迎各位小伙伴关注➕点赞➕留言➕收藏

🎆我坚信努力奔跑才能与幸运不期而遇。

目录

1、为什么要学链表

2.链表的定义

3、链表的插入

①尾插

②头插

③其他位置插入

4、链表的删除

①尾删

②头删

③其他位置删除

5、打印链表

6、销毁链表

写在最后


🎇🎇🎇上篇文章我们用顺序表写了一个目录,通过写目录我们又巩固了顺序表的相关知识,如果你对这个感兴趣可以点击下方的链接哦。

👇👇👇

http://t.csdn.cn/HSkor

🎉🎉🎉废话不多说,我们开始今天的内容。

1、为什么要学链表

在回答这个问题之前,我们先引入一个例子:

 首先我们想到的是用数组存储,但是用数组有些不便之处。因为事先我们并不知道文件1.txt中数据的个数,因此数组的大小不易确定。数组定义的太小,不能容纳所有数据;定义的太大,造成内存空间的浪费。——该问题用动态数组可以解决。

数组需要占用连续的内存空间,当没有所需大小的连续空间时,程序不能运行。——该问题用链表可以解决。

2.链表的定义

链表分为单向链表和双向链表。链表的每个元素称为一个节点。每个节点包含两部分

第一部分  data;第二部分  next。  data时用户需要的数据(可以是一个成员,或多个成员),称为链表的数据领域;next为下一个节点的地址,或称为指向下一个节点的指针,它也被称为链表的指针域。看到这里你可能似懂非懂,接下来上图🎈🎈🎈

 链表的尾部是链表的最后一个节点,即指针域为NULL的节点。链表的长度不是固定的,随时可以添加,如果添加到链表的尾部,则新的节点将成为链表的结尾。所以任何一个需要添加到链表尾部的新节点,其指针域必须是NULL,并使原来链表的结尾指针域指向新的节点。

接下来我们创建一个链表

  1. typedef struct SLinkNode
  2. {
  3. int data;
  4. struct SLinkNode *next;
  5. }SLTNode;

※※注意:我们在定义链表的时候可以使用typedf关键字起一个别名,这样在后面的操作中会省下不少事。SLTNode   等价于 struct SLinkNode。

main函数中代码

  1. int main()
  2. {
  3. SLTNode *plist=NULL;
  4. return 0;
  5. }

3、链表的插入

①尾插

尾插示意图:

尾插后原链表最后一个节点的指针域不再为NULL而是指向新节点。接下来我们用代码来实现一下。

  1. void SListPushBack(SLTNode **pphead,int x)
  2. {
  3. SLTNode *newnode=(SLTNode*)malloc(sizeof(SLTNode));
  4. newnode->data = x;
  5. newnode->next = NULL;
  6. if(*pphead==NULL)
  7. {
  8. *pphead=newnode;
  9. }
  10. else
  11. {
  12. SLTNode *tail = *pphead;
  13. while(tail->next !=NULL)
  14. {
  15. tail=tail->next;
  16. }
  17. tail->next=newnode;
  18. }
  19. }

②头插

头插示意图:

 头插时我们只需要将新节点的指针域指向头节点即可。

代码如下:

  1. void SListPushFront(SLTNode **pphead,SLTDataType x)
  2. {
  3. SLTNode *newnode=(SLTNode*)malloc(sizeof(SLTNode));
  4. newnode->data = x;
  5. newnode->next = *pphead;
  6. *pphead=newnode;
  7. }

③其他位置插入

其他位置插入示意图:

 从其他插入我们需要先断开两个节点之间的联系。

  1. //在pos位置插入一个节点
  2. void SListInsert(SLTNode **pphead,SLTNode *pos,SLTDataType x)
  3. {
  4. SLTNode *newnode=(SLTNode*)malloc(sizeof(SLTNode));
  5. newnode->data = x;
  6. if(*pphead==pos)
  7. {
  8. newnode->next =*pphead;
  9. *pphead=newnode;
  10. }
  11. else
  12. {
  13. //找到pos的前一个位置
  14. SLTNode *posPrev = *pphead;
  15. while(posPrev->next != pos)
  16. {
  17. posPrev=posPrev->next;
  18. }
  19. posPrev->next = newnode;
  20. newnode->next =pos;
  21. }
  22. }

4、链表的删除

①尾删

尾删示意图:

 尾删时,我们只需要将最后一个节点前面的节点的指针域变成NULL即可。

代码如下:

  1. void SListPopBack(SLTNode **pphead)
  2. {
  3. if(*pphead==NULL)//判断链表是否为空
  4. {
  5. return;
  6. }
  7. SLTNode *tail=*pphead;
  8. while(tail->next->next ){
  9. tail=tail->next;
  10. }
  11. free(tail->next);
  12. tail->next =NULL;
  13. }

②头删

头删示意图:

代码如下:

  1. void SListPopFront(SLTNode **pphead)
  2. {
  3. assert(pphead);
  4. if(*pphead==NULL)//判断链表是否为空
  5. return;
  6. SLTNode *q=(*pphead)->next;
  7. free(*pphead);
  8. *pphead=q;
  9. }

③其他位置删除

其他位置删除示意图:

 代码如下:

  1. void SListErase(SLTNode **pphead,SLTNode *pos)
  2. {
  3. if(*pphead==pos)
  4. {
  5. SListPopFront(pphead);//如果要删除的是头节点,我们偷个懒直接调用
  6. }
  7. else
  8. {
  9. SLTNode *prev=*pphead;
  10. while(prev->next !=pos)
  11. {
  12. prev=prev->next ;
  13. }
  14. prev->next =pos->next ;
  15. free(pos);
  16. }
  17. }

5、打印链表

打印链表比较简单,我们只需要遍历一次链表就可以了。

  1. void SListPrint(SLTNode *phead)
  2. {
  3. SLTNode *cur=phead;
  4. while(cur!=NULL)
  5. {
  6. printf("%d->",cur->data);
  7. cur = cur->next;
  8. }
  9. printf("NULL");
  10. }

6、销毁链表

链表的节点都是我们在内存中申请的,使用完后要销毁掉。

  1. void SListDestory(SLTNode **pphead)
  2. {
  3. assert(pphead);
  4. SLTNode *cur= *pphead;
  5. while(cur)
  6. {
  7. SLTNode *next=cur->next ;
  8. free(cur);
  9. }
  10. *pphead=NULL;
  11. }

写在最后

🎉🎉🎉以上就是本篇文章全部内容,作者知识水平有限,若有什么错误或者需改进之处希望大家指出,若是你有更好的代码希望能给博主留言,博主希望能在CSDN与各位一起进步,感谢大家观看!

文章知识点与官方知识档案匹配,可进一步学习相关知识
算法技能树首页概览44139 人正在系统学习中