• 单链表的基本操作(C语言+图解分析)


    目录

    一、单链表的建立

    1、头插法

    2、尾插法

    二、插入结点操作

    三、删除节点操作

    四、单链表操作的一些常见问题

    1、结构体变量和结构体指针的区别?

    2、什么时候要malloc?

    3、形参里面出现了取地址符(&),有什么作用?


            学习并理解单链表,最好先去熟练掌握下C语言的指针,再跟着书本或视频进行练习。本篇文章所有代码都可以运行,读者可以自行调试。数据结构是抽象的,所以最好是看图解教程,才能更清楚的掌握数据结构。当基础知识掌握后,应进行大量练习,去刷题网站练习相关题目。

    一、单链表的建立

    1、头插法

    1. #include
    2. #include //malloc需要
    3. typedef struct List{
    4. int data;
    5. struct List* next;
    6. }LinkList;
    7. int main() {
    8. printf("输入要建立的链表,输入-1停止:\n");
    9. LinkList* head, *node;
    10. int x;
    11. scanf("%d", &x);
    12. head = (LinkList*)malloc(sizeof(LinkList));
    13. head->next = NULL;
    14. while (x != -1) {
    15. node = (LinkList*)malloc(sizeof(LinkList));
    16. node->data = x;
    17. node->next = head->next;
    18. head->next = node;
    19. scanf("%d", &x);
    20. }
    21. printf("头插法建立链表后从头往后输出:\n");
    22. LinkList* p = head->next;
    23. while (p != NULL) {
    24. printf("%d ", p->data);
    25. p = p->next;
    26. }
    27. return 0;
    28. }

    输出结果:

     

     

     让我们来从上到下看一下上述代码的执行效果:

    1、LinkList* head, *node;     

     

    2、head = (LinkList*)malloc(sizeof(LinkList)); head->next = NULL; //新建一个结点作为头结点,让头指针指向它

     

     

    3、node = (LinkList*)malloc(sizeof(LinkList));        //为要插入的结点开辟空间


    4、node->next = head->next;        

     


    5、 head->next = node;

     

     6、整理一下(注意这里head->next指向的是整个node结点而非指向node的next域):

     7、执行第二次循环,node = (LinkList*)malloc(sizeof(LinkList));


    8、node->next = head->next;


    9、 head->next = node;

     10、然后进入下一次循环······

    2、尾插法

    1. #include
    2. #include
    3. typedef struct List{
    4. int data;
    5. struct List* next;
    6. }LinkList;
    7. int main() {
    8. printf("输入要建立的链表,输入-1停止:\n");
    9. LinkList* head, *rear, *node;
    10. int x;
    11. head = (LinkList*)malloc(sizeof(LinkList));
    12. head->next = NULL;
    13. rear = head;
    14. scanf("%d", &x);
    15. while (x != -1) {
    16. node = (LinkList*)malloc(sizeof(LinkList));
    17. node->data = x;
    18. rear->next = node;
    19. rear = node;
    20. scanf("%d", &x);
    21. }
    22. rear->next = NULL;
    23. printf("尾插法建立链表后从头往后输出:\n");
    24. LinkList* p = head->next;
    25. while (p != NULL) {
    26. printf("%d ", p->data);
    27. p = p->next;
    28. }
    29. return 0;
    30. }

    输出结果:

     

    二、插入结点操作

    1. #include
    2. #include
    3. typedef struct List{
    4. int data;
    5. struct List* next;
    6. }LinkList;
    7. int main() {
    8. printf("输入要建立的链表,输入-1停止:\n");
    9. LinkList* head, *rear, *node;
    10. int x;
    11. head = (LinkList*)malloc(sizeof(LinkList));
    12. head->next = NULL;
    13. rear = head;
    14. scanf("%d", &x);
    15. while (x != -1) {
    16. node = (LinkList*)malloc(sizeof(LinkList));
    17. node->data = x;
    18. rear->next = node;
    19. rear = node;
    20. scanf("%d", &x);
    21. }
    22. rear->next = NULL;
    23. printf("尾插法建立链表后从头往后输出:\n");
    24. LinkList* p = head->next;
    25. while (p != NULL) {
    26. printf("%d ", p->data);
    27. p = p->next;
    28. }
    29. puts("");
    30. /*以下是插入操作*/
    31. printf("请输入要在第几个结点后面插入:\n");
    32. int target;
    33. scanf("%d", &target);
    34. printf("请输入要插入的数:\n");
    35. int num;
    36. scanf("%d", &num);
    37. LinkList* q = head->next;
    38. int i = 1;
    39. while (q != NULL && i < target) {
    40. q = q->next;
    41. ++i;
    42. }
    43. node = (LinkList*)malloc(sizeof(LinkList));
    44. node->data = num;
    45. node->next = q->next;
    46. q->next = node;
    47. printf("插入完成后运行结果:\n");
    48. LinkList* pp = head->next;
    49. while (pp != NULL) {
    50. printf("%d ", pp->data);
    51. pp = pp->next;
    52. }
    53. return 0;
    54. }

    输出结果

     

    三、删除节点操作

    删除节点要注意,是查找到第 i-1 个结点再开始操作。

    1. #include
    2. #include
    3. typedef struct List{
    4. int data;
    5. struct List* next;
    6. }LinkList;
    7. int main() {
    8. printf("输入要建立的链表,输入-1停止:\n");
    9. LinkList* head, *rear, *node;
    10. int x;
    11. head = (LinkList*)malloc(sizeof(LinkList));
    12. head->next = NULL;
    13. rear = head;
    14. scanf("%d", &x);
    15. while (x != -1) {
    16. node = (LinkList*)malloc(sizeof(LinkList));
    17. node->data = x;
    18. rear->next = node;
    19. rear = node;
    20. scanf("%d", &x);
    21. }
    22. rear->next = NULL;
    23. printf("尾插法建立链表后从头往后输出:\n");
    24. LinkList* p = head->next;
    25. while (p != NULL) {
    26. printf("%d ", p->data);
    27. p = p->next;
    28. }
    29. puts("");
    30. /*以下是插入操作*/
    31. printf("请输入要删除第几个结点:\n");
    32. int target;
    33. scanf("%d", &target);
    34. LinkList* q = head->next;
    35. int i = 1;
    36. while (q != NULL && i < target - 1) { //找到第target-1个结点即可
    37. q = q->next;
    38. ++i;
    39. }
    40. LinkList* temp = q->next;
    41. q->next = temp->next;
    42. free(temp);
    43. printf("删除完成后运行结果:\n");
    44. LinkList* pp = head->next;
    45. while (pp != NULL) {
    46. printf("%d ", pp->data);
    47. pp = pp->next;
    48. }
    49. return 0;
    50. }

    输出结果:

     

    四、单链表操作的一些常见问题

    1、结构体变量和结构体指针的区别?

            有时候我们会看到如下情况:

    1. typedef struct List{
    2. int data;
    3. struct List* next;
    4. }LNode, *LinkList;

    一些初学者会对LNode*LinkList 表示疑惑,为什么要定义一个结构体变量,一个结构体指针呢?

    首先说明下它们的区别:结构体变量定义完后,会自动在内存中开辟一段空间;而结构体指针定义完后,并不会开辟新的空间。要使用结构体指针,你得手动去开辟空间(比如malloc),然后让结构体指针指向它才行,或者让结构体指针指向其它已经开辟的空间的地址才行。此外,它们的访问结构体成员方式也不同,结构体变量访问用“.”,而结构体指针用“->”,或者 (*p).xx (其中p是结构体指针,xx是结构体中的一个成员)。

            举个例子,比如在头插尾插建立链表中,建立头结点,原来是用结构体指针表示:

    1. LinkList* head;
    2. head = (LinkList*)malloc(sizeof(LinkList));

            我们可以改成用结构体变量表示头结点,因为结构体变量声明后,会自动在内存中开辟空间,这样我们后面就不用手动去malloc了:

    1. LinkList head;
    2. //head = (LinkList*)malloc(sizeof(LinkList)); 不需要了

    2、什么时候要malloc?

            需要新建一个结点时。

    3、形参里面出现了取地址符(&),有什么作用?

            形参里面出现“&”,比如 int func(int &a, int &b); 这是C++的语法,不是C的,因此这里不展开。

  • 相关阅读:
    VUE 项目组成逻辑(手写一个vue-cli)
    带领大家认识 :指针数组,浅浅分析:数组名与&数组名的区别联系
    SOME/IP
    LeetCode Algorithm 剑指 Offer 22. 链表中倒数第k个节点
    人工神经网络与神经网络,人工神经网络入门书籍
    使用springboot 配置一个websocket客户端
    原生实现.NET 5.0+ 自定义日志
    Linux Ubuntu安装配置教程
    Cilium系列-4-Cilium本地路由
    【算法笔记】01. 如何正确的学习和练习算
  • 原文地址:https://blog.csdn.net/m0_56494923/article/details/126479724