当前位置:   article > 正文

C语言之单向链表_单向链表的free

单向链表的free

一、链表

链表是一种常见的数据结构,它可以动态的进行存储分配,根据需要开辟内存单元与释放内存单元,链表中的元素通常由两部份组成:数据域和指针域。

数据域用于存储数据,指针域用于节点的连接。

链表结构如下图所示:链表第一个节点是头指针,每个节点都都包含这数据域与指针域,每个节点与其下一个节点都是通过指针域进行相连的,且最后一个节点的指针域指向NULL。

二、单向链表基本操作

首先我们看看链表元素的数据结构:

  1. typedef struct _Link_t
  2. {
  3. int data; //数据域的数据
  4. struct _Link_t *next; //指向下一个节点的指针,指针域
  5. } LINK_T;

成员data为链表存储的数据,成员next为指向下一个节点的指针。

在这里我们注意到一个点,链表结构中包含指针类型的结构成员,类型为指向相同类型的指针。根据C语言的语法要求,结构体的成员不能是结构体自身类型,即结构体不能自己定义自己,因为这样将会导致一个无穷的递归定义,但结构体成员可以是结构体自身的指针类型,通过指针引用自身这种类型的结构。

2.1创建节点

  1. //data数据域存储的数据
  2. LINK_T *Create_Node(int data)
  3. {
  4. LINK_T *node;
  5. node = (LINK_T*)malloc(sizeof(LINK_T));
  6. if (node == NULL)
  7. {
  8. return -1;
  9. }
  10. memset(node, 0, sizeof(LINK_T));
  11. node->next = NULL;
  12. node->data = data;
  13. return node;
  14. }

需要注意的是,利用malloc申请内存后,系统并不会对内存块自动进行初始化和置零操作,需要我们自己对内存进行置0。

2.2链表插入

从链表头插入:

根据图示,我们很容易分析出,每次有新的节点在链表头插入时,新节点的next将会指向原来head->next所指向的的节点,head->next将会指向新的节点。代码如下图所示

  1. //head头指针
  2. //node需要插入的节点
  3. void Insert_Top(LINK_T *head, LINK_T *node)
  4. {
  5. LINK_T *p = head;
  6. node->next = p->next;
  7. p->next = node;
  8. }

链表尾部插入:

根据图示,我们很容易分析出,每次有新的节点在链表尾部插入时,原来链表最后一个节点的指针域将会指向新节点,新插入节点的指针域将会指向NULL。代码如下:

  1. void Insert_Tail(LINK_T *head, LINK_T *node)
  2. {
  3. LINK_T *p = head;
  4. while((p->next != NULL) && (p = p->next)); //找到链表最后一个节点
  5. p->next = node;
  6. }

由于链表的结构决定了每个节点只能找到其下一个节点,所以在对链表节点查询时,只能使用轮询的方式一个一个查询。

 

2.3节点的删除

根据图示,我们很容易分析出,每次删除节点后,被删除节点的上一个节点将会指向被删除节点的下一个节点。需要注意的是,我们需要使用轮询的方式找到需要删除的节点,代码如下:

  1. //head 头指针
  2. //num 需要删除的节点号
  3. void Delete_Node(LINK_T *head, int num)
  4. {
  5. int i = 0;
  6. LINK_T *p = head;
  7. LINK_T *t;
  8. while((i++ < (num - 1)) && (p = p->next));//找到需要删除节点的上一个节点
  9. t = p->next; //需要删除的节点
  10. p->next = p->next->next; //将节点从链表中释放出来
  11. free(t); //释放被删除节点的内存块
  12. }

2.4链表的遍历

该部分直接看程序分析,链表需要注意的点在于需要提供头指针,且最后一个节点的指针域指向NULL,以及遍历的时候只能挨个轮询。

  1. void Traverse_P(LINK_T *head)
  2. {
  3. LINK_T *p = head;
  4. do
  5. {
  6. printf("%d ", p->data);
  7. }
  8. while((NULL != p->next) && (p = p->next));
  9. printf("\n");
  10. }

三、基本例程

例程功能实现,先将数组data的数据按序存到每个节点中,然后遍历并且打印,再删除第5个节点,然后再变量打印一次链表以验证各调用函数的正确性。

在该程序中,头指针的数据域的数据代表链表的节点数。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. typedef struct _Link_t
  5. {
  6. int data;
  7. struct _Link_t *next;
  8. } LINK_T;
  9. LINK_T *Create_Node(int data); //创建节点
  10. void Insert_Tail(LINK_T *head, LINK_T *node);//尾插入节点
  11. void Insert_Top(LINK_T *head, LINK_T *node); //头插入节点
  12. void Traverse_P(LINK_T *head); //正序遍历
  13. void Delete_Node(LINK_T *head, int num); //删除节点
  14. int main(int argc, const char *argv[])
  15. {
  16. int i = 0;
  17. int data[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  18. LINK_T *head; //创建头指针
  19. head = (LINK_T*)malloc(sizeof(LINK_T));
  20. memset(head, 0, sizeof(LINK_T));
  21. for (i = 0; i < 10; i++) //创建节点并插入链表
  22. {
  23. Insert_Tail(head, Create_Node(data[i]));
  24. head->data++;
  25. }
  26. Traverse_P(head); //遍历并打印链表
  27. Delete_Node(head, 5); //删除第5个节点
  28. Traverse_P(head); //遍历并打印链表
  29. return 0;
  30. }
  31. //data 节点数据域存储的数据
  32. LINK_T *Create_Node(int data)
  33. {
  34. LINK_T *node;
  35. node = (LINK_T*)malloc(sizeof(LINK_T));
  36. memset(node, 0, sizeof(LINK_T));
  37. node->next = NULL;
  38. node->data = data;
  39. return node;
  40. }
  41. //head 链表头指针
  42. //node 需要插入的节点
  43. void Insert_Tail(LINK_T *head, LINK_T *node)
  44. {
  45. LINK_T *p = head;
  46. while((p->next != NULL) && (p = p->next));
  47. p->next = node;
  48. }
  49. //head 链表头指针
  50. //node 需要插入的节点
  51. void Insert_Top(LINK_T *head, LINK_T *node)
  52. {
  53. LINK_T *p = head;
  54. node->next = p->next;
  55. p->next = node;
  56. }
  57. //head 链表头指针
  58. void Traverse_P(LINK_T *head)
  59. {
  60. LINK_T *p = head;
  61. do
  62. {
  63. printf("%d ", p->data);
  64. }
  65. while((NULL != p->next) && (p = p->next));
  66. printf("\n");
  67. }
  68. //head 头指针
  69. //num 需要删除的节点号
  70. void Delete_Node(LINK_T *head, int num)
  71. {
  72. int i = 0;
  73. LINK_T *p = head;
  74. LINK_T *t;
  75. while((i++ < (num - 1)) && (p = p->next));//找到需要删除节点的上一个节点
  76. t = p->next; //需要删除的节点
  77. p->next = p->next->next; //将节点从链表中释放出来
  78. head->data--; //节点数减一
  79. free(t); //释放被删除节点的内存块
  80. }

程序运行结果为:

  1. 10 1 2 3 4 5 6 7 8 9 10
  2. 9 1 2 3 4 6 7 8 9 10

结果和程序所需实现功能相匹配,头指针数据域代表节点数,程序先创建10个节点,并且数据域的数据按照data数组依次赋值,遍历并打印链表,删除第5个节点,然后再遍历并打印链表。

 

仓促成文,不当之处,尚祈方家和读者批评指正。联系邮箱1772348223@qq.com

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

闽ICP备14008679号