• 常用数据结构和算法


    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


    前言

    提示:这里可以添加本文要记录的大概内容:

    这里面有10个数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie树;10个算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法。。


    一、复杂度

    1、时间复杂度(最好情况时间复杂度、最坏情况时间复杂度、平均时间复杂度)

    2、空间复杂度

    二、数据结构知识

    2.1 数据结构的逻辑结构

    数据结构中的逻辑结构(附上c++中的常见数据结构的逻辑结构)_数据结构的逻辑结构有哪些-CSDN博客

    数据结构的逻辑结构包括四种逻辑结构

    1、集合结构

    2、线性结构:一一对应

    3、树形结构

    4、图形结构

    三、数据结构分析

    3.1、链表

    3.1.1 静态链表

    3.2.2动态链表

    3.2.2.1、回顾代码

    看了一个抖音,里面讲了静态链表和动态链表。之前看的静态链表讲的蛮好的。觉得还挺简单的。今天又看到了讲动态链表的。当时就有个疑问。new出来的stu_new的next指针不需要值NULL吗?一直带着这个疑问。还评论了一下,想看看别人是怎么说的。然后回工位还在想这件事情。然后就觉得写一下吧,感觉不是很难,然后就写下了下面的代码。

    下面的代码基本实现了视频里的效果。后面还要跟视频的作下对比。

    1. #include
    2. #include
    3. #include "string.h"
    4. //动态指针
    5. //①枚举类型不会写(成员不会写)
    6. //②结构体指针写法不会写
    7. //scanf循环
    8. //性别
    9. typedef enum Gender
    10. {
    11. male,
    12. female,
    13. middle
    14. }Gend;
    15. //结构体
    16. typedef struct stu
    17. {
    18. char name[10];
    19. int age;
    20. Gend gender;
    21. int score;
    22. struct stu* next;
    23. }Stu;
    24. Stu stuDynamic;
    25. int stuAdd(Stu* stu)
    26. {
    27. if(NULL == stu)
    28. {
    29. return -1;
    30. }
    31. Stu *stuTemp = &stuDynamic;
    32. while(stuTemp->next)
    33. {
    34. stuTemp = stuTemp->next;
    35. }
    36. stuTemp->next = stu;
    37. return 1;
    38. }
    39. void printStu(Stu* stu)
    40. {
    41. Stu* temp = stu->next;
    42. printf("打印学生信息\n");
    43. while(temp)
    44. {
    45. printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
    46. temp = temp->next;
    47. }
    48. }
    49. int main()
    50. {
    51. char name[10] = {'\0'};
    52. int age = -1;
    53. int score;
    54. Gend gender;
    55. printf("输入姓名, 年龄, 性别, 分数\n");
    56. // gets("%s", name);
    57. // scanf("%d", &age);
    58. // scanf("%d", &score);
    59. // scanf("%d", &gender);
    60. while(age != 0)
    61. {
    62. scanf("%s %d %d %d", name, &age, &gender, &score);
    63. Stu *stu_new = (Stu*)malloc(sizeof(Stu));
    64. if(NULL == stu_new)
    65. {
    66. printf("malloc fail");
    67. continue;
    68. }
    69. memcpy(stu_new->name, name, 10);
    70. stu_new->age = age;
    71. stu_new->score = score;
    72. stu_new->gender = gender;
    73. stu_new->next = NULL;
    74. stuAdd(stu_new);
    75. printStu(&stuDynamic);
    76. }
    77. return 0;
    78. }

    但是其中还是有一个问题。就是我一开始写的代码是没有将stu_new的next指针置空的。那个代码就异常了。体现在没有让我继续输入数据,然后也打印了,打印后就退出了。 然后调试的时候发现程序在print里面会异常退出。

    现在来看就是因为stu_new没有置为NULL。所以我之前的考虑是对的。那么视频里的程序是怎么写的呢,需要在会看一下视频代码。下面就把之前写的代码贴出来。

    1. #include
    2. #include
    3. #include "string.h"
    4. //动态指针
    5. //①枚举类型不会写(成员不会写)
    6. //②结构体指针写法不会写
    7. //scanf循环
    8. //性别
    9. typedef enum Gender
    10. {
    11. male,
    12. female,
    13. middle
    14. }Gend;
    15. //结构体
    16. typedef struct stu
    17. {
    18. char name[10];
    19. int age;
    20. Gend gender;
    21. int score;
    22. struct stu* next;
    23. }Stu;
    24. Stu stuDynamic;
    25. int stuAdd(Stu* stu)
    26. {
    27. if(NULL == stu)
    28. {
    29. return -1;
    30. }
    31. Stu *stuTemp = &stuDynamic;
    32. while(stuTemp->next)
    33. {
    34. stuTemp = stuTemp->next;
    35. }
    36. stuTemp->next = stu;
    37. return 1;
    38. }
    39. void printStu(Stu* stu)
    40. {
    41. Stu* temp = stu;
    42. printf("打印学生信息\n");
    43. while(temp)
    44. {
    45. printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
    46. temp = temp->next;
    47. }
    48. }
    49. int main()
    50. {
    51. char name[10] = {'\0'};
    52. int age = -1;
    53. int score;
    54. Gend gender;
    55. printf("输入姓名, 年龄, 性别, 分数\n");
    56. // gets("%s", name);
    57. // scanf("%d", &age);
    58. // scanf("%d", &score);
    59. // scanf("%d", &gender);
    60. while(age != 0)
    61. {
    62. scanf("%s %d %d %d", name, &age, &gender, &score);
    63. Stu *stu_new = (Stu*)malloc(sizeof(Stu));
    64. if(NULL == stu_new)
    65. {
    66. printf("malloc fail");
    67. continue;
    68. }
    69. memcpy(stu_new->name, name, 10);
    70. stu_new->age = age;
    71. stu_new->score = score;
    72. stu_new->gender = gender;
    73. stuAdd(stu_new);
    74. printStu(&stuDynamic);
    75. }
    76. return 0;
    77. }

    所以当stu_new的next指针没有置为NULL的时候,程序会越界访问。导致程序崩溃结束。看起来的效果就像是程序执行完了一样。

    随后还有个问题,就是全局变量stuDynamic的next指针时NULL吗?

    自己写了代码验证

    1. #include
    2. #include
    3. #include "string.h"
    4. Stu stuDynamic;
    5. int main()
    6. {
    7. if(NULL == stuDynamic.next)
    8. {
    9. printf("stuDynamic->next:%p\n", stuDynamic.next);
    10. printf("stuDynamic->next is NULL\n");
    11. }
    12. }
    13. //stuDynamic->next:00000000
    14. //stuDynamic->next is NULL

    查了一个帖子:全局变量和局部变量初始化问题_全局变量需要初始化吗-CSDN博客

    里面这么表述:这里需要分清一个事实,是变量系统都会默认给初始化,只不过全局变量默认初始化为0,而局部变量被初始化为随机数,这个随机数用不了,后面会验证

    3.2.2.2、阶段总结

    看了视频代码,有以下几点需要说明下

    ①全局变量没有写成g_xxx

    ②视频代码重复输入是因为用了while(1)

    ③视频的打印也是从g_stu开始打印,所以有全是0的输出,name是空

    后面可以优化代码。

    下面是优化代码,下面的代码实现了修改和查询

    1. #include
    2. #include
    3. #include "string.h"
    4. #include "stdbool.h"
    5. //动态指针
    6. //①枚举类型不会写(成员不会写)
    7. //②结构体指针写法不会写
    8. //③scanf循环
    9. //④scanf用法
    10. //⑤switch-case写法
    11. //⑥strcpy == 0,没有判断是否==0,导致直接打印0
    12. //⑦解决scanf读单个字符会把换行符\n读取,且字符变量中只存了\n
    13. //⑧将strcmp用错成strcpy,导致出现修改时所有数据都被改了
    14. //性别
    15. typedef enum Gender
    16. {
    17. male,
    18. female,
    19. middle
    20. }Gend;
    21. //结构体
    22. typedef struct stu
    23. {
    24. char name[10];
    25. int age;
    26. Gend gender;
    27. int score;
    28. struct stu* next;
    29. }Stu;
    30. Stu g_stuDaynamic;
    31. //增加
    32. int stu_add(Stu* stu)
    33. {
    34. if(NULL == stu)
    35. {
    36. return -1;
    37. }
    38. Stu *stuTemp = &g_stuDaynamic;
    39. while(stuTemp->next)
    40. {
    41. stuTemp = stuTemp->next;
    42. }
    43. stuTemp->next = stu;
    44. return 1;
    45. }
    46. //查询
    47. int stu_find(Stu* stu, char* name)
    48. {
    49. Stu *temp = stu;
    50. while(NULL == temp)
    51. {
    52. return -1;
    53. }
    54. while(temp)
    55. {
    56. if( strcmp(temp->name, name) == 0)
    57. {
    58. printf("find the record");
    59. printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
    60. return 1;
    61. }
    62. temp = temp->next;
    63. }
    64. printf("find the record Empty!");
    65. }
    66. //修改
    67. int stu_modify(const Stu* stu, Stu* stu_modify)
    68. {
    69. if(NULL == stu)
    70. {
    71. return -1;
    72. }
    73. Stu* temp = stu;
    74. while(temp)
    75. {
    76. if(strcmp(temp->name, stu_modify->name) == 0)
    77. {
    78. (*temp).age = stu_modify->age;
    79. (*temp).gender = stu_modify->gender;
    80. (*temp).score = stu_modify->score;
    81. return 1;
    82. }
    83. temp = temp->next;
    84. }
    85. }
    86. void printStu(Stu* stu)
    87. {
    88. Stu* temp = stu->next;
    89. printf("打印学生信息\n");
    90. while(temp)
    91. {
    92. printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
    93. temp = temp->next;
    94. }
    95. }
    96. int action_add()
    97. {
    98. char name[10] = {'\0'};
    99. int age;
    100. int score;
    101. Gend gender;
    102. printf("输入姓名, 年龄, 性别, 分数\n");
    103. scanf("%s %d %d %d", name, &age, &gender, &score);
    104. Stu* stu_new = (Stu*)malloc(sizeof(Stu));
    105. if(NULL == stu_new)
    106. {
    107. printf("malloc fail");
    108. return -1;
    109. }
    110. memcpy(stu_new->name, name, 10);
    111. stu_new->age = age;
    112. stu_new->score = score;
    113. stu_new->gender = gender;
    114. stu_new->next = NULL;
    115. stu_add(stu_new);
    116. printStu(&g_stuDaynamic);
    117. }
    118. int action_find(char* name)
    119. {
    120. stu_find(&g_stuDaynamic, name);
    121. return 0;
    122. }
    123. int action_modify()
    124. {
    125. char name[10] = {'\0'};
    126. int age;
    127. int score;
    128. Gend gender;
    129. Stu *stu_modify_new = (Stu*)malloc(sizeof(Stu));
    130. if(NULL == stu_modify_new)
    131. {
    132. printf("malloc fail");
    133. return -1;
    134. }
    135. printf("输入修改的姓名, 年龄, 性别, 分数\n");
    136. scanf("%s %d %d %d", name, &age, &gender, &score);
    137. memcpy(stu_modify_new->name, name, 10);
    138. stu_modify_new->age = age;
    139. stu_modify_new->score = score;
    140. stu_modify_new->gender = gender;
    141. stu_modify(&g_stuDaynamic, stu_modify_new);
    142. free(stu_modify_new);
    143. printStu(&g_stuDaynamic);
    144. return 1;
    145. }
    146. int main()
    147. {
    148. bool m_flag = true;
    149. if(NULL == g_stuDaynamic.next)
    150. {
    151. printf("g_stuDaynamic->next:%p\n", g_stuDaynamic.next);
    152. printf("g_stuDaynamic->next is NULL\n");
    153. }
    154. while(m_flag)
    155. {
    156. printf("选择操作(A:增加、D:删除、C:更改、F:查找、其他:退出):\n");
    157. char action[2];
    158. scanf("%s", action);
    159. switch(action[0])
    160. {
    161. case 'A':
    162. {
    163. action_add();
    164. break;
    165. }
    166. case 'F':
    167. {
    168. printf("输入查询的姓名:\n");
    169. char name[100];
    170. scanf("%s", name);
    171. action_find(name);
    172. break;
    173. }
    174. case 'C':
    175. {
    176. action_modify();
    177. break;
    178. }
    179. default:
    180. {
    181. m_flag = false;
    182. break;
    183. }
    184. }
    185. }
    186. return 0;
    187. }

    这个代码还在编译时出现一个警告:

    warning:initialization discards ‘const’ qualifier from pointer target type

    这个帖子就是解释这个告警:warning:initialization discards ‘const’ qualifier from pointer target type 解决方法_initialization discards 'const' qualifier from poi-CSDN博客

    那么就存在一个问题,就是我不想函数更改g_stuDaynamic变量。所以用const限定为只读变量。但是在函数中还要遍历链表,temp又不能增加const修饰。但是赋值时就出现这个告警。下次看看教科书别人是怎么处理的。

    还有一个删除的功能没有实现,这个会涉及到链表头、尾的问题,先阶段性提交一次。

    下面是增加删除的代码

    1. #include
    2. #include
    3. #include "string.h"
    4. #include "stdbool.h"
    5. #include "ctype.h"
    6. //动态指针
    7. //①枚举类型不会写(成员不会写)
    8. //②结构体指针写法不会写
    9. //③scanf循环
    10. //④scanf用法
    11. //⑤switch-case写法
    12. //⑥strcpy == 0,没有判断是否==0,导致直接打印0
    13. //⑦解决scanf读单个字符会把换行符\n读取,且字符变量中只存了\n
    14. //性别
    15. typedef enum Gender
    16. {
    17. male,
    18. female,
    19. middle
    20. }Gend;
    21. //结构体
    22. typedef struct stu
    23. {
    24. char name[10];
    25. int age;
    26. Gend gender;
    27. int score;
    28. struct stu* next;
    29. }Stu;
    30. Stu g_stuDaynamic;
    31. int stu_add(Stu* stu)
    32. {
    33. if(NULL == stu)
    34. {
    35. return -1;
    36. }
    37. Stu *stuTemp = &g_stuDaynamic;
    38. while(stuTemp->next)
    39. {
    40. stuTemp = stuTemp->next;
    41. }
    42. stuTemp->next = stu;
    43. return 1;
    44. }
    45. int stu_find(Stu* stu, char* name)
    46. {
    47. Stu *temp = stu;
    48. while(NULL == temp)
    49. {
    50. return -1;
    51. }
    52. while(temp)
    53. {
    54. if( strcmp(temp->name, name) == 0)
    55. {
    56. printf("find the record");
    57. printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
    58. return 1;
    59. }
    60. temp = temp->next;
    61. }
    62. printf("find the record Empty!");
    63. }
    64. int stu_modify(const Stu* stu, Stu* stu_modify)
    65. {
    66. if(NULL == stu)
    67. {
    68. return -1;
    69. }
    70. Stu* temp = stu;
    71. while(temp)
    72. {
    73. if(strcmp(temp->name, stu_modify->name) == 0)
    74. {
    75. (*temp).age = stu_modify->age;
    76. (*temp).gender = stu_modify->gender;
    77. (*temp).score = stu_modify->score;
    78. return 1;
    79. }
    80. temp = temp->next;
    81. }
    82. }
    83. //删除
    84. int stu_delete(Stu* stu, char* name)
    85. {
    86. if (NULL == stu)
    87. {
    88. return -1;
    89. }
    90. Stu* temp = stu;
    91. while (temp)
    92. {
    93. if(NULL != temp->next && strcmp(temp->next->name, name) == 0)
    94. {
    95. //目标节点在重点
    96. Stu* traget = temp->next;
    97. Stu* tragetNext = traget->next;
    98. temp->next = tragetNext;
    99. free(traget);
    100. printf("已找到记录并删除\n");
    101. return 1;
    102. }
    103. temp = temp->next;
    104. }
    105. printf("未找到可删除记录\n");
    106. return 0;
    107. }
    108. void printStu(Stu* stu)
    109. {
    110. Stu* temp = stu->next;
    111. printf("打印学生信息\n");
    112. while(temp)
    113. {
    114. printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
    115. temp = temp->next;
    116. }
    117. }
    118. int action_add()
    119. {
    120. char name[10] = {'\0'};
    121. int age;
    122. int score;
    123. Gend gender;
    124. printf("输入姓名, 年龄, 性别, 分数\n");
    125. scanf("%s %d %d %d", name, &age, &gender, &score);
    126. Stu* stu_new = (Stu*)malloc(sizeof(Stu));
    127. if(NULL == stu_new)
    128. {
    129. printf("malloc fail");
    130. return -1;
    131. }
    132. memcpy(stu_new->name, name, 10);
    133. stu_new->age = age;
    134. stu_new->score = score;
    135. stu_new->gender = gender;
    136. stu_new->next = NULL;
    137. stu_add(stu_new);
    138. printStu(&g_stuDaynamic);
    139. }
    140. int action_find(char* name)
    141. {
    142. stu_find(&g_stuDaynamic, name);
    143. return 0;
    144. }
    145. int action_modify()
    146. {
    147. char name[10] = {'\0'};
    148. int age;
    149. int score;
    150. Gend gender;
    151. Stu *stu_modify_new = (Stu*)malloc(sizeof(Stu));
    152. if(NULL == stu_modify_new)
    153. {
    154. printf("malloc fail");
    155. return -1;
    156. }
    157. printf("输入修改的姓名, 年龄, 性别, 分数\n");
    158. scanf("%s %d %d %d", name, &age, &gender, &score);
    159. memcpy(stu_modify_new->name, name, 10);
    160. stu_modify_new->age = age;
    161. stu_modify_new->score = score;
    162. stu_modify_new->gender = gender;
    163. stu_modify(&g_stuDaynamic, stu_modify_new);
    164. free(stu_modify_new);
    165. printStu(&g_stuDaynamic);
    166. return 1;
    167. }
    168. int action_delete()
    169. {
    170. printf("输入需要删除的记录:\n");
    171. char* name[100];
    172. scanf("%s", name);
    173. stu_delete(&g_stuDaynamic, name);
    174. printStu(&g_stuDaynamic);
    175. return 0;
    176. }
    177. bool isTargetAlpha(char c)
    178. {
    179. if(toupper(c) == 'A' || toupper(c) == 'D' || toupper(c) == 'C' || toupper(c) == 'F' || toupper(c) == 'Q')
    180. {
    181. return true;
    182. }
    183. return false;
    184. }
    185. int main()
    186. {
    187. bool m_flag = true;
    188. if(NULL == g_stuDaynamic.next)
    189. {
    190. printf("g_stuDaynamic->next:%p\n", g_stuDaynamic.next);
    191. printf("g_stuDaynamic->next is NULL\n");
    192. }
    193. while(m_flag)
    194. {
    195. printf("选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):\n");
    196. char action[2];
    197. scanf("%s", action);
    198. if(!isTargetAlpha(action[0]))
    199. {
    200. continue;
    201. }
    202. switch(toupper(action[0]))
    203. {
    204. case 'A':
    205. {
    206. action_add();
    207. break;
    208. }
    209. case 'F':
    210. {
    211. printf("输入查询的姓名:\n");
    212. char name[100];
    213. scanf("%s", name);
    214. action_find(name);
    215. break;
    216. }
    217. case 'C':
    218. {
    219. action_modify();
    220. break;
    221. }
    222. case 'D':
    223. {
    224. action_delete();
    225. break;
    226. }
    227. case 'Q':
    228. {
    229. m_flag = false;
    230. printf("退出\n");
    231. break;
    232. }
    233. default:
    234. {
    235. printf("操作有误,请重新输入\n");
    236. break;
    237. }
    238. }
    239. }
    240. return 0;
    241. }

    感觉比想象的简单,没有之前那么复杂啊。

    反正自验证实现了功能,目前还遗留的就是输错信息,程序直接退出了。需要优化下。

    另外印象中删除好像还挺复杂呢?

    2024年1月11日20:01:11

    下面就是所谓的复杂的。现在写的是插入。好像删除也不复杂,之前印象中复杂的只有插入。不然链表也太难了吧。同时参考C和指针的书籍。其实这个代码一直你有一个问题,就是我在函数里把g_stuDaynamic写死了,不能处理其他的链表,没有通用性。这个也是看C和指针的书才发现的啊!!

    1. #include "test.h"
    2. //动态指针
    3. //①枚举类型不会写(成员不会写)
    4. //②结构体指针写法不会写
    5. //③scanf循环
    6. //④scanf用法
    7. //⑤switch-case写法
    8. //⑥strcpy == 0,没有判断是否==0,导致直接打印0
    9. //⑦解决scanf读单个字符会把换行符\n读取,且字符变量中只存了\n
    10. //性别
    11. typedef enum Gender
    12. {
    13. male,
    14. female,
    15. middle
    16. }Gend;
    17. //结构体
    18. typedef struct stu
    19. {
    20. char name[10];
    21. int age;
    22. Gend gender;
    23. int score;
    24. struct stu* next;
    25. }Stu;
    26. Stu g_stuDaynamic;
    27. int stu_add(Stu* stu)
    28. {
    29. if(NULL == stu)
    30. {
    31. return -1;
    32. }
    33. Stu *stuTemp = &g_stuDaynamic;
    34. while(stuTemp->next)
    35. {
    36. stuTemp = stuTemp->next;
    37. }
    38. stuTemp->next = stu;
    39. return 1;
    40. }
    41. //插入数据有序排列
    42. void stu_insert(Stu* new)
    43. {
    44. Stu* previous;
    45. Stu* current;
    46. Stu* next;
    47. previous = &g_stuDaynamic;
    48. current = g_stuDaynamic.next;
    49. while(current->next != NULL && current->score <= new->score )
    50. {
    51. previous = current;
    52. current = current->next;
    53. }
    54. if(current->next == NULL)
    55. {
    56. current->next = new;
    57. }
    58. else
    59. {
    60. previous->next = new;
    61. new->next = current;
    62. }
    63. }
    64. int stu_find(Stu* stu, char* name)
    65. {
    66. Stu *temp = stu;
    67. while(NULL == temp)
    68. {
    69. return -1;
    70. }
    71. while(temp)
    72. {
    73. if( strcmp(temp->name, name) == 0)
    74. {
    75. printf("find the record");
    76. printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
    77. return 1;
    78. }
    79. temp = temp->next;
    80. }
    81. printf("find the record Empty!");
    82. }
    83. int stu_modify(const Stu* stu, Stu* stu_modify)
    84. {
    85. if(NULL == stu)
    86. {
    87. return -1;
    88. }
    89. Stu* temp = stu;
    90. while(temp)
    91. {
    92. if(strcmp(temp->name, stu_modify->name) == 0)
    93. {
    94. (*temp).age = stu_modify->age;
    95. (*temp).gender = stu_modify->gender;
    96. (*temp).score = stu_modify->score;
    97. return 1;
    98. }
    99. temp = temp->next;
    100. }
    101. }
    102. //删除
    103. int stu_delete(Stu* stu, char* name)
    104. {
    105. if (NULL == stu)
    106. {
    107. return -1;
    108. }
    109. Stu* temp = stu;
    110. while (temp)
    111. {
    112. if(NULL != temp->next && strcmp(temp->next->name, name) == 0)
    113. {
    114. //目标节点在重点
    115. Stu* traget = temp->next;
    116. Stu* tragetNext = traget->next;
    117. temp->next = tragetNext;
    118. free(traget);
    119. printf("已找到记录并删除\n");
    120. return 1;
    121. }
    122. temp = temp->next;
    123. }
    124. printf("未找到可删除记录\n");
    125. return 0;
    126. }
    127. void printStu(Stu* stu)
    128. {
    129. Stu* temp = stu->next;
    130. printf("打印学生信息\n");
    131. while(temp)
    132. {
    133. printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
    134. temp = temp->next;
    135. }
    136. }
    137. int action_add()
    138. {
    139. char name[10] = {'\0'};
    140. int age;
    141. int score;
    142. Gend gender;
    143. printf("输入姓名, 年龄, 性别, 分数\n");
    144. scanf("%s %d %d %d", name, &age, &gender, &score);
    145. Stu* stu_new = (Stu*)malloc(sizeof(Stu));
    146. if(NULL == stu_new)
    147. {
    148. printf("malloc fail");
    149. return -1;
    150. }
    151. memcpy(stu_new->name, name, 10);
    152. stu_new->age = age;
    153. stu_new->score = score;
    154. stu_new->gender = gender;
    155. stu_new->next = NULL;
    156. stu_add(stu_new);
    157. printStu(&g_stuDaynamic);
    158. }
    159. //插入数据进行有序排列
    160. int action_insert()
    161. {
    162. char name[10] = {'\0'};
    163. int age;
    164. int score;
    165. Gend gender;
    166. printf("输入姓名、年龄、性别、分数\n");
    167. scanf("%s %d %d %d", name, &age, &gender, &score);
    168. Stu* stu_new = (Stu*)malloc(sizeof(Stu));
    169. if(NULL == stu_new)
    170. {
    171. printf("malloc fail");
    172. return -1;
    173. }
    174. memcpy(stu_new->name, name, 10);
    175. stu_new->age = age;
    176. stu_new->score = score;
    177. stu_new->gender = gender;
    178. stu_new->next = NULL;
    179. stu_insert(stu_new);
    180. printStu(&g_stuDaynamic);
    181. }
    182. int action_find(char* name)
    183. {
    184. stu_find(&g_stuDaynamic, name);
    185. return 0;
    186. }
    187. int action_modify()
    188. {
    189. char name[10] = {'\0'};
    190. int age;
    191. int score;
    192. Gend gender;
    193. Stu *stu_modify_new = (Stu*)malloc(sizeof(Stu));
    194. if(NULL == stu_modify_new)
    195. {
    196. printf("malloc fail");
    197. return -1;
    198. }
    199. printf("输入修改的姓名, 年龄, 性别, 分数\n");
    200. scanf("%s %d %d %d", name, &age, &gender, &score);
    201. memcpy(stu_modify_new->name, name, 10);
    202. stu_modify_new->age = age;
    203. stu_modify_new->score = score;
    204. stu_modify_new->gender = gender;
    205. stu_modify(&g_stuDaynamic, stu_modify_new);
    206. free(stu_modify_new);
    207. printStu(&g_stuDaynamic);
    208. return 1;
    209. }
    210. int action_delete()
    211. {
    212. printf("输入需要删除的记录:\n");
    213. char* name[100];
    214. scanf("%s", name);
    215. stu_delete(&g_stuDaynamic, name);
    216. printStu(&g_stuDaynamic);
    217. return 0;
    218. }
    219. bool isTargetAlpha(char c)
    220. {
    221. if(toupper(c) == 'A' || toupper(c) == 'D' || toupper(c) == 'C' || toupper(c) == 'F' || toupper(c) == 'Q' || toupper(c) == 'I')
    222. {
    223. return true;
    224. }
    225. return false;
    226. }
    227. //int i = 0;
    228. //
    229. //void add() const
    230. //{
    231. // i++;
    232. //}
    233. int list_func()
    234. {
    235. // add();
    236. bool m_flag = true;
    237. if(NULL == g_stuDaynamic.next)
    238. {
    239. printf("g_stuDaynamic->next:%p\n", g_stuDaynamic.next);
    240. printf("g_stuDaynamic->next is NULL\n");
    241. }
    242. while(m_flag)
    243. {
    244. printf("选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):\n");
    245. // printf("选择操作(A:增加、D:删除、C、更改:\n");
    246. // printf("hello");
    247. char action[2];
    248. scanf("%s", action);
    249. if(!isTargetAlpha(action[0]))
    250. {
    251. continue;
    252. }
    253. switch(toupper(action[0]))
    254. {
    255. case 'A':
    256. {
    257. action_add();
    258. break;
    259. }
    260. case 'F':
    261. {
    262. printf("输入查询的姓名:\n");
    263. char name[100];
    264. scanf("%s", name);
    265. action_find(name);
    266. break;
    267. }
    268. case 'C':
    269. {
    270. action_modify();
    271. break;
    272. }
    273. case 'D':
    274. {
    275. action_delete();
    276. break;
    277. }
    278. case 'Q':
    279. {
    280. m_flag = false;
    281. printf("退出\n");
    282. break;
    283. }
    284. //插入数据有序排列
    285. case 'I':
    286. {
    287. action_insert();
    288. break;
    289. }
    290. default:
    291. {
    292. printf("操作有误,请重新输入\n");
    293. break;
    294. }
    295. }
    296. }
    297. return 0;
    298. }
    299. //g_stuDaynamic->next:00000000
    300. //g_stuDaynamic->next is NULL
    301. //选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
    302. //A
    303. //输入姓名, 年龄, 性别, 分数
    304. //zhangs 7 0 77
    305. //打印学生信息
    306. //姓名:zhangs, 年龄:7, 性别:0, 成绩:77
    307. //选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
    308. //A
    309. //输入姓名, 年龄, 性别, 分数
    310. //lilu 8 1 88
    311. //打印学生信息
    312. //姓名:zhangs, 年龄:7, 性别:0, 成绩:77
    313. //姓名:lilu, 年龄:8, 性别:1, 成绩:88
    314. //选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
    315. //A
    316. //输入姓名, 年龄, 性别, 分数
    317. //wangmei 9 1 99
    318. //打印学生信息
    319. //姓名:zhangs, 年龄:7, 性别:0, 成绩:77
    320. //姓名:lilu, 年龄:8, 性别:1, 成绩:88
    321. //姓名:wangmei, 年龄:9, 性别:1, 成绩:99
    322. //选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
    323. //I
    324. //输入姓名、年龄、性别、分数
    325. //xux 6 0 90
    326. //打印学生信息
    327. //姓名:zhangs, 年龄:7, 性别:0, 成绩:77
    328. //姓名:lilu, 年龄:8, 性别:1, 成绩:88
    329. //姓名:wangmei, 年龄:9, 性别:1, 成绩:99
    330. //姓名:xux, 年龄:6, 性别:0, 成绩:90
    331. //选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
    332. //I
    333. //输入姓名、年龄、性别、分数
    334. //xiaom 6 1 80
    335. //打印学生信息
    336. //姓名:zhangs, 年龄:7, 性别:0, 成绩:77
    337. //姓名:xiaom, 年龄:6, 性别:1, 成绩:80
    338. //姓名:lilu, 年龄:8, 性别:1, 成绩:88
    339. //姓名:wangmei, 年龄:9, 性别:1, 成绩:99
    340. //姓名:xux, 年龄:6, 性别:0, 成绩:90
    341. //选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
    342. //I
    343. //输入姓名、年龄、性别、分数
    344. //xiaoh 9 0 83
    345. //打印学生信息
    346. //姓名:zhangs, 年龄:7, 性别:0, 成绩:77
    347. //姓名:xiaom, 年龄:6, 性别:1, 成绩:80
    348. //姓名:xiaoh, 年龄:9, 性别:0, 成绩:83
    349. //姓名:lilu, 年龄:8, 性别:1, 成绩:88
    350. //姓名:wangmei, 年龄:9, 性别:1, 成绩:99
    351. //姓名:xux, 年龄:6, 性别:0, 成绩:90
    352. //选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):

    上面的代码插入尾部的时候会异常,下面的可以正常插入尾部

    1. #include "test.h"
    2. //动态指针
    3. //①枚举类型不会写(成员不会写)
    4. //②结构体指针写法不会写
    5. //③scanf循环
    6. //④scanf用法
    7. //⑤switch-case写法
    8. //⑥strcpy == 0,没有判断是否==0,导致直接打印0
    9. //⑦解决scanf读单个字符会把换行符\n读取,且字符变量中只存了\n
    10. //性别
    11. typedef enum Gender
    12. {
    13. male,
    14. female,
    15. middle
    16. }Gend;
    17. //结构体
    18. typedef struct stu
    19. {
    20. char name[10];
    21. int age;
    22. Gend gender;
    23. int score;
    24. struct stu* next;
    25. }Stu;
    26. Stu g_stuDaynamic;
    27. int stu_add(Stu* stu)
    28. {
    29. if(NULL == stu)
    30. {
    31. return -1;
    32. }
    33. Stu *stuTemp = &g_stuDaynamic;
    34. while(stuTemp->next)
    35. {
    36. stuTemp = stuTemp->next;
    37. }
    38. stuTemp->next = stu;
    39. return 1;
    40. }
    41. //插入数据有序排列
    42. //存在最后一个节点判断异常
    43. void stu_insert1(Stu* new)
    44. {
    45. Stu* previous;
    46. Stu* current;
    47. Stu* next;
    48. previous = &g_stuDaynamic;
    49. current = g_stuDaynamic.next;
    50. while(current->next != NULL && current->score <= new->score )
    51. {
    52. previous = current;
    53. current = current->next;
    54. }
    55. if(current->next == NULL)
    56. {
    57. current->next = new;
    58. }
    59. else
    60. {
    61. previous->next = new;
    62. new->next = current;
    63. }
    64. }
    65. //处理有些复杂
    66. void stu_insert2(Stu* new)
    67. {
    68. Stu* previous;
    69. Stu* current;
    70. Stu* next;
    71. previous = &g_stuDaynamic;
    72. current = g_stuDaynamic.next;
    73. while(current->score <= new->score && current->next != NULL)
    74. {
    75. previous = current;
    76. current = current->next;
    77. }
    78. //这边处理起来有些吃力,感觉需要识别是因为到结尾了还是当前节点大于插入数据
    79. if(current->score > new->score)
    80. {
    81. previous->next = new;
    82. new->next = current;
    83. }
    84. else
    85. {
    86. current->next = new;
    87. }
    88. }
    89. //C和指针照着写
    90. void stu_insert3(Stu* new)
    91. {
    92. Stu* previous;
    93. Stu* current;
    94. Stu* next;
    95. previous = NULL;
    96. current = &g_stuDaynamic;
    97. while(current->score <= new->score && current != NULL)
    98. {
    99. previous = current;
    100. current = current->next;
    101. }
    102. //这边处理起来有些吃力,感觉需要识别是因为到结尾了还是当前节点大于插入数据
    103. if(current->score > new->score)
    104. {
    105. previous->next = new;
    106. new->next = current;
    107. }
    108. else
    109. {
    110. current->next = new;
    111. }
    112. }
    113. //C和指针照着写,程序死机
    114. void stu_insert4(Stu* new)
    115. {
    116. Stu* previous;
    117. Stu* current;
    118. Stu* next;
    119. previous = NULL;
    120. current = &g_stuDaynamic;
    121. while( current->score <= new->score && current != NULL) //这边内存泄漏,访问其他内存,没有先判断current是否为空
    122. {
    123. previous = current;
    124. current = current->next;
    125. }
    126. //这边处理起来有些吃力,感觉需要识别是因为到结尾了还是当前节点大于插入数据
    127. if(current->score > new->score)
    128. {
    129. previous->next = new;
    130. new->next = current;
    131. }
    132. else
    133. {
    134. previous->next = new;
    135. }
    136. }
    137. //C和指针照着写,程序死机
    138. void stu_insert5(Stu* new)
    139. {
    140. Stu* previous;
    141. Stu* current;
    142. Stu* next;
    143. previous = NULL;
    144. current = &g_stuDaynamic;
    145. while( current->score <= new->score && current != NULL) //这边内存泄漏,访问其他内存,没有先判断current是否为空
    146. {
    147. previous = current;
    148. current = current->next;
    149. }
    150. //这边处理起来有些吃力,感觉需要识别是因为到结尾了还是当前节点大于插入数据
    151. if(current->score > new->score) //这边内存泄露,current=NULL时,内存泄漏
    152. {
    153. previous->next = new;
    154. new->next = current;
    155. }
    156. else
    157. {
    158. previous->next = new;
    159. }
    160. }
    161. void stu_insert(Stu* new)
    162. {
    163. Stu* previous;
    164. Stu* current;
    165. Stu* next;
    166. previous = NULL;
    167. current = &g_stuDaynamic;
    168. while(current != NULL && current->score <= new->score)
    169. {
    170. previous = current;
    171. current = current->next;
    172. }
    173. //这边处理起来有些吃力,感觉需要识别是因为到结尾了还是当前节点大于插入数据
    174. if(current == NULL)
    175. {
    176. previous->next = new;
    177. }
    178. else
    179. {
    180. previous->next = new;
    181. new->next = current;
    182. }
    183. }
    184. int stu_find(Stu* stu, char* name)
    185. {
    186. Stu *temp = stu;
    187. while(NULL == temp)
    188. {
    189. return -1;
    190. }
    191. while(temp)
    192. {
    193. if( strcmp(temp->name, name) == 0)
    194. {
    195. printf("find the record");
    196. printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
    197. return 1;
    198. }
    199. temp = temp->next;
    200. }
    201. printf("find the record Empty!");
    202. }
    203. int stu_modify(const Stu* stu, Stu* stu_modify)
    204. {
    205. if(NULL == stu)
    206. {
    207. return -1;
    208. }
    209. Stu* temp = stu;
    210. while(temp)
    211. {
    212. if(strcmp(temp->name, stu_modify->name) == 0)
    213. {
    214. (*temp).age = stu_modify->age;
    215. (*temp).gender = stu_modify->gender;
    216. (*temp).score = stu_modify->score;
    217. return 1;
    218. }
    219. temp = temp->next;
    220. }
    221. }
    222. //删除
    223. int stu_delete(Stu* stu, char* name)
    224. {
    225. if (NULL == stu)
    226. {
    227. return -1;
    228. }
    229. Stu* temp = stu;
    230. while (temp)
    231. {
    232. if(NULL != temp->next && strcmp(temp->next->name, name) == 0)
    233. {
    234. //目标节点在重点
    235. Stu* traget = temp->next;
    236. Stu* tragetNext = traget->next;
    237. temp->next = tragetNext;
    238. free(traget);
    239. printf("已找到记录并删除\n");
    240. return 1;
    241. }
    242. temp = temp->next;
    243. }
    244. printf("未找到可删除记录\n");
    245. return 0;
    246. }
    247. void printStu(Stu* stu)
    248. {
    249. Stu* temp = stu->next;
    250. printf("打印学生信息\n");
    251. while(temp)
    252. {
    253. printf("姓名:%s, 年龄:%d, 性别:%d, 成绩:%d\n", temp->name, temp->age, temp->gender, temp->score);
    254. temp = temp->next;
    255. }
    256. }
    257. int action_add()
    258. {
    259. char name[10] = {'\0'};
    260. int age;
    261. int score;
    262. Gend gender;
    263. printf("输入姓名, 年龄, 性别, 分数\n");
    264. scanf("%s %d %d %d", name, &age, &gender, &score);
    265. Stu* stu_new = (Stu*)malloc(sizeof(Stu));
    266. if(NULL == stu_new)
    267. {
    268. printf("malloc fail");
    269. return -1;
    270. }
    271. memcpy(stu_new->name, name, 10);
    272. stu_new->age = age;
    273. stu_new->score = score;
    274. stu_new->gender = gender;
    275. stu_new->next = NULL;
    276. stu_add(stu_new);
    277. printStu(&g_stuDaynamic);
    278. }
    279. //插入数据进行有序排列
    280. int action_insert()
    281. {
    282. char name[10] = {'\0'};
    283. int age;
    284. int score;
    285. Gend gender;
    286. printf("输入姓名、年龄、性别、分数\n");
    287. scanf("%s %d %d %d", name, &age, &gender, &score);
    288. Stu* stu_new = (Stu*)malloc(sizeof(Stu));
    289. if(NULL == stu_new)
    290. {
    291. printf("malloc fail");
    292. return -1;
    293. }
    294. memcpy(stu_new->name, name, 10);
    295. stu_new->age = age;
    296. stu_new->score = score;
    297. stu_new->gender = gender;
    298. stu_new->next = NULL;
    299. stu_insert(stu_new);
    300. printStu(&g_stuDaynamic);
    301. }
    302. int action_find(char* name)
    303. {
    304. stu_find(&g_stuDaynamic, name);
    305. return 0;
    306. }
    307. int action_modify()
    308. {
    309. char name[10] = {'\0'};
    310. int age;
    311. int score;
    312. Gend gender;
    313. Stu *stu_modify_new = (Stu*)malloc(sizeof(Stu));
    314. if(NULL == stu_modify_new)
    315. {
    316. printf("malloc fail");
    317. return -1;
    318. }
    319. printf("输入修改的姓名, 年龄, 性别, 分数\n");
    320. scanf("%s %d %d %d", name, &age, &gender, &score);
    321. memcpy(stu_modify_new->name, name, 10);
    322. stu_modify_new->age = age;
    323. stu_modify_new->score = score;
    324. stu_modify_new->gender = gender;
    325. stu_modify(&g_stuDaynamic, stu_modify_new);
    326. free(stu_modify_new);
    327. printStu(&g_stuDaynamic);
    328. return 1;
    329. }
    330. int action_delete()
    331. {
    332. printf("输入需要删除的记录:\n");
    333. char* name[100];
    334. scanf("%s", name);
    335. stu_delete(&g_stuDaynamic, name);
    336. printStu(&g_stuDaynamic);
    337. return 0;
    338. }
    339. bool isTargetAlpha(char c)
    340. {
    341. if(toupper(c) == 'A' || toupper(c) == 'D' || toupper(c) == 'C' || toupper(c) == 'F' || toupper(c) == 'Q' || toupper(c) == 'I')
    342. {
    343. return true;
    344. }
    345. return false;
    346. }
    347. int list_func()
    348. {
    349. bool m_flag = true;
    350. if(NULL == g_stuDaynamic.next)
    351. {
    352. printf("g_stuDaynamic->next:%p\n", g_stuDaynamic.next);
    353. printf("g_stuDaynamic->next is NULL\n");
    354. }
    355. while(m_flag)
    356. {
    357. printf("选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):\n");
    358. char action[2];
    359. scanf("%s", action);
    360. if(!isTargetAlpha(action[0]))
    361. {
    362. continue;
    363. }
    364. switch(toupper(action[0]))
    365. {
    366. case 'A':
    367. {
    368. action_add();
    369. break;
    370. }
    371. case 'F':
    372. {
    373. printf("输入查询的姓名:\n");
    374. char name[100];
    375. scanf("%s", name);
    376. action_find(name);
    377. break;
    378. }
    379. case 'C':
    380. {
    381. action_modify();
    382. break;
    383. }
    384. case 'D':
    385. {
    386. action_delete();
    387. break;
    388. }
    389. case 'Q':
    390. {
    391. m_flag = false;
    392. printf("退出\n");
    393. break;
    394. }
    395. //插入数据有序排列
    396. case 'I':
    397. {
    398. action_insert();
    399. break;
    400. }
    401. default:
    402. {
    403. printf("操作有误,请重新输入\n");
    404. break;
    405. }
    406. }
    407. }
    408. return 0;
    409. }
    410. //g_stuDaynamic->next:00000000
    411. //g_stuDaynamic->next is NULL
    412. //选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
    413. //A
    414. //输入姓名, 年龄, 性别, 分数
    415. //zhangs 7 0 77
    416. //打印学生信息
    417. //姓名:zhangs, 年龄:7, 性别:0, 成绩:77
    418. //选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
    419. //A
    420. //输入姓名, 年龄, 性别, 分数
    421. //lilu 8 1 88
    422. //打印学生信息
    423. //姓名:zhangs, 年龄:7, 性别:0, 成绩:77
    424. //姓名:lilu, 年龄:8, 性别:1, 成绩:88
    425. //选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
    426. //A
    427. //输入姓名, 年龄, 性别, 分数
    428. //wangmei 9 0 99
    429. //打印学生信息
    430. //姓名:zhangs, 年龄:7, 性别:0, 成绩:77
    431. //姓名:lilu, 年龄:8, 性别:1, 成绩:88
    432. //姓名:wangmei, 年龄:9, 性别:0, 成绩:99
    433. //选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):
    434. //I
    435. //输入姓名、年龄、性别、分数
    436. //lili 5 1 101
    437. //打印学生信息
    438. //姓名:zhangs, 年龄:7, 性别:0, 成绩:77
    439. //姓名:lilu, 年龄:8, 性别:1, 成绩:88
    440. //姓名:wangmei, 年龄:9, 性别:0, 成绩:99
    441. //姓名:lili, 年龄:5, 性别:1, 成绩:101
    442. //选择操作(A:增加、D:删除、C:更改、F:查找、Q:退出):

    几经波折啊!

    3.2.2.2.2 阶段2

    现在可以实现数据的增加、插入、删除、查找、修改了。但是离C和指针还有一些 差别或者差距。

    差距在于我这个目前使用的是一个全局链表变量。所以所有的程序只能针对于这个链表运行。因为函数中写死了链表变量。

    所以这是我又想到一个点。就是怎么叫解耦或者什么叫解耦。那就是函数中不能出现全局变量或者写死某个值或变量。

    我的这段代码就是没有解耦,比如stu_insert函数中就出现这样的代码

    1. previous = &g_stuDaynamic;
    2. current = g_stuDaynamic.next;

    高度耦合。

    所以后面的代码修改方向就是需要解耦。

    3.2.2.3 解耦代码

    2024年1月16日 11:16:16

    下面是解耦的代码,

    搞的头炸啊!

    //lianbiao.c文件

    1. #include "lianbiao.h"
    2. void func()
    3. {
    4. printf("hello\n");
    5. }
    6. bool isTargetCharacter(char* choose)
    7. {
    8. if(choose[0] == 'A' || choose[0] == 'I' || choose[0] == 'D' || choose[0] == 'M' || choose[0] == 'F')
    9. {
    10. return true;
    11. }
    12. return false;
    13. }
    14. //这边printf也是有问题的,我也是把跟指针当做value=0在用,从第二个节点开始打印。同理,我的add函数也是等于是从value=0结构后面加的
    15. void print_lianbiao(lianbiao* stu)
    16. {
    17. lianbiao* root = stu;
    18. lianbiao* current = root->next;
    19. while(current != NULL)
    20. {
    21. printf("姓名:%s,年龄:%d,性别:%d,成绩:%d\n", current->name, current->age, current->gender, current->score);
    22. current = current->next;
    23. }
    24. }
    25. int stu_add1(lianbiao* stu, lianbiao* new_stu)
    26. {
    27. while(stu == NULL)
    28. {
    29. return 0;
    30. }
    31. lianbiao* previous = stu;
    32. lianbiao** current = &previous->next;
    33. while(*current != NULL)
    34. {
    35. *current = (*current)->next;
    36. }
    37. *current = new_stu;
    38. return 1;
    39. }
    40. int stu_add2(lianbiao* stu, lianbiao* new_stu)
    41. {
    42. while(stu == NULL)
    43. {
    44. return 0;
    45. }
    46. lianbiao* previous = stu;
    47. lianbiao* current = previous->next;
    48. while(current != NULL)
    49. {
    50. current = current->next;
    51. }
    52. lianbiao** p = ¤t;
    53. *p = new_stu;
    54. return 1;
    55. }
    56. //吊毛,槽,这样写竟然就可以了,妈的,自己捣鼓一晚上都没弄好。看了书就好了
    57. int stu_add(lianbiao* stu, lianbiao* new_stu)
    58. {
    59. while(stu == NULL)
    60. {
    61. return 0;
    62. }
    63. lianbiao* previous = stu; //stu是二级指针,解引用一次,里面的成员都可以被成功赋值
    64. lianbiao* current = previous->next; //现在复盘,大概是previous->next可以被赋值。但是现在的操作是previous->next赋值给previous,再去更改previous的值就更改不了next的值
    65. while(current != NULL)
    66. {
    67. previous = current;
    68. current = current->next;
    69. }
    70. previous->next = new_stu;
    71. return 1;
    72. }
    73. int action_add(lianbiao* stu_lianbiao)
    74. {
    75. char name[10];
    76. int age;
    77. int gender;
    78. int score;
    79. //lianbiao stu; //这边好像不能写局部变量,栈上申请内存,感觉每次的地址是一样的额
    80. printf("输入需要增加(add)的数据, age=0时退出add操作:\n");
    81. while(1)
    82. {
    83. printf("输入姓名、年龄、性别、成绩\n");
    84. scanf("%s %d %d %d", name, &age, &gender, &score);
    85. if(age == 0)
    86. {
    87. break;
    88. }
    89. lianbiao* stu = (lianbiao*)malloc(sizeof(lianbiao));
    90. strcpy(stu->name, name);
    91. stu->age = age;
    92. stu->gender = gender;
    93. stu->score = score;
    94. stu->next = NULL; //忘了写
    95. if(stu_add(stu_lianbiao, stu))
    96. {
    97. printf("添加成功\n");
    98. }
    99. }
    100. print_lianbiao(stu_lianbiao);
    101. printf("结束添加add操作\n");
    102. }
    103. //这个没有传入根指针的二级指针,竟然也成功了
    104. //我是把根指针当做一个value=0的节点在用了,所以都是在后面add
    105. int stu_insert(lianbiao* stu, lianbiao* new_stu)
    106. {
    107. if(stu == NULL)
    108. {
    109. return 0;
    110. }
    111. lianbiao* previous = NULL;
    112. lianbiao* current = stu;
    113. while(current != NULL && current->score < new_stu->score) //这个地方关于current->score < new_stu->score我是存在疑问的。但是实际调试的时候score的值是0.只能理解为全局变量会被初始化为0
    114. {
    115. previous = current;
    116. current = current->next;
    117. }
    118. if(current == NULL) //这边我还是没有真正的理解书中表达的意思。这边应该写成previous == NULL
    119. {
    120. previous->next = new_stu;
    121. }
    122. else
    123. {
    124. previous->next = new_stu;
    125. new_stu->next = current;
    126. }
    127. return 1;
    128. }
    129. void action_insert(lianbiao* stu_lianbiao)
    130. {
    131. char name[10];
    132. int age;
    133. int gender;
    134. int score;
    135. printf("输入需要插入(insert)的数据, age=0时退出insert操作:\n");
    136. while(1)
    137. {
    138. printf("输入姓名、年龄、性别、成绩\n");
    139. scanf("%s %d %d %d", name, &age, &gender, &score);
    140. if(age == 0)
    141. {
    142. break;
    143. }
    144. lianbiao* stu = (lianbiao*)malloc(sizeof(lianbiao));
    145. strcpy(stu->name, name);
    146. stu->age = age;
    147. stu->gender = gender;
    148. stu->score = score;
    149. stu->next = NULL; //忘了写
    150. if(stu_insert(stu_lianbiao, stu))
    151. {
    152. printf("添加成功\n");
    153. print_lianbiao(stu_lianbiao);
    154. }
    155. }
    156. printf("结束添加add操作\n");
    157. }
    158. void stu_list_func(lianbiao* stu_lianbiao)
    159. {
    160. bool flag = true;
    161. char choose[10];
    162. printf("欢迎进入学生信息管理系统\n");
    163. while(flag)
    164. {
    165. printf("选择操作A:增加、I:插入、D:删除、M:修改、F:查找\n");
    166. scanf("%s", choose);
    167. if(!isTargetCharacter(choose))
    168. {
    169. continue;
    170. }
    171. switch(choose[0])
    172. {
    173. case 'A':
    174. {
    175. action_add(stu_lianbiao);
    176. break;
    177. }
    178. case 'I':
    179. {
    180. action_insert(stu_lianbiao);
    181. break;
    182. }
    183. case 'D':
    184. {
    185. break;
    186. }
    187. case 'M':
    188. {
    189. break;
    190. }
    191. case 'F':
    192. {
    193. break;
    194. }
    195. case 'Q':
    196. {
    197. flag = false;
    198. break;
    199. }
    200. default:
    201. {
    202. break;
    203. }
    204. }
    205. }
    206. }
    207. //D:\APP\codeBlock\ADTlianbiao\main.c
    208. //12, 7
    209. //Hello world!
    210. //欢迎进入学生信息管理系统
    211. //选择操作A:增加、I:插入、D:删除、M:修改、F:查找
    212. //A
    213. //输入需要增加(add)的数据, age=0时退出add操作:
    214. //输入姓名、年龄、性别、成绩
    215. //zhangs 7 0 77
    216. //添加成功
    217. //输入姓名、年龄、性别、成绩
    218. //lilu 8 1 88
    219. //添加成功
    220. //输入姓名、年龄、性别、成绩
    221. //wangmei 9 0 99
    222. //添加成功
    223. //输入姓名、年龄、性别、成绩
    224. //bv 0 0 0
    225. //姓名:zhangs,年龄:7,性别:0,成绩:77
    226. //姓名:lilu,年龄:8,性别:1,成绩:88
    227. //姓名:wangmei,年龄:9,性别:0,成绩:99
    228. //结束添加add操作
    229. //选择操作A:增加、I:插入、D:删除、M:修改、F:查找
    230. //I
    231. //输入需要插入(insert)的数据, age=0时退出insert操作:
    232. //输入姓名、年龄、性别、成绩
    233. //xiaoming 6 0 66
    234. //添加成功
    235. //姓名:xiaoming,年龄:6,性别:0,成绩:66
    236. //姓名:zhangs,年龄:7,性别:0,成绩:77
    237. //姓名:lilu,年龄:8,性别:1,成绩:88
    238. //姓名:wangmei,年龄:9,性别:0,成绩:99
    239. //输入姓名、年龄、性别、成绩
    240. //xiaohong 9 1 101
    241. //添加成功
    242. //姓名:xiaoming,年龄:6,性别:0,成绩:66
    243. //姓名:zhangs,年龄:7,性别:0,成绩:77
    244. //姓名:lilu,年龄:8,性别:1,成绩:88
    245. //姓名:wangmei,年龄:9,性别:0,成绩:99
    246. //姓名:xiaohong,年龄:9,性别:1,成绩:101
    247. //输入姓名、年龄、性别、成绩
    248. //xc 0 0 0
    249. //结束添加add操作

    //lianbiao.h

    1. #ifndef LIANBIAO_H
    2. #define LIANBIAO_H
    3. #include "stdio.h"
    4. #include
    5. #include
    6. typedef struct Lianbiao
    7. {
    8. char name[10];
    9. int age;
    10. int gender;
    11. int score;
    12. struct Lianbiao* next;
    13. }lianbiao;
    14. typedef struct TEST
    15. {
    16. int a;
    17. int* p;
    18. }Test;
    19. void func();
    20. void stu_list_func(lianbiao* stu_lianbiao);
    21. #endif // LIANBIAO_H

    //main.c

    1. #include
    2. #include
    3. #include "lianbiao.h"
    4. lianbiao g_stu_lianbiao;
    5. int testFun(Test* test)
    6. {
    7. test->a = 12;
    8. int* b = (int*)malloc(sizeof(int));
    9. *b = 7;
    10. int* p = test->p;
    11. p = b; //这样写不能正常赋值
    12. int **q = &(test->p); //不需要加括号,->运算符优先级高于&和*
    13. *q = b; //这样写可以正常赋值
    14. }
    15. int main()
    16. {
    17. printf("%s\n", __FILE__);
    18. Test test;
    19. testFun(&test);
    20. printf("%d, %d", test.a, *test.p);
    21. printf("Hello world!\n");
    22. int *p = &g_stu_lianbiao;
    23. stu_list_func(&g_stu_lianbiao);
    24. return 0;
    25. }

    看打印记录感觉代码正常运行了。实际上上面的代码还是有问题,那就是我一直都其实没有理解根节点指针(rootp)是什么意思。在上面的diamante中,我其实一直都是这么用的。那就是将根节点指针指向的value=0的节点当做跟指针在用。(实际上g_stu_lianbiao的初始化就是0)。

    这也是我为什么打印的时候会跳过一个节点,写的奇奇怪怪。

    1. lianbiao* root = stu;
    2. lianbiao* current = root->next;

    上面显示我把root->next当做current。root->score所在的节点被我跳过了。

    3.2.2.4 解耦阶段二

    //lianbiao.h

    1. #ifndef LIANBIAO_H
    2. #define LIANBIAO_H
    3. #include "stdio.h"
    4. #include
    5. #include
    6. typedef struct Lianbiao
    7. {
    8. char name[10];
    9. int age;
    10. int gender;
    11. int score;
    12. struct Lianbiao* next;
    13. }lianbiao;
    14. typedef struct TEST
    15. {
    16. int a;
    17. int* p;
    18. }Test;
    19. void func();
    20. void stu_list_func(lianbiao** stu_lianbiao);
    21. #endif // LIANBIAO_H

    //lianbiao.c

    1. #include "lianbiao.h"
    2. void func()
    3. {
    4. printf("hello\n");
    5. }
    6. bool isTargetCharacter(char* choose)
    7. {
    8. if(choose[0] == 'A' || choose[0] == 'I' || choose[0] == 'D' || choose[0] == 'M' || choose[0] == 'F')
    9. {
    10. return true;
    11. }
    12. return false;
    13. }
    14. //这边printf也是有问题的,我也是把跟指针当做value=0在用,从第二个节点开始打印。同理,我的add函数也是等于是从value=0结构后面加的
    15. void print_lianbiao1(lianbiao* stu)
    16. {
    17. lianbiao* root = stu;
    18. lianbiao* current = root->next;
    19. while(current != NULL)
    20. {
    21. printf("姓名:%s,年龄:%d,性别:%d,成绩:%d\n", current->name, current->age, current->gender, current->score);
    22. current = current->next;
    23. }
    24. }
    25. void print_lianbiao(lianbiao** stu)
    26. {
    27. lianbiao* current = *stu;
    28. while(current != NULL)
    29. {
    30. printf("姓名:%s,年龄:%d,性别:%d,成绩:%d\n", current->name, current->age, current->gender, current->score);
    31. current = current->next;
    32. }
    33. }
    34. int stu_add1(lianbiao* stu, lianbiao* new_stu)
    35. {
    36. while(stu == NULL)
    37. {
    38. return 0;
    39. }
    40. lianbiao* previous = stu;
    41. lianbiao** current = &previous->next;
    42. while(*current != NULL)
    43. {
    44. *current = (*current)->next;
    45. }
    46. *current = new_stu;
    47. return 1;
    48. }
    49. int stu_add2(lianbiao* stu, lianbiao* new_stu)
    50. {
    51. while(stu == NULL)
    52. {
    53. return 0;
    54. }
    55. lianbiao* previous = stu;
    56. lianbiao* current = previous->next;
    57. while(current != NULL)
    58. {
    59. current = current->next;
    60. }
    61. lianbiao** p = ¤t;
    62. *p = new_stu;
    63. return 1;
    64. }
    65. //吊毛,槽,这样写竟然就可以了,妈的,自己捣鼓一晚上都没弄好。看了书就好了
    66. int stu_add3(lianbiao* stu, lianbiao* new_stu)
    67. {
    68. while(stu == NULL)
    69. {
    70. return 0;
    71. }
    72. lianbiao* previous = stu; //stu是二级指针,解引用一次,里面的成员都可以被成功赋值
    73. lianbiao* current = previous->next; //现在复盘,大概是previous->next可以被赋值。但是现在的操作是previous->next赋值给previous,再去更改previous的值就更改不了next的值
    74. while(current != NULL)
    75. {
    76. previous = current;
    77. current = current->next;
    78. }
    79. previous->next = new_stu;
    80. return 1;
    81. }
    82. int stu_add(lianbiao** stu, lianbiao* new_stu)
    83. {
    84. while(stu == NULL)
    85. {
    86. return 0;
    87. }
    88. lianbiao* previous = NULL; //stu是二级指针,解引用一次,里面的成员都可以被成功赋值
    89. lianbiao* current = *stu; //现在复盘,大概是previous->next可以被赋值。但是现在的操作是previous->next赋值给previous,再去更改previous的值就更改不了next的值
    90. while(current != NULL)
    91. {
    92. previous = current;
    93. current = current->next;
    94. }
    95. if(previous == NULL)
    96. {
    97. *stu = new_stu;
    98. }
    99. else
    100. {
    101. previous->next = new_stu;
    102. new_stu->next = current;
    103. }
    104. return 1;
    105. }
    106. int action_add(lianbiao** stu_lianbiao)
    107. {
    108. char name[10];
    109. int age;
    110. int gender;
    111. int score;
    112. //lianbiao stu; //这边好像不能写局部变量,栈上申请内存,感觉每次的地址是一样的额
    113. printf("输入需要增加(add)的数据, age=0时退出add操作:\n");
    114. while(1)
    115. {
    116. printf("输入姓名、年龄、性别、成绩\n");
    117. scanf("%s %d %d %d", name, &age, &gender, &score);
    118. if(age == 0)
    119. {
    120. break;
    121. }
    122. lianbiao* stu = (lianbiao*)malloc(sizeof(lianbiao));
    123. strcpy(stu->name, name);
    124. stu->age = age;
    125. stu->gender = gender;
    126. stu->score = score;
    127. stu->next = NULL; //忘了写
    128. if(stu_add(stu_lianbiao, stu))
    129. {
    130. printf("添加成功\n");
    131. print_lianbiao(stu_lianbiao);
    132. }
    133. }
    134. printf("结束添加add操作\n");
    135. }
    136. //这个没有传入根指针的二级指针,竟然也成功了
    137. //我是把根指针当做一个value=0的节点在用了,所以都是在后面add
    138. int stu_insert1(lianbiao* stu, lianbiao* new_stu)
    139. {
    140. if(stu == NULL)
    141. {
    142. return 0;
    143. }
    144. lianbiao* previous = NULL;
    145. lianbiao* current = stu;
    146. while(current != NULL && current->score < new_stu->score) //这个地方关于current->score < new_stu->score我是存在疑问的。但是实际调试的时候score的值是0.只能理解为全局变量会被初始化为0
    147. {
    148. previous = current;
    149. current = current->next;
    150. }
    151. if(current == NULL) //这边我还是没有真正的理解书中表达的意思。这边应该写成previous == NULL
    152. {
    153. previous->next = new_stu;
    154. }
    155. else
    156. {
    157. previous->next = new_stu;
    158. new_stu->next = current;
    159. }
    160. return 1;
    161. }
    162. int stu_insert(lianbiao** stu, lianbiao* new_stu)
    163. {
    164. if(stu == NULL)
    165. {
    166. return 0;
    167. }
    168. lianbiao* previous = NULL;
    169. lianbiao* current = *stu;
    170. while(current != NULL && current->score < new_stu->score) //这个地方关于current->score < new_stu->score我是存在疑问的。但是实际调试的时候score的值是0.只能理解为全局变量会被初始化为0
    171. {
    172. previous = current;
    173. current = current->next;
    174. }
    175. if(previous == NULL) //这边我还是没有真正的理解书中表达的意思。这边应该写成previous == NULL
    176. {
    177. *stu = new_stu;
    178. }
    179. else
    180. {
    181. previous->next = new_stu;
    182. }
    183. new_stu->next = current; //靠这个一直没在意,调试的时候才发现
    184. return 1;
    185. }
    186. void action_insert(lianbiao* stu_lianbiao)
    187. {
    188. char name[10];
    189. int age;
    190. int gender;
    191. int score;
    192. printf("输入需要插入(insert)的数据, age=0时退出insert操作:\n");
    193. while(1)
    194. {
    195. printf("输入姓名、年龄、性别、成绩\n");
    196. scanf("%s %d %d %d", name, &age, &gender, &score);
    197. if(age == 0)
    198. {
    199. break;
    200. }
    201. lianbiao* stu = (lianbiao*)malloc(sizeof(lianbiao));
    202. strcpy(stu->name, name);
    203. stu->age = age;
    204. stu->gender = gender;
    205. stu->score = score;
    206. stu->next = NULL; //忘了写
    207. if(stu_insert(stu_lianbiao, stu))
    208. {
    209. printf("添加成功\n");
    210. print_lianbiao(stu_lianbiao);
    211. }
    212. }
    213. printf("结束添加add操作\n");
    214. }
    215. void stu_list_func(lianbiao** stu_lianbiao)
    216. {
    217. bool flag = true;
    218. char choose[10];
    219. printf("欢迎进入学生信息管理系统\n");
    220. while(flag)
    221. {
    222. printf("选择操作A:增加、I:插入、D:删除、M:修改、F:查找\n");
    223. scanf("%s", choose);
    224. if(!isTargetCharacter(choose))
    225. {
    226. continue;
    227. }
    228. switch(choose[0])
    229. {
    230. case 'A':
    231. {
    232. action_add(stu_lianbiao);
    233. break;
    234. }
    235. case 'I':
    236. {
    237. action_insert(stu_lianbiao);
    238. break;
    239. }
    240. case 'D':
    241. {
    242. break;
    243. }
    244. case 'M':
    245. {
    246. break;
    247. }
    248. case 'F':
    249. {
    250. break;
    251. }
    252. case 'Q':
    253. {
    254. flag = false;
    255. break;
    256. }
    257. default:
    258. {
    259. break;
    260. }
    261. }
    262. }
    263. }
    264. //D:\APP\codeBlock\ADTlianbiao\main.c
    265. //12, 7
    266. //Hello world!
    267. //欢迎进入学生信息管理系统
    268. //选择操作A:增加、I:插入、D:删除、M:修改、F:查找
    269. //A
    270. //输入需要增加(add)的数据, age=0时退出add操作:
    271. //输入姓名、年龄、性别、成绩
    272. //zhangs 7 0 77
    273. //添加成功
    274. //姓名:zhangs,年龄:7,性别:0,成绩:77
    275. //输入姓名、年龄、性别、成绩
    276. //lilu 8 1 88
    277. //添加成功
    278. //姓名:zhangs,年龄:7,性别:0,成绩:77
    279. //姓名:lilu,年龄:8,性别:1,成绩:88
    280. //输入姓名、年龄、性别、成绩
    281. //wangmei 9 0 99
    282. //添加成功
    283. //姓名:zhangs,年龄:7,性别:0,成绩:77
    284. //姓名:lilu,年龄:8,性别:1,成绩:88
    285. //姓名:wangmei,年龄:9,性别:0,成绩:99
    286. //输入姓名、年龄、性别、成绩
    287. //vc 0 0 0
    288. //结束添加add操作
    289. //选择操作A:增加、I:插入、D:删除、M:修改、F:查找
    290. //I
    291. //输入需要插入(insert)的数据, age=0时退出insert操作:
    292. //输入姓名、年龄、性别、成绩
    293. //xiaoming 6 0 66
    294. //添加成功
    295. //姓名:xiaoming,年龄:6,性别:0,成绩:66
    296. //姓名:zhangs,年龄:7,性别:0,成绩:77
    297. //姓名:lilu,年龄:8,性别:1,成绩:88
    298. //姓名:wangmei,年龄:9,性别:0,成绩:99
    299. //输入姓名、年龄、性别、成绩
    300. //hanxue 9 1 102
    301. //添加成功
    302. //姓名:xiaoming,年龄:6,性别:0,成绩:66
    303. //姓名:zhangs,年龄:7,性别:0,成绩:77
    304. //姓名:lilu,年龄:8,性别:1,成绩:88
    305. //姓名:wangmei,年龄:9,性别:0,成绩:99
    306. //姓名:hanxue,年龄:9,性别:1,成绩:102
    307. //输入姓名、年龄、性别、成绩
    308. //wuhu 7 0 82
    309. //添加成功
    310. //姓名:xiaoming,年龄:6,性别:0,成绩:66
    311. //姓名:zhangs,年龄:7,性别:0,成绩:77
    312. //姓名:wuhu,年龄:7,性别:0,成绩:82
    313. //姓名:lilu,年龄:8,性别:1,成绩:88
    314. //姓名:wangmei,年龄:9,性别:0,成绩:99
    315. //姓名:hanxue,年龄:9,性别:1,成绩:102
    316. //输入姓名、年龄、性别、成绩
    317. //vc 0 0 0
    318. //结束添加add操作
    319. //选择操作A:增加、I:插入、D:删除、M:修改、F:查找

    //main.c

    1. #include
    2. #include
    3. #include "lianbiao.h"
    4. lianbiao* g_stu_lianbiao = NULL;
    5. int testFun(Test* test)
    6. {
    7. test->a = 12;
    8. int* b = (int*)malloc(sizeof(int));
    9. *b = 7;
    10. int* p = test->p;
    11. p = b; //这样写不能正常赋值
    12. // int **q = &(test->p); //不需要加括号,->运算符优先级高于&和*
    13. // *q = b; //这样写可以正常赋值
    14. test->p = b; //离谱的是,这样也可以更改结构体中指针的值
    15. }
    16. //这里的问题是test是个指针,指向一块内存。test指针指向的内存中的数据可以更改。因为确实是对真实内存进行修改
    17. //链表中的问题是,更改根节点的值。指针的值是值传递,无法修改。所以要传递地址的地址
    18. int main()
    19. {
    20. printf("%s\n", __FILE__);
    21. Test test;
    22. testFun(&test);
    23. printf("%d, %d\n", test.a, *test.p);
    24. printf("Hello world!\n");
    25. int *p = &g_stu_lianbiao;
    26. stu_list_func(&g_stu_lianbiao);
    27. return 0;
    28. }

    上面的代码就实现了C和指针里面的链表。

    2024年1月17日09:36:36

    今天还回顾了一下链表,理了一下,下面的是画的图

    所以对malloc也理解了一些。就是malloc申请了一块内存空间。用一个指针p指向那块内存。 

    四、编译报错处理

    4.1 报错1

    implicit declaration of function 'toupper' [-Wimplicit-function-declaration]

    加上头文件"ctype.h"就不报错了。但是按理没有加头文件程序不能执行啊。但是没有头文件程序也是正常执行了。

    翻译:函数'toupper'的隐式声明


    总结

    提示:这里对文章进行总结:
    例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

  • 相关阅读:
    unordered_map的键值不能直接用pair;而map 可以使用 pair 作为键值,而不需要额外定义哈希函数
    OpenJudge NOI 1.13 51:古代密码
    node 第十九天 使用node插件node-jsonwebtoken实现身份令牌jwt认证
    天翼物联与华为联合发布5GtoB终端认证标准2.0
    Leecode专题——回溯系列
    (二)Three光线检测-实现摄像机向鼠标点击位置滑动动画
    MySQL、高级SQL操作
    Unity-Input System新输入系统插件学习
    基于Springboot实现网上商城管理系统演示【项目源码+论文说明】
    消息队列MQ
  • 原文地址:https://blog.csdn.net/2301_77560238/article/details/133673397