当前位置:   article > 正文

【数据结构】:顺序表实战(通讯录)_通讯表排序

通讯表排序

前言 

数据结构(初阶)第一节:数据结构概论-CSDN博客

数据结构(初阶)第二节:顺序表-CSDN博客

        本文将以C语言和顺序表实现通讯录基础管理,实现功能包括增、删、改、查等,在实现相关功能时需要用到在第二节中顺序表的相关内容,需要友友们掌握顺序表的相关内容以及函数的实现方式。

目录

前言 

要用到的两个文件

正文

文件包含关系

Contact.h

Contast.c

头文件

菜单

初始化

销毁

添加

判断名字是否存在

删除

显示

修改

查找

测试文件test.c


要用到的两个文件

SeqList.h

  1. //.h文件定义
  2. #include "Contact.h"//头文件互相包含会报错
  3. #include <malloc.h>
  4. #include <assert.h>
  5. #include <string.h>
  6. #include <stdio.h>
  7. typedef peoInfo SLDataType;
  8. //定义顺序表
  9. typedef struct SeqList
  10. {
  11. SLDataType* a;//数组
  12. int size;//有效元素
  13. int capacity;//容量
  14. }SL;
  15. //初始化
  16. void SLinit(SL* p1);
  17. //销毁
  18. void SLdestory(SL* p1);
  19. //扩容
  20. void SLcheckCapcity(SL* p1);
  21. //尾插
  22. void SLpushBack(SL* p1, SLDataType x);
  23. //打印顺序表
  24. void SLprint(SL* p1);
  25. //头插
  26. void SLpushFront(SL* p1, SLDataType x);
  27. //尾删
  28. void SLpopBack(SL* p1);
  29. //头删
  30. void SLpopFront(SL* p1);
  31. //指定插入
  32. void SLinsert(SL* p1, int pos, SLDataType x);
  33. //指定删除
  34. void SLerase(SL* p1, int pos);
  35. //查询
  36. //int SLfind(SL* p1, SLDataType x);

SeqList.c

  1. #include "SeqList.h"
  2. //初始化
  3. void SLinit(SL* p1)
  4. {
  5. p1->a = (SLDataType*)malloc((sizeof(SLDataType)) * 4);
  6. if (p1->a == NULL)
  7. {
  8. perror("malloc fail");
  9. return;
  10. }
  11. p1->capacity = 4;
  12. p1->size = 0;
  13. }
  14. //销毁
  15. void SLdestory(SL* p1)
  16. {
  17. free(p1->a);
  18. p1->a = NULL;
  19. p1->capacity = 0;
  20. p1->size = 0;
  21. }
  22. //扩容
  23. void SLcheckCapcity(SL* p1)
  24. {
  25. if (p1->size >= p1->capacity)
  26. {
  27. SLDataType* tmp = (SLDataType*)realloc(p1->a, sizeof(SLDataType) * p1->capacity * 2);
  28. if (tmp == NULL)
  29. {
  30. perror("realloc fail");
  31. return;
  32. }
  33. p1->a = tmp;
  34. p1->capacity *= 2;
  35. }
  36. }
  37. //尾插
  38. void SLpushBack(SL* p1, SLDataType x)
  39. {
  40. assert(p1);
  41. SLcheckCapcity(p1);//检查是否需要扩容
  42. p1->a[(p1->size)++] = x;//在size处插入数据
  43. }
  44. //打印顺序表
  45. void SLprint(SL* p1)
  46. {
  47. for (int i = 0; i < p1->size; i++)
  48. {
  49. printf("%d\n", p1->a[i]);
  50. }
  51. }
  52. //头插
  53. void SLpushFront(SL* p1, SLDataType x)
  54. {
  55. assert(p1);
  56. SLcheckCapcity(p1);
  57. for (int i = p1->size; i > 0; i--)
  58. {
  59. p1->a[i] = p1->a[i - 1];
  60. }
  61. p1->a[0] = x;
  62. p1->size++;
  63. }
  64. //尾删
  65. void SLpopBack(SL* p1)
  66. {
  67. assert(p1);
  68. assert(p1->size);//顺序表不为空
  69. //p1->a[p1->size - 1] = -1;
  70. p1->size--;
  71. }
  72. //头删
  73. void SLpopFront(SL* p1)
  74. {
  75. assert(p1);
  76. assert(p1->size);
  77. for (int i = 1; i < p1->size; i++)
  78. {
  79. p1->a[i - 1] = p1->a[i];
  80. }
  81. p1->size--;
  82. }
  83. //指定下标添加
  84. void SLinsert(SL* p1, int pos, SLDataType x)
  85. {
  86. //要注意p1->size指向的是最后一个有效数据的下一位
  87. //pos是指定的插入位置的下标(如果为0则是头插,如果为ps->size-1则为尾插)
  88. //x是待插入的数据
  89. assert(p1 && pos >= 0 && pos < p1->size);
  90. SLcheckCapcity(p1);
  91. for (int i = p1->size; i > pos; i--)
  92. {
  93. p1->a[i] = p1->a[i - 1];
  94. }
  95. p1->a[pos] = x;
  96. p1->size++;
  97. }
  98. //指定下标删除
  99. void SLerase(SL* p1, int pos)
  100. {
  101. assert(p1 && pos >= 0 && pos < p1->size);
  102. for (int i = pos; i < p1->size - 1; i++)
  103. {
  104. p1->a[i] = p1->a[i + 1];
  105. }
  106. p1->size--;
  107. }
  108. //查询
  109. //int SLfind(SL* p1, SLDataType x)
  110. //{
  111. // assert(p1);
  112. // for (int i = 0; i < p1->size; i++)
  113. // {
  114. // if (p1->a[i] == x)
  115. // {
  116. // return i;//找到后返回下标
  117. // }
  118. // }
  119. // return -1;//没有找到返回-1
  120. //}

正文

文件包含关系

在实现通讯录的工程文件中一共包含了5个子文件,分别是

  • test.c:用于在编写过程中测试代码能否正常运行
  • SeqList.h:用于在实现顺序表的过程中定义结构体和各种方法
  • SeqList.c:用于实现在头文件中定义的方法
  • Contact.h:定义通讯录中实现功能的函数
  • Contact.c:实现头文件中定义的函数

        通讯录实质上就是顺序表,只不过是改了名字(换汤不换药),我们只需要在实现顺序表的基础上给他起个别名通讯录(Contact)即可。

        在顺序表中,数组中存储的是单一的元素,在通讯录中,原数组中的元素变成了存储联系人数据的结构体(personInfo),数组中的每个元素都是结构体类型,包括姓名、电话、性别、住址等,本质上是两个结构体的嵌套。

在Contact.h中我们定义好联系人结构体和要用到的方法

  1. #define NAME_MAX 20
  2. #define GENDER_MAX 5
  3. #define PHONE_MAX 20
  4. #define ADDS_MAX 20
  5. typedef struct personInfo
  6. {
  7. char name[NAME_MAX];
  8. char gender[GENDER_MAX];
  9. int age;
  10. char phoneNum[PHONE_MAX];
  11. char adds[ADDS_MAX];
  12. }peoInfo;
  13. //前置声明
  14. typedef struct SeqList Contact;//将顺序表命名为"通讯录"
  15. //菜单
  16. void menu();
  17. //初始化
  18. void ContactInit(Contact* p);
  19. //销毁
  20. void ContactDestory(Contact* p);
  21. //添加
  22. void ContactAdd(Contact* p);
  23. //删除
  24. void ContactDle(Contact* p);
  25. //修改
  26. void ContactModify(Contact* p);
  27. //查找
  28. void ContactFind(Contact* p);
  29. //显示
  30. void ContactShow(Contact* p);

        typedef struct SeqList Contact;在这一句代码中使用前置声明将Seqlist重命名为Contact,在该文件中我们并没有定义结构体SeqList,使用前置声明只是为了让编译器知道有这个结构体的存在,而无法直接对之前重命名过的SL(typedef struct SeqList SL;)再命名的原因是编译器不能识别到SL的存在,如果想要识别必须包含"SeqList.h",但是头文件相互包含会导致报错,后面会讲到。

        在SeqList.h中将SLDateType自定义类型更改为perInfo,需要将"Contact.h"包含进文件,不能将"SeqList.h"同时包含进Contact.h中,这样会导致程序报错。

  1. typedef peoInfo SLDataType;
  2. //定义顺序表
  3. typedef struct SeqList
  4. {
  5. SLDataType* a;//数组
  6. int size;//有效元素
  7. int capacity;//容量
  8. }SL;

        在Contact.h中对SeqList重命名,在SeqList.h中更改自定义数据类型,此时我们通过Contact*p和SL*p定义的两种结构体指针都会被程序正确识别,本质上Contact*p等价于SL*p。

Contact.h

  1. #define NAME_MAX 20
  2. #define GENDER_MAX 5
  3. #define PHONE_MAX 20
  4. #define ADDS_MAX 20
  5. typedef struct personInfo
  6. {
  7. char name[NAME_MAX];
  8. char gender[GENDER_MAX];
  9. int age;
  10. char phoneNum[PHONE_MAX];
  11. char adds[ADDS_MAX];
  12. }peoInfo;
  13. //前置声明
  14. typedef struct SeqList Contact;//将顺序表命名为"通讯录"
  15. //菜单
  16. void menu();
  17. //初始化
  18. void ContactInit(Contact* p);
  19. //销毁
  20. void ContactDestory(Contact* p);
  21. //添加
  22. void ContactAdd(Contact* p);
  23. //删除
  24. void ContactDle(Contact* p);
  25. //修改
  26. void ContactModify(Contact* p);
  27. //查找
  28. void ContactFind(Contact* p);
  29. //显示
  30. void ContactShow(Contact* p);

Contast.c

头文件

  1. #include "Contact.h"
  2. #include "SeqList.h"

菜单

  1. void menu()
  2. {
  3. printf("-----------------------\n");
  4. printf(" 1.添加 \n");
  5. printf(" 2.删除 \n");
  6. printf(" 3.查找 \n");
  7. printf(" 4.显示 \n");
  8. printf(" 5.修改 \n");
  9. printf(" 0.退出 \n");
  10. printf("-----------------------\n");
  11. }

初始化

  1. //初始化
  2. void ContactInit(Contact* p)
  3. {
  4. SLinit(p);//直接调用已经在SeqList.c中实现好的初始化函数即可
  5. }

销毁

  1. void ContactDestory(Contact* p)
  2. {
  3. SLdestory(p);
  4. }

添加

  1. void ContactAdd(Contact* p)
  2. {
  3. peoInfo info;//联系人结构体变量
  4. printf("请输入联系人的姓名:\n");
  5. scanf("%s", info.name);
  6. printf("请输入联系人的性别:\n");
  7. scanf("%s", info.gender);
  8. printf("请输入联系人的年龄:\n");
  9. scanf("%d", &info.age);
  10. printf("请输入联系人的电话号码:\n");
  11. scanf("%s", info.phoneNum);
  12. printf("请输入联系人的住址:\n");
  13. scanf("%s", info.adds);
  14. SLpushBack(p, info);//这里选择尾插
  15. printf("添加成功!\n\n");
  16. }

判断名字是否存在

  1. int FindName(Contact* p, char* name)
  2. {
  3. for (int i = 0; i < p->size; i++)
  4. {
  5. if (strcmp(p->a[i].name, name) == 0)
  6. return i;//返回下标
  7. }
  8. return -1;
  9. }

删除

  1. void ContactDle(Contact* p)
  2. {
  3. char n[NAME_MAX];
  4. printf("请输入要删除的联系人姓名:\n");
  5. scanf("%s", n);
  6. int ret = FindName(p, n);
  7. if (ret < 0)
  8. {
  9. printf("删除对象不存在!\n");
  10. return;
  11. }
  12. SLerase(p, ret);
  13. printf("删除成功!\n");
  14. }

显示

  1. void ContactShow(Contact* p)
  2. {
  3. printf("%-15s%-15s%-15s%-15s%-15s\n", "姓名", "性别", "年龄", "电话", "地址");
  4. for (int i = 0; i < p->size; i++)
  5. {
  6. printf("%-15s%-15s%-15d%-15s%-15s\n", p->a[i].name, p->a[i].gender, p->a[i].age,
  7. p->a[i].phoneNum, p->a[i].adds);
  8. }
  9. }

修改

  1. void ContactModify(Contact* p)
  2. {
  3. char name[NAME_MAX];
  4. printf("请输入要修改的联系人姓名:\n");
  5. scanf("%s", name);
  6. int ret = FindName(p, name);
  7. if (ret < 0)
  8. {
  9. printf("修改对象不存在!\n");
  10. return;
  11. }
  12. printf("请输入新的姓名:\n");
  13. scanf("%s", p->a[ret].name);
  14. printf("请输入新的性别:\n");
  15. scanf("%s", p->a[ret].gender);
  16. printf("请输入新的年龄:\n");
  17. scanf("%d", &p->a[ret].age);
  18. printf("请输入新的电话:\n");
  19. scanf("%s", p->a[ret].phoneNum);
  20. printf("请输入新的地址:\n");
  21. scanf("%s", p->a[ret].adds);
  22. printf("修改成功!\n\n");
  23. }

查找

  1. void ContactFind(Contact* p)
  2. {
  3. char name[NAME_MAX];
  4. printf("请输入要查找的联系人姓名:\n");
  5. scanf("%s", name);
  6. int ret = FindName(p, name);
  7. if (ret < 0)
  8. {
  9. printf("联系人不存在!\n");
  10. return;
  11. }
  12. printf("%-15s%-15s%-15s%-15s%-15s\n", "姓名", "性别", "年龄", "电话", "地址");
  13. printf("%-15s%-15s%-15d%-15s%-15s\n", p->a[ret].name, p->a[ret].gender, p->a[ret].age,
  14. p->a[ret].phoneNum, p->a[ret].adds);
  15. printf("查询成功!\n\n");
  16. }

测试文件test.c

  1. #include "SeqList.h"
  2. int main()
  3. {
  4. Contact con;
  5. ContactInit(&con);
  6. while (1)
  7. {
  8. menu();
  9. int i = 0;
  10. printf("请选择你的操作:");
  11. scanf("%d", &i);
  12. switch (i)
  13. {
  14. case 1:
  15. ContactAdd(&con);
  16. break;
  17. case 2:
  18. ContactDle(&con);
  19. break;
  20. case 3:
  21. ContactFind(&con);
  22. break;
  23. case 4:
  24. ContactShow(&con);
  25. break;
  26. case 5:
  27. ContactModify(&con);
  28. break;
  29. case 0:
  30. printf("程序已退出!\n");
  31. break;
  32. }
  33. }
  34. return 0;
  35. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/黑客灵魂/article/detail/1006910
推荐阅读
相关标签
  

闽ICP备14008679号