【数据结构】2.顺序表实现通讯录
文章目录
- 一、通讯录的要求
- 二、通讯录的具体实现
- 0、 准备工作
- 1、通讯录的初始化
- 2、通讯录的销毁
- 3、通讯录的展示
- 4、通讯录添加数据
- 5、通讯录删除数据
- 6、通讯录的查找
- 7、通讯录的修改
- 8、保存通讯录数据到文件
- 9、读取文件内容到通讯录
- 三、 通讯录的完整实现
一、通讯录的要求
通讯录所能实现的功能要求如下:
1)⾄少能够存储100个⼈的通讯信息
2)能够保存⽤⼾信息:名字、性别、年龄、电话、地址等
3)增加联系⼈
4)删除指定联系⼈
5)查找指定联系⼈
6)修改指定联系⼈
7)显⽰联系⼈信息
二、通讯录的具体实现
0、 准备工作
注:本文所有的SeqList文件均在上文讲解过,如果有不懂的可以点击蓝色字体查看上文。
通讯录的实现是基于动态顺序表实现的,可以理解为在动态顺序表上面套了一层壳子叫做通讯录,里面的核心还是动态顺序表。
由此图可以理解为原来动态顺序表的一个元素,现在变成了一个结构体(包含了联系人的信息)。
由于是在动态顺序表的基础上实现的,所以还需要包含前文所写的SeqList.h和SeqList.c文件,因此要实现通讯录需要包含5个文件:
SeqList.h
SeqList.c:
Contact.h:通讯录函数的声明,结构体构造,宏定义。
Contact.c:通讯录函数的实现。
test.c:通讯录函数的测试
如果要实现通讯录,那我们首先需要定义一个联系人的结构体,包含联系人的各种信息。
即:
这些信息仅做参考,还可以根据需求自己定义一些相关信息。
结构体在通讯录的头文件Contact.h中定义:
typedef struct PersonInfo
{
char name[10];//姓名
char sex[10];//性别
int age;//年龄
char tel[20];//电话
char addr[100];//地址
}Peo
但是为了便于维护,我们可以将数组的最大值用宏定义来替代,提高代码的便利性。
即:
#define NAME_MAX 10
#define SEX_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100
typedef struct PersonInfo
{
char name[NAME_MAX];//姓名
char sex[SEX_MAX];//性别
int age;///年龄
char tel[TEL_MAX];//电话
char addr[ADDR_MAX];//地址
}PeoInfo;
之前在顺序表中,一个元素的类型一般是int类型,现在我们用结构体替代原来的元素,元素类型应该变成结构体类型PeoInfo。
因此需要将SeqList.h文件中的:
typedef int SLDataType;
改为:
typedef PeoInfo SLDataType;
而在SeqList.h文件中引用Contact.h文件中的内容,需要在SeqList.h中添加#include"Contact.h"
。
由于我们实质上是对顺序表进行操作,所以需要对在Contact.h中为顺序表重新起个名字叫做通讯录:
typedef struct SeqList Contact;
接下来就进入正式部分,首先对需要实现的通讯录相关的方法在Conatct.h中进行声明:
//通讯录的初始化
void ContactInit(Contact* con);
//通讯录的销毁
void ContactDestroy(Contact* con);
//通讯录的展示
void ContactShow(Contact* con);
//通讯录添加数据
void ContactAdd(Contact* con);
//通讯录删除数据
void ContactDel(Contact* con);
//通讯录的查找
void ContactFind(Contact* con);
//通讯录的修改
void ContactModify(Contact* con);
//保存通讯录数据到文件
void SaveContact(Contact* con);
//读取文件内容到通讯录
void LoadContact(Contact* con);
接下来再在Contact.c文件中来实现方法,首要需要引用头文件:#include"Contact.h"
,同时实现的部分方法是直接使用的顺序表的方法,因此还需要引用顺序表:#include"SeqList.h"
。
现在完事具备,可以来实现方法了。
1、通讯录的初始化
通讯录的初始化:直接调用顺序表的初始化。
void ContactInit(Contact* con)
{
//调用顺序表的初始化
SLInit(con);
}
在test.c中进行测试:
int main()
{
Contact con;
ContactInit(&con);
return 0;
}

通过测试发现通讯录初始化成功!
2、通讯录的销毁
通讯录的销毁:同样直接调用顺序表的销毁即可。
void ContactDestroy(Contact* con)
{
//调用顺序表的销毁
SLDestroy(con);
}
再进行测试:
int main()
{
Contact con;
ContactInit(&con);
ContactDestroy(&con);
return 0;
}

3、通讯录的展示
通讯录的展示:先打印表头,再依次打印通讯录中每一个结构体里的五个通讯录信息。
void ContactShow(Contact* con)
{
//打印表头
printf("%-10s %-4s %-4s %-11s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
//for循环依次打印通讯录中每一个(元素)结构体里的5个通讯录信息
for (int i = 0; i < con->size; i++)
{
printf("%-10s %-4s %-4d %-11s %-20s\n",
con->arr[i].name,
con->arr[i].sex,
con->arr[i].age,
con->arr[i].tel,
con->arr[i].addr
);
}
}
注:-号表示左对齐,10表示输出的数据占10个字符。
再进行测试:
int main()
{
Contact con;
ContactInit(&con);
ContactShow(&con);
return 0;
}

通过测试发现通讯录展示成功!
4、通讯录添加数据
通讯录添加数据:输入一个元素的通讯录信息,再尾插到通讯录(顺序表)中。
void ContactAdd(Contact* con)
{
//输入一个元素(结构体)的通讯录信息
PeoInfo info;
printf("请输入要添加的联系人姓名:");
scanf("%s", info.name);//数组不用取地址&
printf("请输入要添加的联系人性别:");
scanf("%s",info.sex);
printf("请输入要添加的联系人年龄:");
scanf("%d", &info.age);
printf("请输入要添加的联系人电话:");
scanf("%s", info.tel);
printf("请输入要添加的联系人地址:");
scanf("%s", info.addr);
//将其尾插到通讯录(顺序表)中
SLPushBack(con, info);
printf("联系人数据添加成功!\n");
}
再进行测试:
int main()
{
Contact con;
ContactInit(&con);
ContactAdd(&con);
ContactShow(&con);
return 0;
}

通过测试发现通讯录添加数据成功!
5、通讯录删除数据
在进行删除、查找等操作的时候,我们需要通过姓名这个唯一性元素来得到其整个信息,然后再进行操作。
根据姓名查找:遍历通讯录,找到返回下标,否则返回-1
int FindByName(Contact* con, char Name[])
{
//遍历通讯录,查看通讯录每一个元素中的姓名是否与传入的姓名相同
for (int i = 0; i < con->size; i++)
{
if (0 == strcmp(con->arr[i].name, Name))
{
//返回下标
return i;
}
}
//找不到
return -1;
}
接下来再进行通讯录的删除:输入姓名,找到下标,调用顺序表指定位置删除,删除下标对应的数据。
void ContactDel(Contact* con)
{
//输入要删除的姓名
char Name[NAME_MAX];
printf("请输入你要删除的联系人姓名:");
scanf("%s", Name);
//找到下标
int find = FindByName(con, Name);
if (find < 0)
{
printf("你要删除的联系人数据不存在!\n");
}
//调用顺序表指定位置的删除 删除下标对应的数据
SLErase(con, find);
printf("联系人数据删除成功!\n");
}
再进行测试:
int main()
{
Contact con;
ContactInit(&con);
ContactAdd(&con);
ContactShow(&con);
ContactDel(&con);
ContactShow(&con);
return 0;
}

通过测试发现通讯录数据删除成功!
6、通讯录的查找
通讯录的查找:输入姓名,找到下标,打印下标对应的数据。
void ContactFind(Contact* con)
{
//输入要查找的姓名
char Name[NAME_MAX];
printf("请输入你要查找的联系人姓名:");
scanf("%s", Name);
//找到下标
int find = FindByName(con, Name);
if (find < 0)
{
printf("你要查找的联系人数据不存在!\n");
}
//打印下标对应的数据
printf("%-10s %-4s %-4s %-11s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%-10s %-4s %-4d %-11s %-20s\n",
con->arr[find].name,
con->arr[find].sex,
con->arr[find].age,
con->arr[find].tel,
con->arr[find].addr );
}
再进行测试:
int main()
{
Contact con;
ContactInit(&con);
ContactAdd(&con);
ContactShow(&con);
ContactFind(&con);
return 0;
}

通过测试发现通讯录查找成功!
7、通讯录的修改
通讯录的修改:输入姓名,找到下标,修改下标对应的数据。
void ContactModify(Contact* con)
{
//输入姓名
char Name[NAME_MAX];
printf("请输入你要修改的联系人姓名:");
scanf("%s", Name);
//找到下标
int find = FindByName(con, Name);
if (find < 0)
{
printf("你要修改的联系人数据不存在!\n");
}
//修改下标对应的数据
printf("请输入新的联系人姓名:");
scanf("%s", con->arr[find].name);
printf("请输入新的联系人性别:");
scanf("%s", con->arr[find].sex);
printf("请输入新的联系人年龄:");
scanf("%d", &con->arr[find].age);
printf("请输入新的联系人电话:");
scanf("%s", con->arr[find].tel);
printf("请输入新的联系人地址:");
scanf("%s", con->arr[find].addr);
printf("联系人数据修改成功!\n");
}
再进行测试:
int main()
{
Contact con;
ContactInit(&con);
ContactAdd(&con);
ContactShow(&con);
ContactModify(&con);
ContactShow(&con);
return 0;
}

经过测试通讯录的修改成功!
8、保存通讯录数据到文件
保存数据到文件:打开文件,联系人数据写入文件,关闭文件。
void SaveContact(Contact* con)
{
//打开文件
FILE* pf = fopen("Contact.txt", "ab");
//如果打开失败
{
if (pf == NULL)
{
perror("fopen fail");
}
}
//将联系人数据写入文件
for (int i = 0; i < con->size; i++)
{
fwrite(con->arr + i, sizeof(PeoInfo), 1, pf);
}
printf("通讯录数据保存成功!\n");
//关闭文件
fclose(pf);
}
再进行测试:
int main()
{
Contact con;
ContactInit(&con);
ContactAdd(&con);
ContactShow(&con);
SaveContact(&con);
return 0;
}

同时我们可以点击添加源文件,添加现有项,将Contact.txt文件添加进来,再将txt文件的打开方式设置为二进制编辑器。‘’
就可以在Contact.txt文件中看到;
说明数据已经以二进制的形式保存在文件中了。
9、读取文件内容到通讯录
读取文件内容到通讯录:打开文件,读取文件,尾插到通讯录中,关闭文件。
void LoadContact(Contact* con)
{
//打开文件
FILE* pf=fopen("Contact.txt","rb");
//如果打开失败
if (pf == NULL)
{
perror("fopen fail");
}
//读取文件数据
PeoInfo info;
while (fread(&info, sizeof(PeoInfo), 1, pf))
{
//文件数据尾插到通讯录中
SLPushBack(con, info);
}
//关闭文件
fclose(pf);
}
再进行测试:
int main()
{
Contact con;
ContactInit(&con);
ContactShow(&con);
LoadContact(&con);
ContactShow(&con);
return 0;
}

可以观察到,一开始原本没有数据,但是在我们读取文件到通讯录之后,就有了数据,说明读取文件内容到通讯录成功了!
三、 通讯录的完整实现
在我们实现了通讯录的所有方法之后,我们可以将其集合起来做成完整的通讯录。
再在test.c中来实现这个完整的程序:
#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h"
//打印通讯录界面
void menu()
{
printf("************** 通讯录 **************\n");
printf("******* 1.增加联系人 2.删除联系人 ******\n");
printf("******* 3.修改联系人 4.查找联系人 ******\n");
printf("******* 5.展示联系人 6.保存联系人 ******\n");
printf("******* 7.导入联系人 0.退出 ******\n");
printf("********************************************\n");
}
int main()
{
//通讯录初始化
int input = -1;
Contact con;
ContactInit(&con);
//用do while先执行一次循环,输入0循环结束
do
{
menu();
//输入序号
printf("请选择你要执行的操作:");
scanf("%d", &input);
//根据输入的序号执行对应的操作
switch (input)
{
case 1:
ContactAdd(&con);
break;
case 2:
ContactDel(&con);
break;
case 3:
ContactModify(&con);
break;
case 4:
ContactFind(&con);
break;
case 5:
ContactShow(&con);
break;
case 6:
SaveContact(&con);
break;
case 7:
LoadContact(&con);
break;
case 0:
printf("退出通讯录...\n");
break;
default:
printf("输入错误,请重新选择你的操作:\n");
break;
}
} while (input != 0);
//通讯录销毁
ContactDestroy(&con);
return 0;
}
效果如下: