• c语言练习89:链表的使用


    链表的使用

    虽然有这么多的链表的结构,但是我们实际中最常⽤还是两种结构: 单链表 和 双向带头循环链表 1. ⽆头单向⾮循环链表:结构简单,⼀般不会单独⽤来存数据。实际中更多是作为其他数据结 构的⼦结构,如哈希桶、图的邻接表等等。另外这种结构在笔试⾯试中出现很多。 2. 带头双向循环链表:结构最复杂,⼀般⽤在单独存储数据。实际中使⽤的链表数据结构,都 是带头双向循环链表。另外这个结构虽然结构复杂,但是使⽤代码实现以后会发现结构会带 来很多优势,实现反⽽简单了,后⾯我们代码实现了就知道了。

    补充说明:

    1、链式机构在逻辑上是连续的,在物理结构上不⼀定连续

    2、节点⼀般是从堆上申请的 3、从堆上申请来的空间,是按照⼀定策略分配出来的,每次申请的空间可能连续,可能不连续

    SList.h

    1. #pragma once
    2. #define _CRT_SECURE_NO_WARNINGS
    3. #include
    4. #include
    5. #include
    6. #include
    7. //定义链表节点的结构
    8. typedef int SLDataType;
    9. typedef struct SListNode{
    10. int data;//要保存的数据
    11. struct SListNode* next;
    12. }SLNode;
    13. //创建节点组成链表并打印链表
    14. void SLPrint(SLNode* phead);
    15. //尾插
    16. void SLPushBack(SLNode** pphead, SLDataType x);
    17. void SLPushFront(SLNode** pphead, SLDataType x);
    18. //尾删
    19. void SLPopBack(SLNode** pphead);
    20. void SLPopFront(SLNode** pphead);
    21. //在指定位置之前插入数据
    22. void SLInit(SLNode** pphead, SLNode* pos, SLDataType x);
    23. //在指定位置之后插入数据
    24. void SLInit(SLNode* pos, SLDataType x);
    25. //找节点(考虑第一个参数为一级指针还是二级指针)
    26. //因为不改变头节点,所以可以传一级指针
    27. //但由于代码一致性原则(保持接口一致性),应该传二级指针
    28. void SLFind(SLNode** pphead, SLDataType x);
    29. //删除pos结点
    30. void SLErase(SLNode** pphead, SLNode* pos);
    31. //删除pos之后的结点
    32. void SLEraseAfter(SLNode** pphead, SLNode* pos);
    33. //销毁链表
    34. void SLDesTory(SLNode** pphead);

    SList.c

    1. #define _CRT_SECURE_NO_WARNINGS
    2. #include "SList.h"
    3. void SLPrint(SLNode* phead) {
    4. //循环打印、
    5. SLNode* pcur = phead;
    6. while (pcur) {
    7. printf("%d ->", pcur->data);
    8. pcur = pcur->next;
    9. }
    10. printf("NULL\n");
    11. }
    12. SLNode* SLBuyNode(SLDataType x) {
    13. SLNode* node = (SLNode*)malloc(sizeof(SLNode));
    14. node->data = x;
    15. node->next = NULL;
    16. return node;
    17. }
    18. //尾插
    19. void SLPushBack(SLNode** pphead, SLDataType x) {
    20. assert(pphead);
    21. SLNode* node = SLBuyNode(x);
    22. if (*pphead = NULL) {
    23. *pphead = node;
    24. return;
    25. }
    26. //链表不为空,找尾(定义一个临时变量pcur)
    27. SLNode* pcur= *pphead;
    28. while (pcur->next) {
    29. pcur = pcur->next;
    30. }
    31. pcur->next = node;
    32. }
    33. void SLPushFront(SLNode** pphead, SLDataType x) {
    34. assert(pphead);
    35. SLNode* node = SLBuyNode(x);
    36. //新节点跟头结点连接起来
    37. node->next = *pphead;//plist
    38. //让新的节点成为头结点
    39. *pphead = node;
    40. }
    41. void SLPopBack(SLNode** pphead) {
    42. assert(pphead);
    43. //第一个节点不能为空
    44. assert(*pphead);
    45. //只有一个节点的情况
    46. if ((*pphead)->next==NULL) {
    47. //直接删除头结点
    48. free(*pphead);
    49. pphead = NULL;
    50. return;
    51. }
    52. //有多个结点的情况
    53. //找到尾结点的前一个节点
    54. SLNode* prev = NULL;
    55. SLNode* ptail = *pphead;
    56. while (ptail->next != NULL) {
    57. prev = ptail;
    58. ptail = ptail->next;
    59. }
    60. //prev的next指针不在指向ptail,而是指向ptail的下一个节点
    61. prev->next = ptail->next;
    62. free(ptail);
    63. ptail = NULL;
    64. }
    65. void SLPopFront(SLNode** pphead) {
    66. assert(pphead);
    67. assert(*pphead);
    68. SLNode* del = *pphead;
    69. *pphead = (*pphead)->next;
    70. free(del);
    71. del = NULL;
    72. }
    73. void SLInit(SLNode** pphead, SLNode* pos, SLDataType x) {
    74. assert(pphead);
    75. SLNode* node = SLBuyNode(x);
    76. //处理没有结点的情况(约定链表不能为空+pos也不能为空)
    77. assert(pos);
    78. assert(*pphead);
    79. //处理只有一个结点+pos指向第一个结点(pos即为第一个结点)
    80. if ((*pphead)->next == NULL||pos==*pphead) {
    81. node->next = *pphead;
    82. *pphead = node;
    83. return;
    84. }
    85. //找pos的前一个节点
    86. SLNode* prev = *pphead;
    87. while (prev->next != NULL) {
    88. prev = prev->next;
    89. }
    90. prev->next = pos;
    91. pos->next = node;
    92. }
    93. //查找第一个为x的节点
    94. void SLFind(SLNode** pphead, SLDataType x) {
    95. SLNode* pcur = *pphead;
    96. while (pcur) {
    97. if (pcur->data == x) {
    98. return pcur;
    99. }
    100. pcur = pcur->next;
    101. }
    102. return NULL;
    103. }
    104. //删除pos结点
    105. void SLErase(SLNode** pphead, SLNode* pos) {
    106. assert(pphead);
    107. assert(*pphead);
    108. assert(pos);
    109. if (pos == *pphead) {
    110. *pphead = (*pphead)->next;
    111. free(pos);
    112. return;
    113. }
    114. //找pos的前一个节点
    115. SLNode* prev = *pphead;
    116. while (prev->next!=pos) {
    117. prev = prev->next;
    118. }
    119. prev->next = pos->next;
    120. free(pos);
    121. pos=NULL;
    122. }
    123. //删除pos之后的结点
    124. void SLEraseAfter(SLNode** pphead, SLNode* pos) {
    125. assert(pos && pos->next);
    126. SLNode* del = pos->next;
    127. free(del);
    128. del = NULL;
    129. }
    130. //销毁链表
    131. void SLDesTory(SLNode** pphead) {
    132. assert(pphead);
    133. SLNode* pcur = *pphead;
    134. //循环删除
    135. while (pcur) {
    136. SLNode* next = pcur->next;
    137. free(pcur);
    138. pcur = next;
    139. }
    140. *pphead = NULL;
    141. }

    test.c

    1. #define _CRT_SECURE_NO_WARNINGS
    2. //int removeElement(int* nums, int numsSize, int val) {
    3. // int src, dst;
    4. // while (src < numsSize) {
    5. // if (nums[src] == val) {
    6. // src++;
    7. // }
    8. // else {
    9. // nums[dst] = nums[src];
    10. // src++;
    11. // dst++;
    12. // }
    13. // }
    14. // return dst;
    15. //}
    16. //void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
    17. // int l1 = m - 1, l2 = n - 1;
    18. // int l3 = m + n - 1;
    19. // while (l1 >= 0 && l2 >= 0) {
    20. // if (nums1[l1] > nums2[l2]) {
    21. // nums1[l3--] = nums1[l1--];
    22. // }
    23. // else {
    24. // nums1[l3--] = nums2[l2--];
    25. // }
    26. // }
    27. // while (l2 >= 0) {
    28. // nums1[l3--] = nums2[l2--];
    29. // }
    30. //}
    31. #include"SList.h"
    32. void slttest() {
    33. SLNode* node1 = (SLNode*)malloc(sizeof(SLNode));
    34. node1->data = 1;
    35. SLNode* node2 = (SLNode*)malloc(sizeof(SLNode));
    36. node2->data = 2;
    37. SLNode* node3 = (SLNode*)malloc(sizeof(SLNode));
    38. node3->data = 3;
    39. SLNode* node4 = (SLNode*)malloc(sizeof(SLNode));
    40. node4->data = 4;
    41. node1->next = node2;
    42. node2->next = node3;
    43. node3->next = node4;
    44. node4->next = NULL;
    45. SLNode* plist = node1;
    46. SLPrint(plist);
    47. }
    48. int main() {
    49. slttest();
    50. return 0;
    51. }

  • 相关阅读:
    【C++泛型学习笔记】友元、可变参模板
    EasyPR 车牌识别
    实现物联网的技术要素
    Android 子线程为什么不能更新UI?
    使用dockerfile自定义Tomcat镜像
    通过内网穿透,在Windows 10系统下搭建个人《我的世界》服务器公网联机
    鸿蒙原生应用元服务-访问控制(权限)开发应用权限列表二
    RDMA Shared Receive Queue(四)
    Linux基础学习笔记(十三)——文件的格式化处理
    JAVA核酸预约检测管理系统毕业设计 开题报告
  • 原文地址:https://blog.csdn.net/2301_77479435/article/details/133847016