当前位置:   article > 正文

C语言——单向链表_c语言经典单向链表库

c语言经典单向链表库

        链表的概念:链表是一种动态存储分布的数据结构,由若干个同一结构类型的结点依次串连而成。

        链表分为单向链表和双向链表。

        链表变量一般用指针head表示,用来存放链表首结点的地址

        每个结点由数据部分下一个结点的地址部分组成,即每个结点都指向下一个结点。最后一个结点称为表尾,其下一个结点的地址部分的值为NULL(表示为空地址)。

        特别注意:链表中的各个结点在内存中是可以不连续存放的,具体存放位置由系统分配。

例如:int *ptr ; 

        因此不可以用ptr++的方式来寻找下一个结点。

        使用链表的优点:

        不需要事先定义存储空间大小,可以实时动态分配,内存利用效率高;

        可以很方便地插入新元素(结点) ,使链表保持排序状态,操作效率高。

下面用课本的例子来讲解:

  1. /*用链表实现学生成绩信息的管理*/
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<string.h>
  5. struct stud_node{
  6. int num;
  7. char name[24];
  8. int score;
  9. struct stud_node *next;
  10. };
  11. struct stud_node *Create_Stu_Doc(); /*新建链表*/
  12. struct stud_node *InsertDoc(struct stud_node *head,struct stud_node *stud); /*插入*/
  13. struct stud_node *DeleteDoc(struct stud_node *head,int num); /*删除*/
  14. void Print_Stu_Doc(struct stud_node *head); /*遍历*/
  15. int main(void)
  16. {
  17. struct stud_node *head,*p;
  18. int choice,num,score;
  19. char name[20];
  20. int size = sizeof(struct stud_node);
  21. do{
  22. printf("1:Create\n 2:Insert\n 3: Delete\n 4:Print\n 0:Exit\n");
  23. scanf("%d",&choice);
  24. switch(choice){
  25. case 1:
  26. head = Create_Stu_Doc();
  27. break;
  28. case 2:
  29. printf("Input num,name and score:\n");
  30. scanf("%d %s %d",&num,name,&score);
  31. p = (struct stud_node *)malloc(size);
  32. p->num = num;
  33. strcpy(p->name,name);
  34. p->score = score;
  35. head = InsertDoc(head,p);
  36. break;
  37. case 3:
  38. printf("Input num:\n");
  39. scanf("%d",&num);
  40. head = DeleteDoc(head,num);
  41. break;
  42. case 4:
  43. Print_Stu_Doc(head);
  44. break;
  45. case 0:
  46. break;
  47. }
  48. }
  49. while(choice != 0);
  50. return 0;
  51. }
  52. /*新建链表*/
  53. struct stud_node *Create_Stu_Doc(){
  54. struct stud_node *head,*p;
  55. int num,score;
  56. char name[20];
  57. int size = sizeof(struct stud_node);
  58. head = NULL;
  59. printf("Input num,name and score:\n");
  60. scanf("%d %s %d",&num,name,&score);
  61. while(num != 0){
  62. p=(struct stud_node *)malloc(size);
  63. p->num = num;
  64. strcpy(p->name,name);
  65. p->score = score;
  66. head = InsertDoc(head,p); /*调用插入函数*/
  67. scanf("%d %s %d",&num,name,&score);
  68. }
  69. return head;
  70. }
  71. /*插入操作*/
  72. struct stud_node *InsertDoc(struct stud_node *head,struct stud_node *stud){
  73. struct stud_node *ptr,*ptr1,*ptr2;
  74. ptr2 = head;
  75. ptr = stud; /*ptr指向待插入的新的学生记录结点*/
  76. /*原链表为空链表时的插入*/
  77. if(head == NULL){
  78. head = ptr;
  79. head->next = NULL;
  80. }else{
  81. while((ptr->num > ptr2->num)&&(ptr2->next != NULL)){
  82. ptr1 = ptr2;
  83. ptr2 = ptr2->next; /*ptr1,ptr2各往后移一个结点*/
  84. }
  85. if(ptr->num <= ptr2->num){ /*在ptr1与ptr2之间插入新结点*/
  86. if(head == ptr2){
  87. head=ptr;
  88. }
  89. else{
  90. ptr1->next = ptr;
  91. ptr->next = ptr2;
  92. }
  93. }
  94. else{
  95. ptr2->next = ptr; /*新插入结点成为尾结点*/
  96. ptr->next =NULL;
  97. }
  98. }
  99. return head;
  100. }
  101. /*删除操作*/
  102. struct stud_node *DeleteDoc(struct stud_node *head,int num){
  103. struct stud_node *ptr1,*ptr2;
  104. /*要被删除结点为表头结点*/
  105. while(head != NULL && head->num==num){
  106. ptr2=head;
  107. head=head->next;
  108. free(ptr2);
  109. }
  110. if(head==NULL){
  111. return NULL;
  112. } /*链表为空*/
  113. /*要被删除结点为非表头结点*/
  114. ptr1=head;
  115. ptr2=head->next; /*从表头的下一个结点搜索所有符合删除要求的结点*/
  116. while(ptr2 != NULL){
  117. if(ptr2->num == num)/*ptr2所指结点符合删除要求*/{
  118. ptr1->next=ptr2->next;
  119. free(ptr2);
  120. }
  121. else{
  122. ptr1 = ptr2; /*ptr1后移一个结点*/
  123. ptr2 = ptr1->next; /*ptr2指向ptr1的后一个结点*/
  124. }
  125. }
  126. return head;
  127. }
  128. /*遍历操作*/
  129. void Print_Stu_Doc(struct stud_node *head){
  130. struct stud_node *ptr;
  131. if(head==NULL){
  132. printf("\nNo Records\n");
  133. return;
  134. }
  135. printf("\nThe Students'Records Are:\n");
  136. printf("Num\t Name\t Score\t");
  137. for(ptr=head;ptr!=NULL;ptr=ptr->next){
  138. printf("%d\t%s\t%d\n",ptr->num,ptr->name,ptr->score);
  139. }
  140. }

       申请大小为 struct stud_node 结构的动态内存空间,新申请到的空间要被强制类型转换成

struct stud_node 型的指针,并保存到指针变量p中,如下:

        struct stud_node*p;

        p = ( struct stud_node *)malloc(sizeof( struct stud_node ));

链表的建立:

       上面程序中链表结点是按照学生学号排序的,若向根据数据输入的顺序来建立链表,如下:

  1. /*按输入顺序建立单向链表*/
  2. struct stud_node *Create_Stu_Doc(){
  3. int num,score;
  4. char name[20];
  5. int size = sizeof(struct stud_node);
  6. struct stud_node *head,*tail,*p;
  7. head=tail=NULL;
  8. printf("Input num,name and score:\n");
  9. scanf("%d %s %d",&num,name,&score);
  10. while(num!=0){
  11. p=(struct stud_node *)malloc(size);
  12. p->num = num;
  13. strcpy(p->name,name);
  14. p->score = score;
  15. p->next = NULL;
  16. if(head == NULL){
  17. head = p;
  18. }else{
  19. tail->next=p; /*把原来链表的尾结点的next域指向该新增的结点*/
  20. tail=p;
  21. }
  22. scanf("%d %s %d",&num,name,&score);
  23. }
  24. return head;
  25. }

       由于按数据输入建立链表时,新增加的结点会加在链表末尾,所以该新增结点的 next 域应置成 NULL :   p->next = NULL.

链表的遍历:

       为了逐个显示链表每个结点的数据,程序要不断从链表中读取结点内容,显然需要用到循环。

在for语句中将ptr的初值置为表头head,当ptr不为NULL时循环继续,否则循环结束。不可以用ptr++来寻找下一个结点。

链表的插入:

       插入原则:先连后断。

       首先找到正确位置,然后插入新的结点。寻找正确位置是一个循环的过程:从链表head开始,把要插入的结点stud的num分量值与链表中结点的num分量值逐一比较,直到出现要插入结点的值比第 i 结点的num分量值大,比第 i+1结点的分量值小。所以先与第 i+1 结点相连。再将 i 结点 与 i+1结点断开,并让 i 结点与 stud 结点相连。

链表的删除:

       删除原则:先接后删。

       若被删除结点是表头则 head=head->next ; 

       其他内容省略。

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

闽ICP备14008679号