当前位置:   article > 正文

C语言—数据结构之链表结构体 增删改查 以及动态创建链表_c中结构体链表

c中结构体链表

                                              链表是个好东西。

链表是什么?

链表是一种数据结构,所谓的数据结构就是数据存放的思想。类似数组但又不是数组,比数组更加灵活好用,可以存放许多不同类型的数据。

链表的优势是?

例如 我们定义一个存放10个元素的整形数组  int arry[10] ,我们对数组的 ‘查’ 和 ’改‘ 很方便,但是对数组的 增加 和 删除 却很难。数组已经定死了10个元素。数组是连续的空间,此时想要在数组中增加其中一个元素或删除一个元素很难。另外数组只能存放指定类型的数据(例如 int数组只能存放int类型数据 ,char数组 只能存放char类型数据),不能同时存放多种类型、复杂的数据,不灵活不方便。

链表这个数据结构能够很好的解决以上这些问题。

链表与数组的区别

a、数组中数的类型必须相同;

b、数组中数在内存中必须是连续存储的,链表是不连续的地址空间

c、 链表可以在节点中定义多种数据类型,数组只能定义一种类型,数据类型单一

链表节点的定义

  1. struct Test //这是结构体 链表节点的
  2. {
  3. int x,y,z;
  4. float a,b,c;
  5. char i,j;
  6. int num [20];
  7. char arry[10] = {0}; //链表的成员变量,一个节点存放数据,
  8. //k可以根据自己的需求,在节点中定义多种数据类型;
  9. struct Test *next; //链表节点的连接,这是链表连接的关键,存放下一个节点的地址
  10. }; //存放下一个节点的地址可以访问下一个节点的数据

一、改查——链表节点 查找和修改 

代码如下

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. struct Test //结构体的成员变量
  4. {
  5. int data;
  6. struct Test *next;
  7. };
  8. void Test(struct Test *head) //遍历链表中所有的节点,打印出链表节点的值data
  9. {
  10. while(head != NULL){
  11. printf("%d ",head->data);
  12. head = head->next;
  13. }
  14. putchar('\n');
  15. }
  16. int cha(struct Test *head,int number) //查找链表中是否存在这个值
  17. {
  18. while(head != NULL){
  19. if(head->data == number){ //判断是否存在我们想要查找的这个值
  20. printf("find Test data = %d,number = %d \n",head->data,number);
  21. return 1; //查找成功打印提示信息,并返回return 1。
  22. }
  23. head = head->next;
  24. }
  25. return -1; //查找失败返回-1
  26. }
  27. int gai(struct Test *head,int number ,int data) //调用此函数,修改链表中的值
  28. {
  29. while(head != NULL){ //遍历链表
  30. if(head->data == number){ //判断链表节点是否存在这个值,存在就修改这个节点的值
  31. head->data = data;
  32. return 1; //修改成功返回1
  33. }
  34. head = head->next;
  35. }
  36. return 0; //修改失败返回0
  37. }
  38. int main()
  39. {
  40. struct Test *head = NULL;
  41. int number;
  42. int data;
  43. struct Test t1; //结构体链表节点的定义
  44. struct Test t2; //定义五个节点 t1、t2、t3、t4、t5
  45. struct Test t3;
  46. struct Test t4;
  47. struct Test t5;
  48. t1.data = 100; //给五个节点赋值和结构体链表节点的连接
  49. t1.next = &t2;
  50. t2.data = 200;
  51. t2.next = &t3;
  52. t3.data = 300;
  53. t3.next = &t4;
  54. t4.data = 400;
  55. t4.next = &t5;
  56. t5.data = 500;
  57. t5.next = NULL;
  58. head = &t1; //结构体链表的头节点赋值
  59. puts("please scanf number");
  60. scanf("%d",&number); //请输入需要查链表节点中的值,值存放在number变量
  61. if(cha(head,number) == -1){ //调用int cha(struct Test *,int)传入链表头结点
  62. puts("Not find number"); //head和需要查找的值number。如果查找失败打印提示
  63. Test(head); //打印链表中的所有的值,并且调用exit退出程序运行。
  64. exit(-1);
  65. }
  66. Test(head); //遍历打印链表所有的值
  67. puts("please enter amend data");
  68. scanf("%d",&data); //输入修改的新值data
  69. gai(head,number,data); //把找到链表节点中的值number,修改成新的值data
  70. Test(head);
  71. return 0;
  72. }
  73. ~
  74. ~
  75. ~

    运行结果:

  1. please scanf number //提示 输入需要查找的值
  2. 300 //输入 300
  3. find Test data = 300,number = 300 //成功查找到300这个值
  4. 100 200 300 400 500 //打印链表节点的数据,显示300 值的位置
  5. please enter amend data //提示 输入需要修的值
  6. 888 //输入888
  7. 100 200 888 400 500 //把链表节点300值成功修改成888 ,打印所有链表结果

二、删——链表节点的删除

代码如下

  1. #include<stdio.h>
  2. struct Test
  3. {
  4. int data;
  5. struct Test *next;
  6. };
  7. struct Test *delete(struct Test *head,int number) //delete删除节点函数
  8. {
  9. struct Test *p = head;
  10. if(head == NULL ){ //判断链表是否存在
  11. puts(" inexistence head == NULL");
  12. return NULL;
  13. }
  14. if(head->data == number){ //先判断链表第一个节点是否需要删除
  15. p = head->next; //如果需要删除,就把第一节点的下一个节点,作为新的第一节点
  16. return p; //返回新的头节点
  17. }
  18. while(head->next != NULL){ //遍历链表节点
  19. if(head->next->data == number){ //判断,如果当前这个节点的下一个节点的值是我
  20. //们需要删除的节点时
  21. head->next = head->next->next; // 把当前节点连接,改为下一个节点的一下一个节点
  22. return p; //删除成功返回头节点
  23. }
  24. head = head->next;
  25. }
  26. puts("not find"); //删除失败 打印提示信息
  27. return p; //删除失败 并返回头节点
  28. }
  29. void Test(struct Test *head) //遍历打印所有链表节点的值,
  30. {
  31. while(head != NULL){
  32. printf("%d ",head->data);
  33. head = head->next;
  34. }
  35. putchar('\n');
  36. }
  37. int main()
  38. {
  39. int number;
  40. struct Test *head = NULL;
  41. struct Test t1,t2,t3,t4,t5; //定义五个链表节点t1,t2,t3,t4,t5
  42. t1.data = 100; //给五个链表节点赋值和连接
  43. t1.next = &t2;
  44. t2.data = 200;
  45. t2.next = &t3;
  46. t3.data = 300;
  47. t3.next = &t4;
  48. t4.data = 400;
  49. t4.next = &t5;
  50. t5.data = 500;
  51. t5.next = NULL;
  52. head = &t1; //链表头节点 (第一个节点)
  53. Test(head); //遍历打印所有链表节点的值
  54. puts("please scanf number");
  55. scanf("%d",&number); //输入需要删除节点的值
  56. head = delete(head,number); //调用delete()函数查找链表节点需要删除的值,并删除节点
  57. Test(head); //遍历打印所有链表节点的值,查看删除链表结果
  58. return 0;
  59. }
  60. ~
  61. ~
  62. ~
  63. ~
  64. ~

运行结果:

  1. ./a.out //执行程序
  2. 100 200 300 400 500 //遍历打印链表所有节点的值
  3. please scanf number //提示输入需要删除节点的值
  4. 400 //输入400
  5. 100 200 300 500 //遍历打印链表所有节点的值,链表节点400被删除

三、增——链表节点的插入增加

有两种插入方式:1、节点后面插入 2、节点前面插入

1、节点后面插入

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. struct Test
  4. {
  5. int data;
  6. struct Test *next;
  7. };
  8. void Test(struct Test *head)
  9. {
  10. while(head != NULL){
  11. printf("%d ",head->data);
  12. head = head->next;
  13. }
  14. putchar('\n');
  15. }
  16. struct Test *weicha(struct Test *head,int number) //链表节点后面插入
  17. {
  18. struct Test *hp = head; //保留链表头节点(链表的第一节点)
  19. struct Test *p; //创建新的节点
  20. p = (struct Test *)malloc( sizeof(struct Test) ); //给新节点开辟空间
  21. puts("scanf *p data"); //给新节点赋值
  22. scanf("%d",&p->data);
  23. while(head != NULL){ //遍历链表所有节点
  24. if(head->data == number){ //判断此节点是的值,是不是我们要插入新节点的节点的值
  25. p->next = head->next; //节点的向后插入新的节点
  26. head->next = p;
  27. return hp; //插入成功,返回头节点
  28. }
  29. head = head->next;
  30. }
  31. puts("Not find number"); //插入失败打印提示信息
  32. return hp;
  33. }
  34. int main()
  35. {
  36. int number;
  37. struct Test *head = NULL;
  38. struct Test t1,t2,t3,t4,t5; //定义五个新节点,t1,t2,t3,t4,t5
  39. t1.data = 100; //五个链表节点的连接赋值
  40. t1.next = &t2;
  41. t2.data = 200;
  42. t2.next = &t3;
  43. t3.data = 300;
  44. t3.next = &t4;
  45. t4.data = 400;
  46. t4.next = &t5;
  47. t5.data = 500;
  48. t5.next = NULL;
  49. head = &t1; //链表的头节点(第一节点)
  50. Test(head); //遍历打印所有节点
  51. while(1){ //输入0退出循环,否者不断进行链表新节点的插入
  52. puts("please number");
  53. scanf("%d",&number); //输入你需要在那个节点后插入新的节点
  54. if(number == 0){ //输入0退出循环,否者不断进行链表新节点的插入
  55. break;
  56. }
  57. weicha(head,number); //调用函数,
  58. Test(head); //打印修改结果
  59. }
  60. Test(head);
  61. return 0;
  62. }
  63. ~
  64. ~
  65. ~
  66. ~
  67. ~
  68. ~
  69. ~
  70. ~
  71. ~
  72. ~
  73. ~
  74. ~
  75. ~

       运行结果:

  1. 100 200 300 400 500 //遍历打印链表节点所有的值
  2. please number //提示输入。 在哪个链表节点后面插入新的链表节点
  3. 100 //输入100。 选择在100链表节点后面插入新节点
  4. scanf *p data //提示输入。 请输入在链表100后插入多少的值
  5. 101 //输入101。 在100后面插入101的值
  6. 100 101 200 300 400 500 //打印链表节点的修改结果 100节点后面插入新的节点101 ,插入修改成功
  7. please number //以下步骤,同上
  8. 500
  9. scanf *p data
  10. 501
  11. 100 101 200 300 400 500 501
  12. please number //以下步骤,同上
  13. 300
  14. scanf *p data
  15. 301
  16. 100 101 200 300 301 400 500 501
  17. please number //以下步骤,同上
  18. 0 //输入0 结束向后插入新的节点操作
  19. 100 101 200 300 301 400 500 501 //遍历打印最终链表插入修改的结果

2、节点前面插入

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. struct Test
  4. {
  5. int data;
  6. struct Test *next;
  7. };
  8. void Test(struct Test *head)
  9. {
  10. while(head != NULL){
  11. printf("%d ",head->data);
  12. head = head->next;
  13. }
  14. putchar('\n');
  15. }
  16. struct Test *toucha(struct Test *head,int number) //向链表节点的前面插入新的节点
  17. {
  18. struct Test *head2 = head;
  19. struct Test *p; //创建新的链表节点
  20. p = (struct Test *)malloc( sizeof(struct Test) ); //为新节点开辟新的空间
  21. puts("scanf *p data");
  22. scanf("%d",&p->data); 输入新节点的data值
  23. if(head->data == number){ //首先判断是否选择在链表头节点(第一个节点)前面插入新节点
  24. p->next = head; //如果是,就把新的节点作为新头节点,连接上旧的头节点
  25. return p; //返回新的头节点
  26. }
  27. while(head->next != NULL){ //链表节点的遍历,从链表的第二个节点开始遍历,头节点前面已经判断过了
  28. if(head->next->data == number){ //判断当前链表节点的下一个链表节点是不是我想要向前插入的
  29. p->next = head->next;
  30. head->next = p;
  31. return head2;
  32. }
  33. head = head->next;
  34. }
  35. puts("Not find number"); //查找输出失败打印提示信息
  36. return head2;
  37. }
  38. int main()
  39. {
  40. int number;
  41. struct Test *head = NULL;
  42. struct Test t1,t2,t3,t4,t5; //链表节点的定义
  43. t1.data = 100; //链表节点的赋值和连接
  44. t1.next = &t2;
  45. t2.data = 200;
  46. t2.next = &t3;
  47. t3.data = 300;
  48. t3.next = &t4;
  49. t4.data = 400;
  50. t4.next = &t5;
  51. t5.data = 500;
  52. t5.next = NULL;
  53. head = &t1; // 链表的头节点
  54. Test(head); //遍历所有链表的节点,打印
  55. while(1){
  56. puts("please number"); //提示信息,输入你要向前插入节点的位置
  57. scanf("%d",&number);
  58. if(number == 0){ //输入为0,退出插入循环
  59. break;
  60. }
  61. head = toucha(head,number);
  62. Test(head); //插入一次打印一遍链表,查看插入结果
  63. }
  64. Test(head); //打印链表最终结果
  65. return 0;
  66. }
  67. ~
  68. ~
  69. ~
  70. ~
  71. ~
  72. ~
  73. ~
  74. ~
  75. ~
  76. ~

       运行结果:

  1. 100 200 300 400 500 //打印链表所有节点
  2. please number //提示输入,需要在那个节点前插入一个新的节点
  3. 500 //输入500 ,在节点链表500前插入
  4. scanf *p data //提示输入,在500前面插入的值为多少
  5. 499 //输入499 ,在500链表节点前插入新的节点 499
  6. 100 200 300 400 499 500 // 插入新链表节点成功,打印链表。在500 前插入499
  7. please number //以下步骤,同上
  8. 100
  9. scanf *p data
  10. 99
  11. 99 100 200 300 400 499 500
  12. please number //以下步骤,同上
  13. 300
  14. scanf *p data
  15. 299
  16. 99 100 200 299 300 400 499 500
  17. please number //输入为0退出循环,结束向前插入新的节点操作
  18. 0
  19. 99 100 200 299 300 400 499 500 //打印所有链表节点,最终结果。

四、动态创建链表节点

创建链表节点分为 1.尾插法  2.头插法

1.尾插法
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. struct Test
  4. {
  5. int data;
  6. struct Test *next;
  7. };
  8. void printLink(struct Test *head) //遍历打印所有链表节点
  9. {
  10. while(head != NULL){
  11. printf("%d ",head->data);
  12. head = head->next;
  13. }
  14. putchar('\n');
  15. }
  16. struct Test *endInsert(struct Test *head,struct Test *new) //尾插法,向后插入新的节点
  17. {
  18. struct Test *p = head;
  19. if(head == NULL){ //判断链表节点是否为空
  20. head = new; //如果是空的链表头节点,让头节点=新节点
  21. return head; //返回头节点地址
  22. }
  23. while(head->next != NULL){ //如果链表头节点不为空NULL
  24. head = head->next; //遍历链表节点,使指针 位移到链表的最后一个节点,
  25. }
  26. head->next = new; //最后一个节点,连接到下一个新节点的地址,
  27. return p; //返回头节点地址
  28. }
  29. struct Test *createLink(struct Test *head) //动态创建链表
  30. {
  31. struct Test *new = NULL; //链表新节点的定义
  32. while(1){
  33. new =(struct Test *)malloc(sizeof(struct Test) ); //给链表新节点开辟新空间
  34. new->next = NULL;
  35. puts("createLink new data"); //给链表新节点data赋值
  36. scanf("%d", &(new->data) );
  37. if(new->data == 0){ //data输入为0时,停止链表节点的创建退出
  38. free(new); //清除不需要的新节点空间,堆
  39. puts("Quit"); //打印退出提示信息
  40. return head; //返回链表头节点地址
  41. }
  42. head = endInsert(head,new); //每创建一次新的链表节点,就调用endInsert()函数
  43. //让新的节点插入链表最后一位节点
  44. }
  45. return head;
  46. }
  47. int main()
  48. {
  49. int number;
  50. struct Test *head = NULL;
  51. head = createLink(head); //不断动态创建链表,并且吧创建新的的链表节点插在链表的最后一位
  52. struct Test t1 = {888,NULL}; //单独创建一个新的节点
  53. head = endInsert(head,&t1); //创建一个新节点t1,放在链表最后一位,单独调用endInsert函数
  54. printLink(head); //打印所有链表节点,看最终结果
  55. return 0;
  56. }

运行结果:

  1. createLink new data //提示输入 ,创建的节点,为新的节点赋值值
  2. 1 //输入1,节点的值为1
  3. createLink new data //创建第二个节点
  4. 2
  5. createLink new data //创建第三个节点
  6. 3
  7. createLink new data //创建第四个节点
  8. 4
  9. createLink new data //创建第五个节点
  10. 5
  11. createLink new data //输入为0,取消节点的创建
  12. 0
  13. Quit //退出创建
  14. 1 2 3 4 5 888 //打印链表节点的结果
  15. //为何最后一个节点是888,因为单独创建一个新节点 struct Test t1
2.头插法
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. struct Test
  4. {
  5. int data;
  6. struct Test *next;
  7. };
  8. void printLink(struct Test *head)
  9. {
  10. while(head != NULL){
  11. printf("%d ",head->data);
  12. head = head->next;
  13. }
  14. putchar('\n');
  15. }
  16. struct Test *headInsert(struct Test *head,struct Test *new) //链表节点的头插法,向链表头节点插入一个新的节点
  17. {
  18. if(head == NULL){ //判断头节点是否为空指针NULL
  19. head = new; //是,就让新节点作为头节点
  20. return head; //返回头节点
  21. }else{
  22. new->next = head; //如果头节点不为空,就让新的节点连接下一个旧的链表头节点
  23. head = new; //(吧旧的头节点作为第二个节点,新的节点作为第一个节点(头节点))
  24. }
  25. return head;
  26. }
  27. struct Test *createLink(struct Test *head)//不断动态创建新的节点,并且吧新节点,作为新的头节点
  28. {
  29. struct Test *new = NULL; //新节点的定义
  30. while(1){
  31. new =(struct Test *)malloc(sizeof(struct Test) ); //为新节点开辟新空间
  32. new->next = NULL;
  33. puts("createLink new data"); //为新节点赋值
  34. scanf("%d", &(new->data) );
  35. if(new->data == 0){ //当不需要创建新节点的时候,输入0,退出创建节点
  36. free(new);
  37. puts("Quit"); //打印提示信息
  38. return head; //返回链表头节点
  39. }
  40. head = headInsert(head,new); //每创建一次新的节点,就把新的节点,作为新的链表头节点(头插法)
  41. }
  42. return head;
  43. }
  44. int main()
  45. {
  46. int number;
  47. struct Test *head = NULL;
  48. head = createLink(head); //调用createLink()函数不断创建新节点,并且吧新的节点作为新的头节点(头插法)
  49. printLink(head); //打印链表节点结果
  50. struct Test t1 = {888,NULL}; //单独创建新的节点
  51. head = headInsert(head,&t1); //单独调用headInsert()函数(头插法), 吧t1插入头节点
  52. printLink(head); //打印最终链表结果
  53. return 0;
  54. }

运行结果:

  1. ./a.out //运行程序
  2. createLink new data //动态创建新节点,并把新的节点作为头节点(头插法)
  3. 1 //输入1,输入新节点的值为1
  4. createLink new data //以下步骤,同上
  5. 2
  6. createLink new data //以下步骤,同上
  7. 3
  8. createLink new data //以下步骤,同上
  9. 4
  10. createLink new data //以下步骤,同上
  11. 5
  12. createLink new data //输入为0 ,停止创建链表新节点,退出
  13. 0
  14. Quit //打印退出提示信息
  15. 5 4 3 2 1 //打印用头插法动态创建链表节点的结果
  16. 888 5 4 3 2 1 //在单独调用endInsert()函数插入一个新节点888

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

闽ICP备14008679号