当前位置:   article > 正文

数据结构之线性表(单链表的实现)

数据结构之线性表(单链表的实现)

目录

一、单链表的原理

二、单链表的实现

1.单链表的定义

2.单链表的初始化

3.清空单链表

4.单链表是否为空

5.单链表的长度

6.获取指定位置 i 的元素

7.获取指定元素 e 的位置  

8.向链表中插入指定位置的元素

9.向链表中删除指定位置的元素

10.遍历链表中的元素

三、打印测试功能

1.测试

2.结果输出

3.总代码


一、单链表的原理

        本章节紧跟上一篇文章《顺序表的实现》来继续讲述线性表的一种:单链表。

        前面我们讲的线性表的顺序存储结构。它是有缺点的,最大的缺点就是插入和删除时需要移动大量元素,这显然就需要耗费时间。能不能想办法解决呢?

         要解决这个问题,我们就得考虑一下导致这个问题的原因。为什么当插入和删除时,就要移动大量元素,仔细分析后,发现原因就在于相邻两元素的存储位置也具有邻居关系。它们编号是1,2,3,…,n,它们在内存中的位置也是挨着的,中间没有空隙,当然就无法快速介入,而删除后,当中就会留出空隙,自然需要弥补。问题就出在这里。

        我们可以在第一个元素时,就知道第二个元素的位置(内存地址),而找到它;在第二个元素时,再找到第三个元素的位置(内存地址)。这样所有的元素我们就都可以通过遍历而找到,而这就是单链表的特点,如下图所示。

         而链表的结构则如下图所示,第一个节点的指针由头节点所指,第二个节点的指针由第一个节点所指,以此类推。

二、单链表的实现

1.单链表的定义

        定义一些功能常量和单链表的结构。

        这里需要注意的是,我给链表起别名的是一个指针,后面我们在实现链表功能的时候,我们传递函数参数的时候要传递的是一个双指针(LinkList* L)。 这是因为链表的结构使然,因为链表存储的是其他链表的指针,它是一个地址,后面我们在进行链表的增加和删除的时候,会经常涉及到指针的变化。

        如果函数的参数是本身一级指针,那么在函数内部对指针的修改将不会反映到函数外部,因为函数接收到的是指针的一个副本。使用指针的指针作为参数,则可以确保在函数内部对指针的修改能够反映到原始的指针上。

typedef  struct  Node*  LinkList;

  1. #include <iostream>
  2. #define MAX_SIZE 20
  3. #define OK 1
  4. #define ERROR 0
  5. #define TRUE 1
  6. #define FALSE 0
  7. typedef int Status;
  8. typedef int ElemType;
  9. typedef struct Node
  10. {
  11. ElemType data;
  12. struct Node* next;
  13. }Node;
  14. typedef struct Node* LinkList;
2.单链表的初始化

        链表的初始化主要是为头节点分配内存空间,使它的data 和 next 都指向为 NULL,方便我们后续的操作。

  1. Status InitList(LinkList* L)
  2. {
  3. *L = (LinkList)malloc(sizeof(Node));
  4. if (*L == NULL) return ERROR;
  5. (*L)->data = 0;
  6. (*L)->next = NULL;
  7. return OK;
  8. }
3.清空单链表

        对链表进行清空操作,因为是用 malloc 进行分配的空间,对堆中的空间进行释放操作。

  1. Status ClearList(LinkList* L)
  2. {
  3. LinkList p, q;
  4. p = (*L)->next;
  5. while (p != NULL)
  6. {
  7. q = p->next;
  8. free(p);
  9. p = q;
  10. }
  11. (*L)->next = NULL;
  12. return OK;
  13. }
4.单链表是否为空

        判断头节点指向的元素是否为空。即 next 是否为 NULL。

  1. Status isListEmpty(LinkList L)
  2. {
  3. if (L->next == NULL) return TRUE;
  4. return FALSE;
  5. }
5.单链表的长度

        求链表的长度,定义一个变量,然后用while循环遍历链表

  1. int ListLength(LinkList L)
  2. {
  3. int num{ 0 };
  4. LinkList temp = L->next;
  5. while (temp != NULL)
  6. {
  7. temp = temp->next;
  8. num++;
  9. }
  10. return num;
  11. }
6.获取指定位置 i 的元素

        定义一个变量,进行while操作,判断是否与指定位置 i 相同,获取其节点值。

  1. Status GetElem(LinkList L, int i, ElemType* e)
  2. {
  3. int num{ 1 };
  4. LinkList temp = L->next;
  5. while (temp != NULL && num < i)
  6. {
  7. temp = temp->next;
  8. num++;
  9. }
  10. if (temp == NULL || num > i) return ERROR;
  11. *e = temp->data;
  12. }
7.获取指定元素 e 的位置  

        和上述功能类似,返回值为 int 位置。

  1. int LocateElem(LinkList L, ElemType* e)
  2. {
  3. int num{ 0 };
  4. LinkList temp = L->next;
  5. while (temp != NULL)
  6. {
  7. num++;
  8. if (temp->data = *e)
  9. {
  10. return num;
  11. }
  12. temp = temp->next;
  13. }
  14. return 0;
  15. }
8.向链表中插入指定位置的元素

          此功能为链表的难点所在,需要根据图像理解实现,如下图所示。 

     

  1. Status LinkInsert(LinkList* L, int i, ElemType e)
  2. {
  3. int j;
  4. LinkList p, s;
  5. p = *L;
  6. j = 1;
  7. while (p != NULL && j < i)
  8. {
  9. p = p->next;
  10. ++j;
  11. }
  12. if (!p || j > i) return ERROR;
  13. s = (LinkList)malloc(sizeof(Node));
  14. if (s == NULL) return ERROR;
  15. s->data = e;
  16. s->next = p->next;
  17. p->next = s;
  18. return OK;
  19. }
9.向链表中删除指定位置的元素

        和上功能类似,如图所示。

  1. Status LinkDelete(LinkList* L, int i, ElemType* e)
  2. {
  3. int j;
  4. LinkList p, s;
  5. j = 1;
  6. p = (*L);
  7. while (p != NULL && j < i)
  8. {
  9. p = p->next;
  10. ++j;
  11. }
  12. if (!p || j > i) return ERROR;
  13. s = p->next;
  14. p->next = s->next;
  15. *e = s->data;
  16. free(s);
  17. return OK;
  18. }
10.遍历链表中的元素

        功能比较简单,通过不断遍历打印其节点的data值。

  1. Status visit(ElemType e)
  2. {
  3. printf("%d->", e);
  4. return OK;
  5. }
  6. Status ListTraverse(LinkList L)
  7. {
  8. LinkList p = L->next;
  9. while (p != NULL)
  10. {
  11. visit(p->data);
  12. p = p->next;
  13. }
  14. printf("\n");
  15. return OK;
  16. }

三、打印测试功能

1.测试

        测试主要为测试以上的功能是否可以实现。

  1. int TestSingleList()
  2. {
  3. LinkList L;
  4. ElemType e;
  5. Status ret;
  6. int j, k;
  7. // 初始化
  8. ret = InitList(&L);
  9. printf("初始化长度:%d\n", ListLength(L));
  10. for(j = 1; j <= 5; j++)
  11. {
  12. ret = LinkInsert(&L, 1, j);
  13. }
  14. printf("插入5个元素后:");
  15. ListTraverse(L);
  16. ret = isListEmpty(L);
  17. printf("是否为空,%d\n", ret);
  18. ret = ClearList(&L);
  19. printf("清空后的长度:%d\n", ListLength(L));
  20. printf("是否为空,%d\n", ret);
  21. for (j = 1; j <= 10; j++)
  22. {
  23. ret = LinkInsert(&L, j, j);
  24. }
  25. printf("插入10个元素后:");
  26. ListTraverse(L);
  27. LinkInsert(&L, 3, 100);
  28. printf("在第2个节点后面增加元素100:");
  29. ListTraverse(L);
  30. LinkDelete(&L, 2, &e);
  31. printf("删除第二个节点,节点元素为%d :", e);
  32. ListTraverse(L);
  33. ClearList(&L);
  34. return 0;
  35. }
2.结果输出

           结果输出如图所示:

3.总代码

        总代码如下:

  1. #include <iostream>
  2. #define MAX_SIZE 20
  3. #define OK 1
  4. #define ERROR 0
  5. #define TRUE 1
  6. #define FALSE 0
  7. typedef int Status;
  8. typedef int ElemType;
  9. typedef struct Node
  10. {
  11. ElemType data;
  12. struct Node* next;
  13. }Node;
  14. typedef struct Node* LinkList;
  15. Status visit(ElemType e)
  16. {
  17. printf("%d->", e);
  18. return OK;
  19. }
  20. Status InitList(LinkList* L)
  21. {
  22. *L = (LinkList)malloc(sizeof(Node));
  23. if (*L == NULL) return ERROR;
  24. (*L)->data = 0;
  25. (*L)->next = NULL;
  26. return OK;
  27. }
  28. Status ClearList(LinkList* L)
  29. {
  30. LinkList p, q;
  31. p = (*L)->next;
  32. while (p != NULL)
  33. {
  34. q = p->next;
  35. free(p);
  36. p = q;
  37. }
  38. (*L)->next = NULL;
  39. return OK;
  40. }
  41. Status isListEmpty(LinkList L)
  42. {
  43. if (L->next == NULL) return TRUE;
  44. return FALSE;
  45. }
  46. int ListLength(LinkList L)
  47. {
  48. int num{ 0 };
  49. LinkList temp = L->next;
  50. while (temp != NULL)
  51. {
  52. temp = temp->next;
  53. num++;
  54. }
  55. return num;
  56. }
  57. Status GetElem(LinkList L, int i, ElemType* e)
  58. {
  59. int num{ 1 };
  60. LinkList temp = L->next;
  61. while (temp != NULL && num < i)
  62. {
  63. temp = temp->next;
  64. num++;
  65. }
  66. if (temp == NULL || num > i) return ERROR;
  67. *e = temp->data;
  68. }
  69. int LocateElem(LinkList L, ElemType* e)
  70. {
  71. int num{ 0 };
  72. LinkList temp = L->next;
  73. while (temp != NULL)
  74. {
  75. num++;
  76. if (temp->data = *e)
  77. {
  78. return num;
  79. }
  80. temp = temp->next;
  81. }
  82. return 0;
  83. }
  84. Status LinkInsert(LinkList* L, int i, ElemType e)
  85. {
  86. int j;
  87. LinkList p, s;
  88. p = *L;
  89. j = 1;
  90. while (p != NULL && j < i)
  91. {
  92. p = p->next;
  93. ++j;
  94. }
  95. if (!p || j > i) return ERROR;
  96. s = (LinkList)malloc(sizeof(Node));
  97. if (s == NULL) return ERROR;
  98. s->data = e;
  99. s->next = p->next;
  100. p->next = s;
  101. return OK;
  102. }
  103. Status LinkDelete(LinkList* L, int i, ElemType* e)
  104. {
  105. int j;
  106. LinkList p, s;
  107. j = 1;
  108. p = (*L);
  109. while (p != NULL && j < i)
  110. {
  111. p = p->next;
  112. ++j;
  113. }
  114. if (!p || j > i) return ERROR;
  115. s = p->next;
  116. p->next = s->next;
  117. *e = s->data;
  118. free(s);
  119. return OK;
  120. }
  121. Status ListTraverse(LinkList L)
  122. {
  123. LinkList p = L->next;
  124. while (p != NULL)
  125. {
  126. visit(p->data);
  127. p = p->next;
  128. }
  129. printf("\n");
  130. return OK;
  131. }
  132. Status CreateListHead(LinkList* L,int n)
  133. {
  134. LinkList p;
  135. srand((unsigned)time(0));
  136. *L = (LinkList)malloc(sizeof(Node));
  137. if (*L == NULL) return ERROR;
  138. (*L)->next = NULL;
  139. for (int i = 0; i < n; i++)
  140. {
  141. p = (LinkList)malloc(sizeof(Node));
  142. if (p == NULL) return ERROR;
  143. p->data = rand() % 100 + 1;
  144. p->next = (*L)->next;
  145. (*L)->next = p;
  146. }
  147. return OK;
  148. }
  149. Status CreateListTail(LinkList* L,int n)
  150. {
  151. LinkList p, r;
  152. srand((unsigned)time(0));
  153. *L = (LinkList)malloc(sizeof(Node));
  154. if (*L == NULL) return ERROR;
  155. (*L)->next = NULL;
  156. r = (*L);
  157. for (int i = 0; i < n; i++)
  158. {
  159. p = (LinkList)malloc(sizeof(Node));
  160. if (p == NULL) return ERROR;
  161. p->data = rand() % 100 + 1;
  162. r->next = p;
  163. r = p;
  164. }
  165. return OK;
  166. }
  167. int TestSingleList()
  168. {
  169. LinkList L;
  170. ElemType e;
  171. Status ret;
  172. int j, k;
  173. // 初始化
  174. ret = InitList(&L);
  175. printf("初始化长度:%d\n", ListLength(L));
  176. for(j = 1; j <= 5; j++)
  177. {
  178. ret = LinkInsert(&L, 1, j);
  179. }
  180. printf("插入5个元素后:");
  181. ListTraverse(L);
  182. ret = isListEmpty(L);
  183. printf("是否为空,%d\n", ret);
  184. ret = ClearList(&L);
  185. printf("清空后的长度:%d\n", ListLength(L));
  186. printf("是否为空,%d\n", ret);
  187. for (j = 1; j <= 10; j++)
  188. {
  189. ret = LinkInsert(&L, j, j);
  190. }
  191. printf("插入10个元素后:");
  192. ListTraverse(L);
  193. LinkInsert(&L, 3, 100);
  194. printf("在第2个节点后面增加元素100:");
  195. ListTraverse(L);
  196. LinkDelete(&L, 2, &e);
  197. printf("删除第二个节点,节点元素为%d :", e);
  198. ListTraverse(L);
  199. ClearList(&L);
  200. return 0;
  201. }
  202. int main()
  203. {
  204. return TestSingleList();
  205. }

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号