数据布局——链表

[复制链接]
发表于 2026-1-18 21:35:59 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
【本节内容】

1.链表

1.链表的概念及布局

概念:链表是一种物理存储布局上非一连、非序次的存储布局,数据元素的逻辑序次是通过链表中的指针链接序次实现的 。就像我们一节一节的小火车一样,靠中心的链子链接在一起。


实际中 数据布局中
 





1.2 链表的分类

实际中链表的布局非常多样,以下情况组合起来就有8种链表布局:

1. 单向大概双向
 




2. 带头大概不带头
 




3. 循环大概非循环
 




固然有这么多的链表的布局,但是我们实际中最常用还是两种布局:
 


1. 无头单向非循环链表:布局简单,一样平常不会单独用来存数据。实际中更多是作为其他数据布局的子布局,如哈希桶、图的毗邻表等等。别的这种布局在笔试口试中出现许多。
2. 带头双向循环链表:布局最复杂,一样平常用在单独存储数据。实际中利用的链表数据布局,都是带头双向循环链表。别的这个布局固然布局复杂,但是利用代码实现以后会发现布局会带来许多上风,实现反而简单了,背面我们代码实现了就知道了。
 

1、无头+单向+非循环链表增删查改实现
SList.h
  1. #pragma once
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<assert.h>
  5. typedef int SLTDataType;
  6. typedef struct SListNode
  7. {
  8.         SLTDataType data;
  9.         struct SListNode* next;
  10. }SLTNode;
  11. void SLTPrint(SLTNode* phead);//打印链表
  12. void SLPushFront(SLTNode** pphead, SLTDataType x);//头插
  13. void SLPushBack(SLTNode** pphead, SLTDataType x);//尾插
  14. void SLPopFront(SLTNode** pphead);//头删
  15. void SLPopBack(SLTNode** pphead);//尾删
  16. void SLErase(SLTNode** pphead, SLTNode* pos);// 删除pos位置的值
  17. void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);//在pos位置插入
  18. SLTNode* STFind(SLTNode* phead, SLTDataType x);//查找与x值相同的节点位置
复制代码
SList.c
  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include"Slist.h"
  3. void SLTPrint(SLTNode* phead)//打印链表
  4. {
  5.         SLTNode* cur = phead;
  6.         while (cur != NULL)
  7.         {
  8.                 printf("%d->", cur->data);
  9.                 cur = cur->next;
  10.         }
  11.         printf("NULL\n");
  12. }
  13. SLTNode* BuyLTNode(SLTDataType x)//初始化节点
  14. {
  15.         SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
  16.         if (newnode == NULL)
  17.         {
  18.                 perror("malloc fail");
  19.                 return NULL;
  20.         }
  21.         newnode->data = x;
  22.         newnode->next = NULL;
  23.         return newnode;
  24. }
  25. void SLPushFront(SLTNode** pphead, SLTDataType x)//头插
  26. {
  27.         SLTNode* newnode = BuyLTNode(x);
  28.         newnode->next = *pphead;
  29.         *pphead = newnode;
  30. }
  31. void SLPushBack(SLTNode** pphead, SLTDataType x)//尾插
  32. {
  33.         SLTNode* newnode = BuyLTNode(x);
  34.         // 1、空链表
  35.         if (*pphead == NULL)
  36.         {
  37.                 *pphead = newnode;
  38.         }
  39.         // 2、非空链表
  40.         else
  41.         {
  42.                 SLTNode* tail = *pphead;
  43.                 while (tail->next != NULL)
  44.                 {
  45.                         tail = tail->next;
  46.                 }
  47.                 tail->next = newnode;
  48.         }
  49. }
  50. void SLPopFront(SLTNode** pphead)//头删
  51. {
  52.         // 判空
  53.         assert(*pphead);
  54.         SLTNode* del = *pphead;
  55.         *pphead = (*pphead)->next;
  56.         free(del);
  57. }
  58. void SLPopBack(SLTNode** pphead)//尾删
  59. {
  60.         assert(*pphead);
  61.         // 一个节点
  62.         if ((*pphead)->next == NULL)
  63.         {
  64.                 free(*pphead);
  65.                 *pphead = NULL;
  66.         }
  67.         // 多个节点
  68.         else
  69.         {
  70.                 SLTNode* tail = *pphead;
  71.                 // 找尾
  72.                 while (tail->next->next)
  73.                 {
  74.                         tail = tail->next;
  75.                 }
  76.                 free(tail->next);
  77.                 tail->next = NULL;
  78.         }
  79. }
  80. SLTNode* STFind(SLTNode* phead, SLTDataType x)//查找与x值相同的节点位置
  81. {
  82.         SLTNode* cur = phead;
  83.         while (cur)
  84.         {
  85.                 if (cur->data == x)
  86.                 {
  87.                         return cur;
  88.                 }
  89.                 cur = cur->next;
  90.         }
  91.         return NULL;
  92. }
  93. void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)//在pos位置插入
  94. {
  95.         assert(pphead);
  96.         assert(pos);
  97.         if (*pphead == pos)
  98.         {
  99.                 SLPushFront(pphead, x);
  100.         }
  101.         else
  102.         {
  103.                 SLTNode* prev = *pphead;
  104.                 while (prev->next != pos)
  105.                 {
  106.                         prev = prev->next;
  107.                 }
  108.                 SLTNode* newnode = BuyLTNode(x);
  109.                 prev->next = newnode;
  110.                 newnode->next = pos;
  111.         }
  112. }
  113. void SLErase(SLTNode** pphead, SLTNode* pos)// 删除pos位置的值
  114. {
  115.         assert(pphead);
  116.         assert(pos);
  117.         if (pos == *pphead)
  118.         {
  119.                 SLPopFront(pphead);
  120.         }
  121.         else
  122.         {
  123.                 SLTNode* prev = *pphead;
  124.                 while (prev->next != pos)
  125.                 {
  126.                         prev = prev->next;
  127.                 }
  128.                 prev->next = pos->next;
  129.                 free(pos);
  130.         }
  131. }
复制代码
test.c
  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include "SList.h"
  3. int main()
  4. {
  5.         SLTNode* plist = NULL;
  6.         SLPushBack(&plist, 1);
  7.         SLPushBack(&plist, 2);
  8.         SLPushBack(&plist, 3);
  9.         SLPushBack(&plist, 4);
  10.         SLPushFront(&plist, 0);
  11.         SLPopBack(&plist);
  12.         SLPopFront(&plist);
  13.         SLTNode* pos = STFind(plist, 1);
  14.         SLErase(&plist, pos);
  15.         SLTPrint(plist);
  16.         return 0;
  17. }
复制代码
运行效果:


 
2.双向链表:
DList.h
  1. #pragma once
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<assert.h>
  5. #include<stdbool.h>
  6. typedef int LTDataType;
  7. typedef struct ListNode
  8. {
  9.         struct ListNode* next;
  10.         struct ListNode* prev;
  11.         LTDataType data;
  12. }LTNode;
  13. LTNode* LTInit();//初始化双向链表
  14. void LTPrint(LTNode* phead);//打印双向链表
  15. bool LTEmpty(LTNode* phead);//判断链表是否为空
  16. void LTPushBack(LTNode* phead, LTDataType x);//双向链表尾插
  17. void LTPushFront(LTNode* phead, LTDataType x);//双向链表头插
  18. void LTPopBack(LTNode* phead);//双向链表尾删
  19. void LTPopFront(LTNode* phead);//双向链表头删
  20. LTNode* LTFind(LTNode* phead, LTDataType x);//查找与x值相同的节点
  21. void LTInsert(LTNode* pos, LTDataType x);// 在pos位置插入
  22. void LTErase(LTNode* pos);// 删除pos位置的值
  23. void LTDestroy(LTNode* phead);//销毁双向链表
复制代码
DList.c
  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include"DList.h"
  3. LTNode* BuyLTNode(LTDataType x)//初始化节点
  4. {
  5.         LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
  6.         if (newnode == NULL)
  7.         {
  8.                 perror("malloc fail");
  9.                 return NULL;
  10.         }
  11.         newnode->data = x;
  12.         newnode->next = NULL;
  13.         newnode->prev = NULL;
  14.         return newnode;
  15. }
  16. LTNode* LTInit()//初始化双向链表
  17. {
  18.         LTNode* phead = BuyLTNode(-1);
  19.         phead->next = phead;
  20.         phead->prev = phead;
  21.         return phead;
  22. }
  23. void LTPrint(LTNode* phead)//打印双向链表
  24. {
  25.         assert(phead);
  26.         printf("guard<==>");
  27.         LTNode* cur = phead->next;
  28.         while (cur != phead)
  29.         {
  30.                 printf("%d<==>", cur->data);
  31.                 cur = cur->next;
  32.         }
  33.         printf("\n");
  34. }
  35. bool LTEmpty(LTNode* phead)//判断双向链表是否为空
  36. {
  37.         assert(phead);
  38.         return phead->next == phead;
  39. }
  40. void LTPushBack(LTNode* phead, LTDataType x)//双向链表尾插
  41. {
  42.         assert(phead);
  43.         LTInsert(phead, x);
  44. }
  45. void LTPushFront(LTNode* phead, LTDataType x)//双向链表头插
  46. {
  47.         LTInsert(phead->next, x);
  48. }
  49. void LTPopBack(LTNode* phead)//双向链表尾删
  50. {
  51.         assert(phead);
  52.         assert(!LTEmpty(phead));
  53.         LTErase(phead->prev);
  54. }
  55. void LTPopFront(LTNode* phead)//双向链表头删
  56. {
  57.         assert(phead);
  58.         assert(!LTEmpty(phead));
  59.         LTErase(phead->next);
  60. }
  61. LTNode* LTFind(LTNode* phead, LTDataType x)//查找与x值相同的节点
  62. {
  63.         assert(phead);
  64.         LTNode* cur = phead->next;
  65.         while (cur != phead)
  66.         {
  67.                 if (cur->data == x)
  68.                 {
  69.                         return cur;
  70.                 }
  71.                 cur = cur->next;
  72.         }
  73.         return NULL;
  74. }
  75. void LTInsert(LTNode* pos, LTDataType x)// 在pos位置插入
  76. {
  77.         assert(pos);
  78.         LTNode* prev = pos->prev;
  79.         LTNode* newnode = BuyLTNode(x);
  80.         prev->next = newnode;
  81.         newnode->prev = prev;
  82.         newnode->next = pos;
  83.         pos->prev = newnode;
  84. }
  85. void LTErase(LTNode* pos)//删除pos位置的值
  86. {
  87.         assert(pos);
  88.         LTNode* posPrev = pos->prev;
  89.         LTNode* posNext = pos->next;
  90.         posPrev->next = posNext;
  91.         posNext->prev = posPrev;
  92.         free(pos);
  93. }
  94. void LTDestroy(LTNode* phead)//销毁双向链表
  95. {
  96.         assert(phead);
  97.         LTNode* cur = phead->next;
  98.         while (cur != phead)
  99.         {
  100.                 LTNode* next = cur->next;
  101.                 free(cur);
  102.                 cur = next;
  103.         }
  104.         free(phead);
  105. }
复制代码
test.c
  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include "DList.h"
  3. int main()
  4. {
  5.         LTNode* plist = LTInit();
  6.         printf("%d\n",LTEmpty(plist));
  7.         LTPushBack(plist, 1);
  8.         LTPushBack(plist, 2);
  9.         LTPushBack(plist, 3);
  10.         LTPushBack(plist, 4);
  11.         LTPushBack(plist, 5);
  12.         LTPushBack(plist, 6);
  13.         LTPopFront(plist);
  14.         LTPopBack(plist);
  15.         LTNode* pos = LTFind(plist,2);
  16.         LTErase(pos);
  17.         LTPrint(plist);
  18.         LTDestroy(plist);
  19.         return 0;
  20. }
复制代码
运行效果:



 
PS:看到这里了,码字不易,给个一键三连鼓励一下吧!有不敷大概错误之处接待在批评区指出!
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表