• [数据结构初阶]一文轻松学链表


    链表的概念及结构

    概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表
    中的指针链接次序实现的 。

     

     

    链表的分类

    实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

    单向或者双向

    带头或者不带头 

    循环或者非循环

    链表的实现  

    SList.h

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. typedef int SLTDataType;
    6. typedef struct SListNode
    7. {
    8. SLTDataType data;
    9. struct SListNode* next;
    10. }SLTNode;
    11. void SListPrint(SLTNode* phead);
    12. void SListPushBack(SLTDataType** phead, SLTDataType x);
    13. void SListPushFront(SLTDataType** phead, SLTDataType x);
    14. void SListPopBack(SLTNode** pphead);
    15. void SListPopFront(SLTNode** pphead);
    16. SLTNode* BuySListNode(SLTDataType x);
    17. SLTDataType* SListFind(SLTNode* phead, SLTDataType x);
    18. void SListModify(SLTNode* phead, SLTDataType x, SLTDataType y);
    19. void SListFrontPush(SLTNode** pphead, SLTDataType x, SLTDataType y);
    20. void SListBackPush(SLTNode** pphead, SLTDataType x, SLTDataType y);
    21. void SListPop(SLTNode** pphead, SLTDataType x);
    22. void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
    23. void SListErase(SLTNode** pphead, SLTNode* pos);

    SList.c

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. #include"SList.h"
    6. void SListPrint(SLTNode* phead)
    7. {
    8. SLTNode* cur = phead;
    9. while (cur != NULL)
    10. {
    11. printf("%d->", cur->data);
    12. cur = cur->next;
    13. }
    14. printf("null\n");
    15. }
    16. void SListPushBack(SLTDataType** pphead, SLTDataType x)
    17. {
    18. assert(pphead);
    19. SLTNode* newnode = BuySListNode(x);
    20. if (*pphead == NULL)
    21. {
    22. *pphead = newnode;
    23. }
    24. else
    25. {
    26. SLTNode* tail = *pphead;
    27. while (tail->next != NULL)
    28. {
    29. tail = tail->next;
    30. }
    31. tail->next = newnode;
    32. }
    33. }
    34. SLTNode* BuySListNode(SLTDataType x)
    35. {
    36. SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
    37. assert(newnode);
    38. newnode->data = x;
    39. newnode->next = NULL;
    40. return newnode;
    41. }
    42. void SListPushFront(SLTDataType** pphead, SLTDataType x)
    43. {
    44. assert(pphead);
    45. SLTNode* newnode = BuySListNode(x);
    46. newnode->next = *pphead;
    47. *pphead = newnode;
    48. }
    49. void SListPopBack(SLTNode** pphead)
    50. {
    51. assert(pphead);
    52. assert(*pphead);
    53. if ((*pphead)->next == NULL)
    54. {
    55. free(*pphead);
    56. *pphead = NULL;
    57. }
    58. else
    59. {
    60. SLTNode* tail = *pphead;
    61. /*SLTNode* tailPrev = NULL;
    62. while (tail->next != NULL)
    63. {
    64. tailPrev = tail;
    65. tail = tail->next;
    66. }
    67. free(tail);
    68. tailPrev->next = NULL;*/
    69. while (tail->next->next != NULL)
    70. {
    71. tail = tail->next;
    72. }
    73. free(tail->next);
    74. tail->next = NULL;
    75. }
    76. }
    77. void SListPopFront(SLTNode** pphead)
    78. {
    79. assert(pphead);
    80. assert(*pphead);
    81. SLTNode* next = (*pphead)->next;
    82. free(*pphead);
    83. *pphead = next;
    84. }
    85. SLTDataType* SListFind(SLTNode* phead, SLTDataType x)
    86. {
    87. SLTNode* cur = phead;
    88. while (cur)
    89. {
    90. if (cur->data == x)
    91. {
    92. return cur;
    93. }
    94. cur = cur->next;
    95. }
    96. return NULL;
    97. }
    98. void SListModify(SLTNode* phead, SLTDataType x, SLTDataType y)
    99. {
    100. SLTNode* ret = SListFind(phead, x);
    101. if (ret)
    102. {
    103. ret->data = y;
    104. }
    105. }
    106. void SListFrontPush(SLTNode** pphead, SLTDataType x, SLTDataType y)
    107. {
    108. assert(pphead);
    109. assert(*pphead);
    110. SLTNode* pos = SListFind(*pphead, x);
    111. if (pos)
    112. {
    113. SListInsert(pphead, pos, y);
    114. }
    115. }
    116. void SListBackPush(SLTNode** pphead, SLTDataType x, SLTDataType y)
    117. {
    118. assert(pphead);
    119. assert(*pphead);
    120. SLTNode* pos = SListFind(*pphead, x);
    121. if (pos)
    122. {
    123. if (pos == *pphead)
    124. {
    125. SListPushBack(pphead, x);
    126. }
    127. else
    128. {
    129. SLTNode* newnode = BuySListNode(x);
    130. newnode->next = pos->next;
    131. pos->next = newnode;
    132. newnode->data = y;
    133. }
    134. }
    135. }
    136. void SListPop(SLTNode** pphead, SLTDataType x)
    137. {
    138. assert(pphead);
    139. assert(*pphead);
    140. SLTNode* pos = SListFind(*pphead, x);
    141. if (pos)
    142. {
    143. SListErase(pphead, pos);
    144. }
    145. }
    146. void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
    147. {
    148. assert(pos);
    149. assert(pphead);
    150. if (pos == *pphead)
    151. {
    152. SListPushFront(pphead, x);
    153. }
    154. else
    155. {
    156. SLTNode* prev = *pphead;
    157. while (prev->next != pos )
    158. {
    159. prev = prev->next;
    160. }
    161. SLTNode* newnode = BuySListNode(x);
    162. prev->next = newnode;
    163. newnode->next = pos;
    164. }
    165. }
    166. void SListErase(SLTNode** pphead, SLTNode* pos)
    167. {
    168. assert(pphead);
    169. assert(pos);
    170. if (*pphead == pos)
    171. {
    172. SListPopFront(pphead);
    173. }
    174. else
    175. {
    176. SLTNode* prev = *pphead;
    177. while (prev->next != pos)
    178. {
    179. prev = prev->next;
    180. }
    181. prev->next = pos->next;
    182. free(pos);
    183. }
    184. }

    Frist.c

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include"SList.h"
    4. #include
    5. void menu()
    6. {
    7. printf("*****************************************************************\n");
    8. printf("1、尾插 2、头插\n");
    9. printf("3、尾删 4、头删\n");
    10. printf("5、前面插 6、后面插\n");
    11. printf("7、任意删 8、修改\n");
    12. printf("9、打印 -1、退出\n");
    13. printf("*****************************************************************\n");
    14. }
    15. void TestSList1()
    16. {
    17. SLTNode* n1 = NULL;
    18. /*SLTNode* n1 = (SLTNode*)malloc(sizeof(SLTNode));
    19. assert(n1);*/
    20. //SLTNode* n2 = (SLTNode*)malloc(sizeof(SLTNode));
    21. //assert(n2);
    22. //SLTNode* n3 = (SLTNode*)malloc(sizeof(SLTNode));
    23. //assert(n3);
    24. //SLTNode* n4 = (SLTNode*)malloc(sizeof(SLTNode));
    25. //assert(n4);
    26. //n1->data = 1;
    27. //n2->data = 2;
    28. //n3->data = 3;
    29. //n4->data = 4;
    30. //n1->next = n2;
    31. //n2->next = n3;
    32. //n3->next = n4;
    33. //n4->next = NULL;
    34. SListPushFront(&n1, 1);
    35. SListPushBack(&n1, 5);
    36. SListPushBack(&n1, 2);
    37. SListPushFront(&n1, 1);
    38. SListPrint(n1);
    39. SLTNode* a = SListFind(n1, 5);
    40. SListModify(n1, 1, 6);
    41. SListPrint(n1);
    42. SListFrontPush(&n1, 1, 2);
    43. SListPrint(n1);
    44. SListPrint(n1);
    45. }
    46. int main()
    47. {
    48. SLTNode* n1 = NULL;
    49. int option;
    50. do {
    51. menu();
    52. if (scanf("%d", &option) == EOF)
    53. {
    54. printf("scanf输入错误\n");
    55. break;
    56. }
    57. int val, pos;
    58. switch (option)
    59. {
    60. case -1:
    61. printf("退出\n");
    62. exit(0);
    63. break;
    64. case 1:
    65. printf("请连续输入你要尾插的数据,以0结束:\n");
    66. scanf("%d", &val);
    67. while (val != 0)
    68. {
    69. SListPushBack(&n1, val);
    70. scanf("%d", &val);
    71. }
    72. break;
    73. case 2: {
    74. printf("请连续输入你要头插的数据,以0结束:\n");
    75. scanf("%d", &val);
    76. while (val != 0)
    77. {
    78. SListPushFront(&n1, val);
    79. scanf("%d", &val);
    80. }
    81. break;
    82. }
    83. case 3:
    84. SListPopBack(&n1);
    85. break;
    86. case 4:
    87. SListPopFront(&n1);
    88. break;
    89. case 5:
    90. {
    91. int y;
    92. int x;
    93. printf("请输入你要的被插入的,和插入的值\n");
    94. scanf("%d%d", &x, &y);
    95. SListFrontPush(&n1, x, y);
    96. break;
    97. }
    98. case 6:
    99. {
    100. int y;
    101. int x;
    102. printf("请输入你要的被插入的,和插入的值\n");
    103. scanf("%d%d", &x, &y);
    104. SListBackPush(&n1, x, y);
    105. break;
    106. }
    107. case 7:
    108. {
    109. int x;
    110. printf("请输入你要删除的值\n");
    111. scanf("%d", &x);
    112. SListPop(&n1, x);
    113. }
    114. case 8:
    115. {
    116. int y;
    117. int x;
    118. printf("请输入你要修改的位置,和修改后的值\n");
    119. scanf("%d%d", &x, &y);
    120. SListModify(n1, x, y);
    121. break;
    122. }
    123. case 9:
    124. SListPrint(n1);
    125. break;
    126. default:
    127. exit(-1);
    128. break;
    129. }
    130. } while (option != -1);
    131. return 0;
    132. }

    链表面试题

    【LeetCode】203. 移除链表元素的三种方法_江湖第一深情的博客-CSDN博客

            给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

    【LeetCode】206. 反转链表—力扣_江湖第一深情的博客-CSDN博客

            给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

    【LeetCode】876. 链表的中间结点—力扣_江湖第一深情的博客-CSDN博客

            给定一个头结点为 head 的非空单链表,返回链表的中间结点。

            如果有两个中间结点,则返回第二个中间结点。        

    (3条消息) 剑指offer--链表中倒数第k个结点(jz22)_笨笨同学‍的博客-CSDN博客

            输入一个链表,输出该链表中倒数第k个结点。

    (3条消息) 【2016校招真题】OR36 链表的回文结构_笨笨同学‍的博客-CSDN博客

            对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。

            给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

    (3条消息) 【程序员面试宝典】CM11 链表分割_笨笨同学‍的博客-CSDN博客

            现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

    (3条消息) 【LeetCode】21. 合并两个有序链表—力扣_笨笨同学‍的博客-CSDN博客 

            将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。  

    (3条消息) 【LeetCode】160. 相交链表—力扣_笨笨同学‍的博客-CSDN博客

              给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。        

    (3条消息) 【LeetCode】141. 环形链表—力扣_笨笨同学‍的博客-CSDN博客 

            给你一个链表的头节点 head ,判断链表中是否有环。

            如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

            如果链表中存在环 ,则返回 true 。 否则,返回 false 。

    (3条消息) 【LeetCode】142. 环形链表 II—力扣_笨笨同学‍的博客-CSDN博客 

            给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

            如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

            不允许修改 链表。

    (3条消息) 【LeetCode】138. 复制带随机指针的链表—力扣_笨笨同学‍的博客-CSDN博客        

             给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

            构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

            例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

            返回复制链表的头节点。

            用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

            val:一个表示 Node.val 的整数。
            random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。
            你的代码 只 接受原链表的头节点 head 作为传入参数。

  • 相关阅读:
    qiankun 乾坤主应用访问微应用css静态图片资源报404
    Kubernetes革命:云原生时代的应用编排和自动化
    ECharts与Excel的结合实战
    安全开发之碰撞检测与伤害计算逻辑
    【数据结构】二叉搜索树的原理及其实现
    iOS TestFlight 使用详解
    计算机网络概述及因特网
    APP 页面秒开优化方面总结~
    Linux 指令心法(十三)`mkdir` 创建新的目录(文件夹)
    angular基础总结
  • 原文地址:https://blog.csdn.net/qq_51581716/article/details/127613796