当前位置:   article > 正文

C语言中的链表_链表c语言

链表c语言

目录

一、链表概述

二、链表操作

1、动态创建链表

(1)malloc函数

(2)calloc函数

(3)free函数

2、链表的插入操作

3、链表的删除操作补充内容

三、链表完整代码实现


一、链表概述

        链表是一种常见的数据结构,在链表中可以动态的进行内存分配。也可以将链表看成是一个功能强大的数组,它可以在节点中定义多种数据类型,还可以根据需要随意增加,删除,或者插入节点。

        每个链表都有一个头指针,一般以head来表示,存放的是一个地址。链表中的节点分为两类,头结点和一般节点,头结点是没有数据域的。链表中每个节点都分为两部分,一个数据域,一个是指针域。

        简单来说,链表就如同车链子一样,head指向第一个元素:第一个元素又指向第二个元素;……,直到最后一个元素,最后的一个元素不再指向其它元素,它称为“表尾”,它的地址部分放一个“NULL”(表示“空地址”),链表到此结束。

        本文仅对单链表进行介绍。

 

二、链表操作

1、动态创建链表

        链表的创建的是一个动态的过程,动态创建一个节点时,要为其分配内存,相关函数介绍如下:

(1)malloc函数

        函数功能:在内存中动态地分配一块size大小的内存空间。malloc函数会返回一个指针,该指针指向分配的内存空间,如果出现错误则返回NULL。

        malloc函数原型如下:

void *malloc(unsigned int size);

(2)calloc函数

        函数功能:在内存中动态分配n个长度为size的连续内存空间数组。calloc函数会返回一个指针,该指针指向动态分配的连续内存空间地址。当分配空间错误时,返回NULL。

        calloc函数原型如下:

void *calloc(unsigned n, unsigned size);

(3)free函数

        函数功能:使用由指针ptr指向的内存区,使部分内存区能被其他变量使用。ptr是最近一次调用calloc或malloc函数时返回的值。free函数无返回值。(释放内存空间)

        函数原型如下:

void free(void *ptr);

2、链表的插入操作

        链表的插入操作可以在链表的头节点位置进行,也可以在中间节点或者尾结点进行。三种链表的插入操作思路是一样的。

  1. // 链表的插入操作(在链表的头结点插入)
  2. // 该函数将会返回链表的头指针
  3. struct Student *Insert(struct Student *pHead)
  4. {
  5. struct Student *pNew; // 指向新分配的空间
  6. printf("-------Insert member at first------\n"); // 提示信息
  7. pNew = (struct Student*)malloc(sizeof(struct Student)); // 分配内存空间,并返回指向该内存空间的指针
  8. scanf("%s",&pNew->cName); // 输入新加入的学生姓名
  9. scanf("%d",&pNew->iNumber); // 输入新加入的学生学号
  10. // 两步操作:1.将原来的头节点地址给到新节点指向的下一级节点;2.将新节点的地址给到头节点。
  11. pNew->pNext = pHead; // 新节点指针指向原来的首节点(将原来的头结点地址给到新加入的节点指向的地址)
  12. pHead = pNew; // 链表头指针指向新节点(新节点变成了头节点)
  13. iCount++; // 增加链表的节点数
  14. return pHead; // 返回链表头指针
  15. }

3、链表的删除操作补充内容

        链表删除过程中,可以对待删除的链表序号进行判断

(1)在对头结点进行赋值过程中,可以先对链表的头结点进行判断,判断当前链表头节点是否为空, 非空情况下再进行后续的头结点赋值操作;

  1. if (pHead == NULL) // 首先判断链表头是否为空,即整个链表是否为空表
  2. { // 若是空表,则输出空
  3. printf("\n---The List NULL!---\n");
  4. return pHead;
  5. }
  6. pTemp = pHead; // pHead赋值给pTemp,得到链表的头结点

(2)在执行循环判断语句过程中,可以先判断待删除的节点下标序号是否为pTemp指向的节点;

  1. while ((iIndex != pTemp->iIndex) && (pTemp->pNext != NULL)) // 当要删除的iIndex不等于pTemp所指向的节点下标且满足pTemp的下一个结点不为空
  2. {
  3. pPre = pTemp; // 将pTemp赋给pPre;
  4. pTemp = pTemp->pNext; // 再将pTemp指向下一个节点;重复进行,直到找到待删除的节点序号,此时pTemp指向的节点就是所要找的待删除节点
  5. }

(3)在进行节点删除过程中,可以先判断待删除的节点是否为第一个节点;

  1. if (iIndex == pTemp->iIndex)
  2. {
  3. // 除非链表中不存在要寻找的iIndex,否则这个条件是一定成立的,
  4. if(pTemp == pHead)
  5. { // 如果要删除的是第1个节点
  6. pHead = pTemp->pNext; // 则让pHead指向pTemp的下一个节点,也就是第二个节点
  7. }
  8. else
  9. {
  10. pPre->pNext = pTemp->pNext; // 如果要删除的不是第一个节点,则让pPre的next指向pTemp(要删除的结点)的下一个结点,此时则跳过了这个iIndex,即达到删除的效果
  11. }
  12. printf("Delete: %d\n", iIndex);
  13. iCount = iCount - 1;
  14. }

三、链表完整代码实现

        本节详细链表操作见代码实现,包括链表的动态创建,插入、删除和输出操作。

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. // 创建链表节点结构,表示每一个学生
  4. struct Student
  5. {
  6. char cName[20]; // 学生姓名
  7. int iNumber; // 学号
  8. struct Student *pNext; // 指向下一个节点的指针
  9. };
  10. int iCount; // 全局变量表示链表长度
  11. // Create函数的功能是创建链表,动态分配内存空间的方式创建链表
  12. // 该函数将会返回链表的头指针
  13. //(在链表的尾结点插入)
  14. struct Student *Create()
  15. {
  16. struct Student *pHead = NULL; // 初始换链表头指针为空
  17. struct Student *pNew, *pEnd; // pEnd用来指向原来的尾节点,pNew用来指向新创建的节点
  18. iCount = 0; // 表示链表中节点的数量
  19. pEnd = pNew = (struct Student*)malloc(sizeof(struct Student)); // malloc 函数分配内存,先用pEnd和pNew两个指针都指向第一个分配的内存
  20. printf("------Please First Enter Name, The Number------\n");
  21. scanf("%s",&pNew->cName);
  22. scanf("%d",&pNew->iNumber);
  23. while(pNew->iNumber != 0)
  24. {
  25. iCount++;
  26. // 第一次加入节点,新节点即为首节点,也是最后一个节点,并且需要将新加入的节点的指针指向NULL,即为pHead指向。
  27. if(iCount == 1)
  28. {
  29. pNew->pNext = pHead; // 使得指针指向为空(新加入的节点为首节点的时候,节点空指针即为pHead指向
  30. pEnd = pNew; // 跟踪新加入的节点(新加入的节点地址即为尾结点地址)
  31. pHead = pNew; // 头指针指向首节点(将新加入的节点的地址给头指针)
  32. }
  33. else
  34. {
  35. pNew->pNext = NULL; // 新节点的指针为空(将新加入的节点指针指向空)
  36. pEnd->pNext = pNew; // 原来的尾结点指向新节点(原来的尾结点变成了中间节点,需要将新节点地址给原来的尾结点)
  37. pEnd = pNew; // pEnd指向新节点(让新加入的节点成为尾结点)
  38. }
  39. pNew = (struct Student*)malloc(sizeof(struct Student)); // 再次分配节点内存空间
  40. scanf("%s",&pNew->cName); // 再次输入新的节点进入循环判断,如果满足新节点要求则执行循环继续添加,如果不满足则跳出循环
  41. scanf("%d",&pNew->iNumber);
  42. }
  43. free(pNew); // 不满足新节点要求,跳出循环后调用free函数释放未使用的内存空间
  44. return pHead; // 该函数返回链表的头指针
  45. }
  46. // 定义打印函数Print
  47. // void 函数没有返回值
  48. void Print(struct Student *pHead)
  49. {
  50. struct Student *pTemp; // 循环所用的临时指针
  51. int iIndex = 1; // 表示链表中节点的序号
  52. printf("======The List Has %d Members:======\n",iCount);
  53. printf("\n");
  54. pTemp = pHead; // 指针得到首节点的地址
  55. while(pTemp != NULL)
  56. {
  57. printf("The NO%d Member is:\n",iIndex);
  58. printf("The Name is %s\n",pTemp->cName); // 输出姓名
  59. printf("The Number is %d\n",pTemp->iNumber); // 输出学号
  60. printf("\n");
  61. pTemp = pTemp->pNext; // 移动临时指针到下一个节点
  62. iIndex++; // 进行自加运算
  63. }
  64. }
  65. // 链表的插入操作(在链表的头结点插入)
  66. // 该函数将会返回链表的头指针
  67. struct Student *Insert(struct Student *pHead)
  68. {
  69. struct Student *pNew; // 指向新分配的空间
  70. printf("-------Insert member at first------\n"); // 提示信息
  71. pNew = (struct Student*)malloc(sizeof(struct Student)); // 分配内存空间,并返回指向该内存空间的指针
  72. scanf("%s",&pNew->cName); // 输入新加入的学生姓名
  73. scanf("%d",&pNew->iNumber); // 输入新加入的学生学号
  74. // 两步操作:1.将原来的头节点地址给到新节点指向的下一级节点;2.将新节点的地址给到头节点。
  75. pNew->pNext = pHead; // 新节点指针指向原来的首节点(将原来的头结点地址给到新加入的节点指向的地址)
  76. pHead = pNew; // 链表头指针指向新节点(新节点变成了头节点)
  77. iCount++; // 增加链表的节点数
  78. return pHead; // 返回链表头指针
  79. }
  80. // 删除链表节点
  81. // 输入:链表头结点pHead,要删除的节点下标iIndex;dd
  82. void Delete(struct Student *pHead, int iIndex)
  83. {
  84. int i; // 控制循环变量
  85. struct Student *pTemp; // 临时指针变量,表示要删除的节点
  86. struct Student *pPre; // 表示要删除节点之前 的节点
  87. pTemp = pHead; // pHead赋值给pTemp,得到链表的头结点
  88. pPre = pTemp; // pPre指向pTemp,将pTemp的地址给到pPre
  89. printf("======Delete NO%d member======\n",iIndex); // 提示待删除节点位置信息
  90. // for语句进行循环操作,使得pTemp指向要删除的节点
  91. for(i=1; 1<iIndex; i++)
  92. {
  93. // 将pTemp赋值给pPre,再将pTemp指向下一个节点,重复进行,直到找到需要定位的iIndex节点,此时pTemp指向的节点就是所要找的待删除的节点
  94. pPre = pTemp; // 定位到要删除的节点pTemp
  95. pTemp = pTemp->pNext; // 再将pTemp指向下一个节点
  96. }
  97. pPre->pNext = pTemp->pNext; // 连接待删除节点两边的节点地址(将待删除节点两边的地址相关联)(重点!!!)
  98. free(pTemp); // 释放掉要删除节点的内存空间
  99. iCount--; // 减少链表中元素的个数
  100. }
  101. // 定义主函数
  102. int main()
  103. {
  104. struct Student *pHead; // 定义头结点
  105. pHead = Create(); // 创建链表节点
  106. pHead = Insert(pHead); // 插入新的节点
  107. Delete(pHead,2); // 删除链表中第二个节点的操作
  108. Print(pHead); // 输出最终的链表
  109. return 0;
  110. }

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

闽ICP备14008679号