• 数据结构——通讯录项目


    1.通讯录的介绍

    顺序表是通讯录的底层结构。

    通讯录是将顺序表的类型替换成结构体类型来储存用户数据,通过运用顺序表结构来实现的。

    用户数据结构:

    1. typedef struct PersonInfo
    2. {
    3. char name[12];
    4. char sex[10];
    5. int age;
    6. char tel[11];
    7. char addr[100];
    8. }PeoInfo;

    2. 通讯录功能的实现

    2.1 构建菜单

    将通讯录的所有功能都一一列出来,让用户一目了然。

    Contact.c:

    1. void menu()
    2. {
    3. printf("*******************************************\n");
    4. printf("******* 1.添加联系人 2.查找联系人 ******\n");
    5. printf("******* 1.修改联系人 2.删除联系人 ******\n");
    6. printf("******* 1.查看通讯录 0.退出通讯录 ******\n");
    7. printf("*******************************************\n");
    8. }

    测试结果如下:

     2.2 构建选择操作

    Contact.c:

    1. int op = -1;
    2. do {
    3. menu();
    4. printf("请选择您的操作:\n");
    5. scanf("%d", &op);
    6. switch (op)
    7. {
    8. case 1:
    9. //添加联系人
    10. break;
    11. case 2:
    12. //查找联系人
    13. break;
    14. case 3:
    15. //修改联系人
    16. break;
    17. case 4:
    18. //删除联系人
    19. break;
    20. case 5:
    21. //查看通讯录
    22. break;
    23. case 0:
    24. //退出通讯录
    25. printf("通讯录退出中.....\n");
    26. break;
    27. }
    28. } while(op);

     测试结果如下:

     2.3 构建通讯录数据类型

    Contact.c:

    1. typedef struct PersonInfo
    2. {
    3. char name[NAME_MAX];//使用宏便于后期修改代码
    4. char sex[SEX_MAX];
    5. int age;
    6. char tel[TEL_MAX];
    7. char addr[ADDR_MAX];
    8. }PeoInfo;

    2.4 通讯录的初始化和销毁

    Contact.h:

    1. //初始化通讯录
    2. void InitContact(contact* con);//实际初始化的是顺序表
    3. //销毁通讯录数据
    4. void DestroyContact(contact* con);

    Contact.c:

    1. void InitContact(contact* con)
    2. {
    3. SLInit(con);
    4. }
    5. void DestroyContact(contact* con)
    6. {
    7. SLDestory(con);
    8. }

    2.5 增加联系人

    Contact.h:

    void AddContact(contact* con);

    Contact.c:

    1. void AddContact(contact* con)
    2. {
    3. SLCheckCapacity(con);
    4. printf("请输入联系人姓名:\n");
    5. scanf("%s", con->arr[con->size].name);
    6. printf("请输入联系人性别:\n");
    7. scanf("%s", con->arr[con->size].sex);
    8. printf("请输入联系人年龄:\n");
    9. scanf("%d", &con->arr[con->size].age);
    10. printf("请输入联系人电话:\n");
    11. scanf("%s", con->arr[con->size].tel);
    12. printf("请输入联系人住址:\n");
    13. scanf("%s", con->arr[con->size].addr);
    14. con->size++;
    15. }

    测试结果如下:

    2.6 展示联系人

    Contact.h:

    void ShowContact(contact* con);

    Contact.c:

    1. void ShowContact(contact* con) {
    2. printf("%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");
    3. for (int i = 0; i < con->size; i++)
    4. {
    5. printf("%s %s %d %s %s\n",
    6. con->arr[i].name,
    7. con->arr[i].sex,
    8. con->arr[i].age,
    9. con->arr[i].tel,
    10. con->arr[i].addr
    11. );
    12. }
    13. }

    测试结果如下:

    2.7 查找联系人

    Contact.h:

    void FindContact(contact* con);

    Contact.c:

    1. //查找通讯录数据
    2. int FindByName(contact* con, char name[])//根据需求设计查找的方式
    3. {
    4. for (int i = 0; i < con->size; i++)
    5. {
    6. if (strcmp(con->arr[i].name, name) == 0)
    7. {
    8. return i;
    9. }
    10. }
    11. return -1;
    12. }
    13. void FindContact(contact* con)
    14. {
    15. char name[NAME_MAX];
    16. printf("请输入要查找人的名字:\n");
    17. scanf("%s", name);
    18. int FindIndex = FindByName(con, name);
    19. if (FindIndex < 0)
    20. {
    21. printf("联系人不存在!\n");
    22. return;
    23. }
    24. printf(%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n, "姓名", "性别", "年龄", "电话", "住址");
    25. printf(%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n,
    26. con->arr[FindIndex].name,
    27. con->arr[FindIndex].sex,
    28. con->arr[FindIndex].age,
    29. con->arr[FindIndex].tel,
    30. con->arr[FindIndex].addr
    31. );
    32. }

    测试结果如下:

     2.8 删除联系人

     Contact.h:

    void DelContact(contact* con);

    Contact.c:

    1. void DelContact(contact* con)
    2. {
    3. //删除之前一定要查找
    4. printf("请输入要删除的联系人的姓名:\n");
    5. char name[NAME_MAX];
    6. scanf("%s", name);
    7. int ret = FindByName(con, name);
    8. //找不到,不能执行删除
    9. if (ret < 0)
    10. {
    11. printf("要删除的联系人不存在!\n");
    12. return;
    13. }
    14. //执行删除操作
    15. SLErase(con, ret);
    16. }

    测试结果如下:

    2.9 修改联系人

    Contact.h:

    void ModifyContact(contact* con);

    Contact.c:

    1. void ModifyContact(contact* con)
    2. {
    3. //修改之前进行查找
    4. char name[NAME_MAX];
    5. printf("请输入要修改联系人的姓名:\n");
    6. scanf("%s",name);
    7. int findIndex = FindByName(con, name);
    8. //没有找到,不能执行修改操作
    9. if (findIndex < 0)
    10. {
    11. printf("要修改的联系人不存在!\n");
    12. return;
    13. }
    14. //找到了,执行修改操作
    15. printf("请输入姓名:\n");
    16. scanf("%s", con->arr[findIndex].name);
    17. printf("请输入年龄:\n");
    18. scanf("%d", &con->arr[findIndex].age);
    19. printf("请输入性别:\n");
    20. scanf("%s", con->arr[findIndex].sex);
    21. printf("请输入电话:\n");
    22. scanf("%s", con->arr[findIndex].tel);
    23. printf("请输入地址:\n");
    24. scanf("%s", con->arr[findIndex].addr);
    25. printf("修改联系人成功!\n");
    26. }
    27. //找到了,执行修改操作

    测试结果如下:

    3. 通讯录功能优化

    上面我们已经实现的通讯录的基本功能,但是我们会发现程序一旦结束,通讯录里储存的数据便会丢失。对于这种情况我们该如何解决呢?

    答:将通讯录数据以二进制多大的方式储存到文件里

    3.1 储存数据

    Contact.h:

    void SaveContact(contact* con)

    Contact.c:

    1. void SaveContact(contact* con) {
    2. FILE* pf = fopen("contact.txt", "wb");
    3. if (pf == NULL) {
    4. perror("fopen error!\n");
    5. return;
    6. }
    7. //将通讯录数据写⼊⽂件
    8. for (int i = 0; i < con->size; i++)
    9. {
    10. fwrite(&(con->arr[i]), sizeof(Info), 1, pf);
    11. }
    12. printf("通讯录数据保存成功!\n");
    13. fclose(pf);
    14. }

    测试结果如下:

    3.2 读取数据

     Contact.h:

    void LoadContact(contact* con);

    Contact.c:

    1. void LoadContact(contact* con) {
    2. FILE* pf = fopen("contact.txt", "rb");
    3. if (pf == NULL) {
    4. perror("fopen error!\n");
    5. return;
    6. }
    7. //循环读取⽂件数据
    8. Info info = { 0 };
    9. while (fread(&info, sizeof(Info), 1, pf))
    10. {
    11. SLCheckCapacity(con);
    12. con->arr[con->size] = info;
    13. con->size++;
    14. }
    15. //printf("%s %s\n", info.name, info.tel);
    16. printf("历史数据导入通讯录成功!\n");
    17. fclose(pf);
    18. }

    测试结果如下:

    这样我们就不用担心数据丢失了!

    4. 项目完整代码

    SeqList.h:

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include"Contact.h"
    7. typedef Info SLDataType;
    8. typedef struct SeqList
    9. {
    10. SLDataType* arr;
    11. int capacity;
    12. int size;
    13. }SL;
    14. //初始化和打印
    15. void SLInit(SL* ps);
    16. void SLPrint(SL* ps);
    17. //扩容
    18. void SLCheckCapacity(SL* ps);
    19. //头插和尾插
    20. void SLPushBack(SL* ps, SLDataType x);
    21. void SLPushFront(SL* ps, SLDataType x);
    22. //头删和尾删
    23. void SLPopBack(SL* ps);
    24. void SLPopFront(SL* ps);
    25. //在指定位置插入数据
    26. void SLInsert(SL* ps, int pos, SLDataType x);
    27. //在指定位置删除
    28. void SLErase(SL* ps, int pos);
    29. //查找数据
    30. //int SLFind(SL* ps, SLDataType x);
    31. //销毁
    32. void SLDestory(SL* ps);

    SeqList.c:

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include "SeqList.h"
    3. void SLInit(SL* ps)
    4. {
    5. ps->arr = NULL;
    6. ps->size = ps->capacity = 0;
    7. }
    8. //void SLPrint(SL* ps)
    9. //{
    10. // for (int i = 0; i < ps->size; i++)
    11. // {
    12. // printf("%d ", ps->arr[i]);
    13. // }
    14. // printf("\n");
    15. //}
    16. //检查内存空间,扩容
    17. void SLCheckCapacity(SL* ps)
    18. {
    19. int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
    20. SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));
    21. if (tmp == NULL)
    22. {
    23. perror("realloc fall!");
    24. exit(1);
    25. }
    26. ps->arr = tmp;
    27. ps->capacity = newcapacity;
    28. }
    29. //尾插
    30. void SLPushBack(SL* ps,SLDataType x)
    31. {
    32. assert(ps);
    33. //空间不够,扩容
    34. SLCheckCapacity(ps);
    35. //空间足够,直接插入
    36. ps->arr[ps->size++] = x;
    37. }
    38. //头插
    39. void SLPushFront(SL* ps, SLDataType x)
    40. {
    41. assert(ps);
    42. //判断是否扩容
    43. SLCheckCapacity(ps);
    44. //旧数据往后挪动一位
    45. for (int i = ps->size; i > 0; i--)
    46. {
    47. ps->arr[i] = ps->arr[i - 1];
    48. }
    49. ps->arr[0] = x;
    50. ps->size++;
    51. }
    52. //尾删
    53. void SLPopBack(SL* ps) {
    54. assert(ps);
    55. //判断顺序表是否为空
    56. assert(ps->size);
    57. //不为空
    58. ps->size--;
    59. }
    60. //头删
    61. void SLPopFront(SL* ps)
    62. {
    63. assert(ps);
    64. //判断顺序表是否为空
    65. assert(ps->size);
    66. for (int i = 0; i < ps->size-1; i++)
    67. {
    68. ps->arr[i] = ps->arr[i + 1];
    69. }
    70. ps->size--;
    71. }
    72. //在指定位置插入数据
    73. void SLInsert(SL* ps, int pos, SLDataType x)
    74. {
    75. assert(ps && (pos>=0&&pos <= ps->size));
    76. //判断是否扩容
    77. SLCheckCapacity(ps);
    78. for (int i = ps->size; i > pos; i--)
    79. {
    80. ps->arr[i ] = ps->arr[i - 1];
    81. }
    82. ps->arr[pos] = x;
    83. ps->size++;
    84. }
    85. //在指定位置删除
    86. void SLErase(SL* ps, int pos)
    87. {
    88. assert(ps && (pos >= 0 && pos <= ps->size));
    89. //判断顺序表是否为空
    90. assert(ps->size);
    91. //不为空
    92. for (int i = pos; i < ps->size-1; i++)
    93. {
    94. ps->arr[i] = ps->arr[i + 1];
    95. }
    96. ps->size--;
    97. }
    98. //查找数据
    99. //int SLFind(SL* ps, SLDataType x)
    100. //{
    101. // assert(ps);
    102. // for (int i = 0; i < ps->size; i++)
    103. // {
    104. // if (ps->arr[i] == x)
    105. // {
    106. // return i;
    107. // }
    108. // }
    109. // return -1;
    110. //}
    111. void SLDestory(SL* ps)
    112. {
    113. assert(ps);
    114. if (ps->arr)
    115. {
    116. free(ps->arr);
    117. }
    118. ps->arr = NULL;
    119. ps->capacity = ps->size = 0;
    120. }

    Contact.h:

    1. #pragma once
    2. #include
    3. #define NAME_MAX 100
    4. #define SEX_MAX 10
    5. #define TEL_MAX 20
    6. #define ADDR_MAX 100
    7. //⽤户数据
    8. typedef struct PersonInfo
    9. {
    10. char name[NAME_MAX];
    11. char sex[SEX_MAX];
    12. int age;
    13. char tel[TEL_MAX];
    14. char addr[ADDR_MAX];
    15. }Info;
    16. //前置声明 防止头文件嵌套调用
    17. typedef struct SeqList contact;
    18. //初始化通讯录
    19. void InitContact(contact* con);//实际初始化的是顺序表
    20. //销毁通讯录数据
    21. void DestroyContact(contact* con);
    22. //添加通讯录数据
    23. void AddContact(contact* con);
    24. //展⽰通讯录数据
    25. void ShowContact(contact* con);
    26. //删除通讯录数据
    27. void DelContact(contact* con);
    28. //查找通讯录数据
    29. void FindContact(contact* con);
    30. //修改通讯录数据
    31. void ModifyContact(contact* con);
    32. //保存数据
    33. void SaveContact(contact* con);
    34. //读取数据
    35. void LoadContact(contact* con);

    Contact.c:

    1. #include"SeqList.h"
    2. void InitContact(contact* con)
    3. {
    4. SLInit(con);
    5. }
    6. void DestroyContact(contact* con)
    7. {
    8. SLDestory(con);
    9. }
    10. //添加联系人
    11. void AddContact(contact* con)
    12. {
    13. SLCheckCapacity(con);
    14. printf("请输入联系人姓名:\n");
    15. scanf("%s", con->arr[con->size].name);
    16. printf("请输入联系人性别:\n");
    17. scanf("%s", con->arr[con->size].sex);
    18. printf("请输入联系人年龄:\n");
    19. scanf("%d", &con->arr[con->size].age);
    20. printf("请输入联系人电话:\n");
    21. scanf("%s", con->arr[con->size].tel);
    22. printf("请输入联系人住址:\n");
    23. scanf("%s", con->arr[con->size].addr);
    24. con->size++;
    25. }
    26. //展⽰通讯录数据
    27. void ShowContact(contact* con) {
    28. printf("%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");
    29. for (int i = 0; i < con->size; i++)
    30. {
    31. printf("%-20s\t%-5s\t%-4d\t%-12s\t%-20s\n",
    32. con->arr[i].name,
    33. con->arr[i].sex,
    34. con->arr[i].age,
    35. con->arr[i].tel,
    36. con->arr[i].addr
    37. );
    38. }
    39. }
    40. //查找通讯录数据
    41. int FindByName(contact* con, char name[])//根据需求设计查找的方式
    42. {
    43. for (int i = 0; i < con->size; i++)
    44. {
    45. if (strcmp(con->arr[i].name, name) == 0)
    46. {
    47. return i;
    48. }
    49. }
    50. return -1;
    51. }
    52. void FindContact(contact* con)
    53. {
    54. char name[NAME_MAX];
    55. printf("请输入要查找人的名字:\n");
    56. scanf("%s", name);
    57. int FindIndex = FindByName(con, name);
    58. if (FindIndex < 0)
    59. {
    60. printf("联系人不存在!\n");
    61. return;
    62. }
    63. printf("%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");
    64. printf("%-20s\t%-5s\t%-4d\t%-12s\t%-20s\n",
    65. con->arr[FindIndex].name,
    66. con->arr[FindIndex].sex,
    67. con->arr[FindIndex].age,
    68. con->arr[FindIndex].tel,
    69. con->arr[FindIndex].addr
    70. );
    71. }
    72. //删除通讯录数据
    73. void DelContact(contact* con)
    74. {
    75. //删除之前一定要查找
    76. printf("请输入要删除的联系人的姓名:\n");
    77. char name[NAME_MAX];
    78. scanf("%s", name);
    79. int ret = FindByName(con, name);
    80. //找不到,不能执行删除
    81. if (ret < 0)
    82. {
    83. printf("要删除的联系人不存在!\n");
    84. return;
    85. }
    86. //执行删除操作
    87. SLErase(con, ret);
    88. }
    89. //修改通讯录数据
    90. void ModifyContact(contact* con)
    91. {
    92. //修改之前进行查找
    93. char name[NAME_MAX];
    94. printf("请输入要修改联系人的姓名:\n");
    95. scanf("%s",name);
    96. int findIndex = FindByName(con, name);
    97. //没有找到,不能执行修改操作
    98. if (findIndex < 0)
    99. {
    100. printf("要修改的联系人不存在!\n");
    101. return;
    102. }
    103. //找到了,执行修改操作
    104. printf("请输入姓名:\n");
    105. scanf("%s", con->arr[findIndex].name);
    106. printf("请输入年龄:\n");
    107. scanf("%d", &con->arr[findIndex].age);
    108. printf("请输入性别:\n");
    109. scanf("%s", con->arr[findIndex].sex);
    110. printf("请输入电话:\n");
    111. scanf("%s", con->arr[findIndex].tel);
    112. printf("请输入地址:\n");
    113. scanf("%s", con->arr[findIndex].addr);
    114. printf("修改联系人成功!\n");
    115. }
    116. //保存数据
    117. void SaveContact(contact* con) {
    118. FILE* pf = fopen("contact.txt", "wb");
    119. if (pf == NULL) {
    120. perror("fopen error!\n");
    121. return;
    122. }
    123. //将通讯录数据写⼊⽂件
    124. for (int i = 0; i < con->size; i++)
    125. {
    126. fwrite(&(con->arr[i]), sizeof(Info), 1, pf);
    127. }
    128. printf("通讯录数据保存成功!\n");
    129. fclose(pf);
    130. pf = NULL;
    131. }
    132. //读取数据
    133. void LoadContact(contact* con) {
    134. FILE* pf = fopen("contact.txt", "rb");
    135. if (pf == NULL) {
    136. perror("fopen error!\n");
    137. return;
    138. }
    139. //循环读取⽂件数据
    140. Info info = { 0 };
    141. while (fread(&info, sizeof(Info), 1, pf))
    142. {
    143. SLCheckCapacity(con);
    144. con->arr[con->size] = info;
    145. con->size++;
    146. }
    147. //printf("%s %s\n", info.name, info.tel);
    148. printf("历史数据导入通讯录成功!\n");
    149. fclose(pf);
    150. pf = NULL;
    151. }

    ConTest.c

    1. #include"SeqList.h"
    2. void menu()
    3. {
    4. printf("*******************************************\n");
    5. printf("******* 1.添加联系人 2.查找联系人 ******\n");
    6. printf("******* 3.修改联系人 4.删除联系人 ******\n");
    7. printf("******* 5.查看通讯录 0.退出通讯录 ******\n");
    8. printf("*******************************************\n");
    9. }
    10. int main()
    11. {
    12. int op = -1;
    13. contact con;
    14. //通讯录初始化
    15. InitContact(&con);
    16. LoadContact(&con);
    17. do {
    18. menu();
    19. printf("请选择您的操作:\n");
    20. scanf("%d", &op);
    21. switch (op)
    22. {
    23. case 1:
    24. //添加联系人
    25. AddContact(&con);
    26. break;
    27. case 2:
    28. //查找联系人
    29. FindContact(&con);
    30. break;
    31. case 3:
    32. //修改联系人
    33. ModifyContact(&con);
    34. break;
    35. case 4:
    36. //删除联系人
    37. DelContact(&con);
    38. printf("联系人删除成功!\n");
    39. break;
    40. case 5:
    41. //查看通讯录
    42. ShowContact(&con);
    43. break;
    44. break;
    45. case 0:
    46. //退出通讯录
    47. printf("通讯录退出中.....\n");
    48. break;
    49. }
    50. } while (op);
    51. SaveContact(&con);
    52. DestroyContact(&con);
    53. return 0;
    54. }

     对于顺序表代码的实现在上一篇中有讲解,如果有的小伙伴有兴趣,可以去看一看。链接在下方:http://t.csdnimg.cn/wpM1t

    本文为作者学习后的总结,如果有什么不恰当的地方,欢迎大佬指正!!! 

  • 相关阅读:
    [学习记录] SpringBoot 1. 基础入门
    Python+requests+pytest+excel+allure 接口自动化测试实战
    springboot项目启动后执行方法
    如何使用决策树判断要不要去相亲?
    分享10大自动化测试框架,你用过几个?
    基于LQR算法的一阶倒立摆控制
    Go入门系列:你好,世界
    C++实现单例模式
    GPTCache:革新大模型缓存,降低成本,提升效率
    【学习笔记】CF559E Gerald and Path
  • 原文地址:https://blog.csdn.net/wx2023_10_15/article/details/136606162