当前位置:   article > 正文

【零基础学数据结构】链表

【零基础学数据结构】链表

目录

1.链表的概念

​编辑 2.链表的雏形

​编辑 3.链表的组成

​编辑 4.链表代码

 4.1创建节点

 4.2链表的打印

 4.3链表的尾插

 4.4链表的头插

 4.5链表的尾删

 4.6链表的头删

 4.7链表的查找

 4.8链表在指定位置之前插⼊数据

 4.9链表在指定位置之后插⼊数据

 4.9-1删除pos节点

 4.9-2删除pos之后的节点

4.9-3销毁链表

补充:测试文件:


1.链表的概念

 2.链表的雏形

 3.链表的组成

 4.链表代码

 创建准备;

  • SListNode.h文件
  • SListNode.c文件
  • text.c文件 

 4.1创建节点

 数据+指向下一个节点的指针

  1. // 首先定义数据的类型,方便后续更改
  2. typedef int SLTNodeDataType;
  3. // 创建节点
  4. typedef struct SListNode
  5. {
  6. SLTNodeDataType data; // 存储数据
  7. struct SListNode* next;// 指向下一个节点的指针
  8. }SLTNode;

 

 4.2链表的打印

 头文件声明:

void SLTPrint(SLTNode* phead);

执行文件代码实现: 

  1. // 链表的打印
  2. void SLTPrint(SLTNode* phead)
  3. {
  4. SLTNode* pcur = phead;// 保证phead指向的位置是收节点,方便后续再次遍历
  5. while (pcur)// 等价于 pcur != NULL;
  6. {
  7. printf("%d->", pcur->data);
  8. pcur = pcur->next;
  9. }
  10. printf("NULL\n");
  11. }

 

 4.3链表的尾插

 头文件声明:

void SLTPushBack(SLTNode** pphead, SLTNodeDataType x);
  1. // 创建新的节点
  2. SLTNode* SLTBuyNode(SLTNodeDataType x)
  3. {
  4. SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
  5. if (NULL == newnode)
  6. {
  7. perror("SLTBuyNode malloc err!");
  8. exit(1);
  9. }
  10. // 创建节点成功
  11. newnode->data = x;
  12. newnode->next = NULL;
  13. // 返回
  14. return newnode;
  15. }

 执行文件代码实现: 

  1. // 链表的尾插
  2. void SLTPushBack(SLTNode** pphead, SLTNodeDataType x)
  3. {
  4. // 传参不可为空
  5. assert(pphead);
  6. // 创建一个新的节点
  7. SLTNode* newnode = SLTBuyNode(x);
  8. // 空链表和非空链表
  9. if (*pphead == NULL)
  10. {
  11. *pphead = newnode;
  12. }
  13. else
  14. {
  15. // 找尾巴
  16. SLTNode* ptail = *pphead;
  17. while (ptail->next) // 等价于ptail->next !=NULL;
  18. {
  19. ptail = ptail->next;
  20. }
  21. // 找到尾巴,开始连接
  22. ptail->next = newnode;
  23. }
  24. }

 

 4.4链表的头插

  头文件声明:

  1. // 链表的头插
  2. void SLTPushFront(SLTNode** pphead, SLTNodeDataType x);

 执行文件代码实现:

  1. // 链表的头插
  2. void SLTPushFront(SLTNode** pphead, SLTNodeDataType x)
  3. {
  4. // 传参不可为空
  5. assert(pphead);
  6. // 创建一个新的节点
  7. SLTNode* newnode = SLTBuyNode(x);
  8. // 头插
  9. newnode->next = *pphead;
  10. *pphead = newnode;
  11. }

头插就很简单了, 只需要创建新的节点放到链表的头部,不论是空链表和非空链表,情况都是一样的,连接好后,将头指针改指向,指向新头插的节点。

 4.5链表的尾删

 头文件声明:

void SLTPopBack(SLTNode** pphead);

  执行文件代码实现:

  1. // 链表的尾删
  2. void SLTPopBack(SLTNode** pphead)
  3. {
  4. // 链表不可以为空,传参不可为空
  5. assert(pphead && *pphead);
  6. // 链表有一个节点和多个节点
  7. // 一个节点
  8. if ((*pphead)->next == NULL)
  9. {
  10. free(*pphead);
  11. *pphead = NULL;
  12. }
  13. else //多个节点
  14. {
  15. // 找尾
  16. SLTNode* prev = *pphead;
  17. SLTNode* ptail = *pphead;
  18. while (ptail->next)
  19. {
  20. prev = ptail;
  21. ptail = ptail->next;
  22. }
  23. free(ptail); // 释放空间
  24. ptail = NULL;// 防止野指针
  25. prev->next = NULL;
  26. }
  27. }

 尾删除需要影响原链表,所以传二级指针,同时尾删时我们需要注意是否节点是一个,如果是一个,删除后链表为空,申请的空间需要释放,防止造成空间浪费。如果是多个节点,我们需要找尾巴ptail,并且记录前一个节点prev,删除尾节点并且释放,置为空,将prev->next=NULL。

 4.6链表的头删

 头文件声明:

void SLTPopFront(SLTNode** pphead);

   执行文件代码实现:

  1. // 链表的头删
  2. void SLTPopFront(SLTNode** pphead)
  3. {
  4. assert(pphead && *pphead);
  5. SLTNode* next = (*pphead)->next;
  6. free(*pphead);
  7. *pphead = next;
  8. }

 删除前断言所传的指针是否为空,链表是否为空,头删除前记录下一个节点,删除头节点后,将头置后。

 4.7链表的查找

 头文件声明:

SLTNode* SLTFind(SLTNode* phead, SLTNodeDataType x);

 执行文件代码实现:

  1. // 链表的查找
  2. SLTNode* SLTFind(SLTNode* phead, SLTNodeDataType x)
  3. {
  4. SLTNode* prev = phead;
  5. while (prev)// 等价于 prev != NULL;
  6. {
  7. if (prev->data == x)
  8. {
  9. return prev;
  10. }
  11. prev = prev->next;
  12. }
  13. // 遍历完毕没有找到,返回空。
  14. return NULL;
  15. }

 4.8链表在指定位置之前插⼊数据

 头文件声明:

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTNodeDataType x);

 执行文件代码实现:

  1. // 链表在指定位置之前插⼊数据
  2. void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTNodeDataType x)
  3. {
  4. // 不可以传入NULL
  5. assert(pphead && *pphead);
  6. assert(pos);
  7. // 创建一个新的节点
  8. SLTNode* newnode = SLTBuyNode(x);
  9. // 如果节点只有一个,就是头插
  10. if (pos == *pphead)
  11. {
  12. SLTPushFront(pphead, x);
  13. }
  14. else
  15. {
  16. SLTNode* pcur = *pphead;
  17. // pcur所指向的节点不为pos前一个节点
  18. while (pcur->next != pos)
  19. {
  20. pcur = pcur->next;
  21. }
  22. // pcur所指向的节点为pos前一个节点
  23. newnode->next = pos;
  24. pcur->next = newnode;
  25. }
  26. }

 4.9链表在指定位置之后插⼊数据

  头文件声明:

void SLTInsertAfter(SLTNode* pos, SLTNodeDataType x);

 执行文件代码实现:

  1. // 链表在指定位置之后插⼊数据
  2. void SLTInsertAfter(SLTNode* pos, SLTNodeDataType x)
  3. {
  4. assert(pos);
  5. // 创建要插入的节点
  6. SLTNode* newnode = SLTBuyNode(x);
  7. // 开始插入
  8. newnode->next = pos->next;
  9. pos->next = newnode;
  10. }

 4.9-1删除pos节点

 头文件声明:

void SLTErase(SLTNode** pphead, SLTNode* pos);

  执行文件代码实现:

  1. //删除pos节点
  2. void SLTErase(SLTNode** pphead, SLTNode* pos)
  3. {
  4. assert(pphead && *pphead);
  5. assert(pos);
  6. if (*pphead == pos)
  7. {
  8. SLTPopFront(pphead);
  9. }
  10. else
  11. {
  12. SLTNode* prev = *pphead;
  13. while (prev->next != pos)
  14. {
  15. prev = prev->next;
  16. }
  17. // prev所指向的就是pos前一个节点
  18. prev->next = pos->next;
  19. free(pos);
  20. pos = NULL;
  21. }
  22. }

 4.9-2删除pos之后的节点

 头文件声明:

void SLTEraseAfter(SLTNode* pos);

 执行文件代码实现:

  1. //删除pos之后的节点
  2. void SLTEraseAfter(SLTNode* pos)
  3. {
  4. assert(pos && pos->next); // 传过来的参数不可以为空,pos下一个的参数也不可以是NULL
  5. SLTNode* del = pos->next;
  6. pos->next = del->next;
  7. free(del);
  8. del = NULL;
  9. }

4.9-3销毁链表

 文件声明:

void SListDesTroy(SLTNode** pphead);

 执行文件代码实现:

  1. //销毁链表
  2. void SListDesTroy(SLTNode** pphead)
  3. {
  4. assert(pphead && *pphead);
  5. SLTNode* pcur = *pphead;
  6. while (pcur)
  7. {
  8. SLTNode* next = pcur->next;
  9. free(pcur);
  10. pcur = next;
  11. }
  12. // 全部销毁完后,置为空NULL;
  13. *pphead = NULL;
  14. }

补充:测试文件:

  1. //void SListNodeText01()
  2. //{
  3. // // 创建节点
  4. // SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));
  5. // node1->data = 1;
  6. //
  7. // SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
  8. // node2->data = 2;
  9. //
  10. // SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
  11. // node3->data = 3;
  12. //
  13. // SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
  14. // node4->data = 4;
  15. //
  16. // // 将四个节点连接起来
  17. // node1->next = node2;
  18. // node2->next = node3;
  19. // node3->next = node4;
  20. // node4->next = NULL;
  21. //
  22. // // 打印
  23. // SLTPrint(node1);
  24. //}
  25. void SLTNodeText02()
  26. {
  27. //SLTNode* plist = NULL;
  28. // 测试尾插
  29. //SLTPushBack(&plist, 1);
  30. //SLTPushBack(&plist, 2);
  31. //SLTPushBack(&plist, 3);
  32. //SLTPushBack(&plist, 4);
  33. /*SLTPrint(plist);*/// 1->2->3->4->NULL;
  34. // 测试头插
  35. /*SLTPushFront(&plist, 5);
  36. SLTPrint(plist);
  37. SLTPushFront(&plist, 6);
  38. SLTPrint(plist);
  39. SLTPushFront(&plist, 7);
  40. SLTPrint(plist);
  41. SLTPushFront(&plist, 8);
  42. SLTPrint(plist);*/
  43. // 测试尾删
  44. //SLTPopBack(&plist);
  45. //SLTPrint(plist);
  46. //SLTPopBack(&plist);
  47. //SLTPrint(plist);
  48. //SLTPopBack(&plist);
  49. //SLTPrint(plist);
  50. //SLTPopBack(&plist);
  51. //SLTPrint(plist);
  52. // 测试头删
  53. //SLTPopFront(&plist);
  54. //SLTPrint(plist);
  55. //SLTPopFront(&plist);
  56. //SLTPrint(plist);
  57. //SLTPopFront(&plist);
  58. //SLTPrint(plist);
  59. //SLTPopFront(&plist);
  60. //SLTPrint(plist);
  61. // 报错
  62. //SLTPopFront(&plist);
  63. //SLTPrint(plist);
  64. // 测试查找
  65. //SLTNode* find = SLTFind(plist, NULL);
  66. //if (find == NULL)
  67. //{
  68. // printf("没有找到!\n");
  69. //}
  70. //else
  71. //{
  72. // printf("找到了!\n");
  73. //}
  74. // 测试在pos位置之前插⼊数据
  75. //SLTNode* find = SLTFind(plist, 1);
  76. //SLTInsert(&plist, find, 11);
  77. //SLTPrint(plist);
  78. // 测试链表在指定位置之后插⼊数据
  79. /*SLTNode* find = SLTFind(plist, 4);
  80. SLTInsertAfter(find, 11);
  81. SLTPrint(plist);*/
  82. // 测试删除pos之后的节点
  83. /*SLTNode* find = SLTFind(plist, 1);
  84. SLTEraseAfter(find);
  85. SLTPrint(plist);*/
  86. // 测试销毁
  87. SListDesTroy(&plist);
  88. }
  89. int main()
  90. {
  91. //SListNodeText01();
  92. SLTNodeText02();
  93. return 0;
  94. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/458332
推荐阅读
相关标签
  

闽ICP备14008679号