线性表—链式存储之单链表

落日映苍穹つ 2021-11-15 12:52 596阅读 0赞

线性表—链式存储之单链表

  • 1、定义
  • 2、表示方式
  • 3、时间效率
  • 4、相关概念
  • 5、头指针与头结点的异同
  • 6、带头节点的单链表与不带头结点的单链表
  • 7、单链表的优缺点(相比于线性表)
  • 8、带头结点的单链表代码

1、定义

用一组地址任意的存储单元存放线性表中的数据元素。
其结构特点:逻辑上相邻的数据元素在物理上不一定相邻。

2、表示方式

链表中的数据是以结点来表示

3、时间效率

*插入和删除一个数据元素的时间复杂度为O(1)
*查找的时间复杂度为O(n)

4、相关概念

数据域

存储数据元素信息的域

指针域

存储后继元素的域

节点

数据域+指针域

头指针

指向链表中第一个结点(或为头结点、或为首元结点)的指针

头结点

在链表的首元结点之前附设的一个结点;数据域内只放空表标志和表长等信息,它不计入表长度

首元结点

指链表中存储线性表第一个数据元素a0的结点在这里插入图片描述

5、头指针与头结点的异同

头指针

*头指针具有标识作用,所以常用头指针冠以链表的名字
*头指针必须有。无论链表是否为空,头指针不为空。

头结点

*头结点不是必需的
*头结点的数据域一般无意义(也可存放链表长度)
*头结点使得对首元结点的插入与删除与其他节点的操作统一起来了

6、带头节点的单链表与不带头结点的单链表

带头节点的单链表
在这里插入图片描述
不带头结点的单链表
在这里插入图片描述

7、单链表的优缺点(相比于线性表)

和顺序表相比,单链表的优点和缺点正好相反
优点

*不需要预先确定数据元素的最大个数
*插入和删除操作不需要移动数据元素

缺点

*查找数据元素时需要顺序进行,不能像顺序表那样随机查找任意一个数据元素
*每个结点中要有一个指针域,因此空间单元利用率不高,而且单链表操作的算法也较复杂

8、带头结点的单链表代码

link.h

  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #define FALSE 0
  6. #define TRUE 1
  7. typedef int Status; //返回状态
  8. typedef int DataType; //数据类型
  9. typedef struct Node
  10. {
  11. DataType data;
  12. struct Node *next;
  13. }Link;
  14. int LinkLength(Link *head); //获取链表长度
  15. void InitiaLink(Link **head); //初始化链表
  16. Status CleanLink(Link *head); //清空链表
  17. Status DestroyLink(Link *head); //销毁链表
  18. Status DeleteLinkElem(Link *head, int i); //删除链表元素
  19. Status GetLinkElem(Link *head, int i, DataType *elem); //获取链表元素
  20. Status LinkInsertElem(Link *head, int i, DataType elem); //在链表插入元素
  21. #endif // MAINWINDOW_H

link.c

  1. #include "link.h"
  2. //初始化链表
  3. void InitiaLink(Link **head)
  4. {
  5. *head = (Link *)malloc(sizeof(Link));
  6. (*head)->next = NULL;
  7. (*head)->data = 0;
  8. }
  9. //获取链表长度
  10. int LinkLength(Link *head)
  11. {
  12. int length = 0;
  13. Link *p = head;
  14. if (head == NULL)
  15. {
  16. return length;
  17. }
  18. while(p->next != NULL)
  19. {
  20. length++;
  21. p = p->next;
  22. }
  23. return length;
  24. }
  25. //插入元素
  26. Status LinkInsertElem(Link *head, int i, DataType elem)
  27. {
  28. int j = 0;
  29. Link *q = NULL;
  30. Link *p = head;
  31. if (i < 0)
  32. {
  33. printf("Error index!\n");
  34. return FALSE;
  35. }
  36. while (p->next != NULL && j < i - 1)
  37. {
  38. p = p->next;
  39. j++;
  40. }
  41. if(j != i - 1)
  42. {
  43. printf("元素位置参数错!\n");
  44. return FALSE;
  45. }
  46. q = (Link *)malloc(sizeof(Link));
  47. q->data = elem;
  48. q->next = p->next;
  49. p->next = q;
  50. return TRUE;
  51. }
  52. //获取元素
  53. Status GetLinkElem(Link *head, int i, DataType *elem)
  54. {
  55. int j = 0;
  56. Link *p = head;
  57. if (i > LinkLength(head) || i < 0)
  58. {
  59. printf("Error index!\n");
  60. return FALSE;
  61. }
  62. while (p->next != NULL && j < i)
  63. {
  64. p = p->next;
  65. j++;
  66. }
  67. if(j != i)
  68. {
  69. printf("取元素位置参数错误!\n");
  70. return FALSE;
  71. }
  72. *elem = p->data;
  73. return TRUE;
  74. }
  75. //删除元素
  76. Status DeleteLinkElem(Link *head, int i)
  77. {
  78. int j = 0;
  79. Link *p = head;
  80. Link *q = NULL;
  81. if (i > LinkLength(head) || i < 0)
  82. {
  83. printf("Error index!\n");
  84. return FALSE;
  85. }
  86. while (p->next != NULL && j < i - 1)
  87. {
  88. p = p->next;
  89. j++;
  90. }
  91. if(j != i - 1)
  92. {
  93. printf("位置参数错误!\n");
  94. return FALSE;
  95. }
  96. q = p->next;
  97. p->next = p->next->next;
  98. free(q);
  99. return TRUE;
  100. }
  101. //销毁链表
  102. Status DestroyLink(Link *head)
  103. {
  104. Link *q = NULL;
  105. Link *p = head;
  106. if (p == NULL)
  107. {
  108. printf("Link is empty!\n");
  109. return FALSE;
  110. }
  111. while (p != NULL)
  112. {
  113. q = p;
  114. p = p->next;
  115. free(q);
  116. }
  117. head = NULL;
  118. return TRUE;
  119. }
  120. //清空链表
  121. Status CleanLink(Link *head)
  122. {
  123. Link *q = NULL;
  124. Link *p = head;
  125. if (p->next == NULL)
  126. {
  127. printf("Link has been cleaned!\n");
  128. return FALSE;
  129. }
  130. while (p->next != NULL)
  131. {
  132. q = p->next;
  133. p->next = p->next->next;
  134. free(q);
  135. }
  136. return TRUE;
  137. }

main.c

  1. #include "link.h"
  2. int main()
  3. {
  4. int elem = 0;
  5. int length = 0;
  6. Link *head;
  7. InitiaLink(&head);
  8. printf("Insert data:\n");
  9. for (int i = 1; i <= 10; i++)
  10. {
  11. LinkInsertElem(head, i, i);
  12. }
  13. printf("Link data:\n");
  14. for (int i = 1; i <= LinkLength(head); i++)
  15. {
  16. GetLinkElem(head, i, &elem);
  17. printf("%d\n", elem);
  18. }
  19. length = LinkLength(head);
  20. printf("Link length:%d\n", length);
  21. printf("After delete data:\n");
  22. DeleteLinkElem(head, 4);
  23. for (int i = 1; i <= LinkLength(head); i++)
  24. {
  25. GetLinkElem(head, i, &elem);
  26. printf("%d\n", elem);
  27. }
  28. length = LinkLength(head);
  29. printf("Link length:%d\n", length);
  30. printf("Clean link:\n");
  31. CleanLink(head);
  32. length = LinkLength(head);
  33. printf("Link length:");
  34. printf("%d\n", length);
  35. printf("Destory link:\n");
  36. DestroyLink(head);
  37. printf("Link has been destoryed!\n");
  38. return 0;
  39. }

注:清空链表是保留头结点,删除其余的结点。销毁链表是将头结点也一并删除。

发表评论

表情:
评论列表 (有 0 条评论,596人围观)

还没有评论,来说两句吧...

相关阅读

    相关 线性存储

          今天小编给大家分享一下关于数据结构中线性表的链式存储结构,这里只放代码,在重要的代码后附上解释,但是不进行具体某一项操作的详细算法分析。希望大家都能将这部分知识学好