基于动态顺序表实现通讯录
C语言基础要求:结构体、动态内存管理、顺序表、文件操作
1、功能要求
- 至少能够存储100个人的通讯信息
- 能够保存用户信息:名字、性别、年龄、电话、地址等
- 增加联系人信息
- 删除指定联系人
- 查找制定联系人
- 修改指定联系人
- 显示联系人信息
2、代码实现
【思考1】用静态顺序表和动态顺序表分别如何实现
【思考2】如何保证程序结束后,历史通讯录信息不会丢失
//contact.h
#define NAME_MAX 11
#define TEL_MAX 13
#define SEX_MAX 5
#define ADDR_MAX 14
//通讯录包含的类型
typedef struct
{
char name[NAME_MAX];
int age;
char tel[TEL_MAX];
char sex[SEX_MAX];
char addr[ADDR_MAX];
}PersonInfo;
//前置声明
struct Seqlist;
typedef struct Seqlist CT;
//初始化
void CTInit(CT* ct);
//销毁
void CTDestroy(CT* ct);
//查看
void CTCheck(CT* ct);
//增加
void CTAdd(CT* ct);
//删除
void CTDel(CT* ct);
//查找
void CTFind(CT* ct);
//修改
void CTVice(CT* ct);
//contact.c
//查找函数
int CTFind1(CT* ct)
{
char tmp[NAME_MAX] = { 0 };
scanf("%s", tmp);
for (int i = 0; i < ct->size; i++)
{
if (!strcmp(tmp, ct->sqlist->name))
{
return i;
}
}
return -1;
}
//赋值函数
void CTAss(SLTYPE* a, SLTYPE* b)
{
for (int i = 0; i < NAME_MAX; i++)
a->name[i] = b->name[i];
a->age = b->age;
for (int i = 0; i < TEL_MAX; i++)
a->tel[i] = b->tel[i];
for (int i = 0; i < SEX_MAX; i++)
a->sex[i] = b->sex[i];
for (int i = 0; i < ADDR_MAX; i++)
a->addr[i] = b->addr[i];
}
//初始化
void CTInit(CT* ct)
{
ct->size = 0;
ct->capacity = 0;
ct->sqlist = NULL;
}
//销毁
void CTDestroy(CT* ct)
{
free(ct->sqlist);
ct->sqlist = NULL;
ct->size = ct->capacity = 0;
}
//查看
void CTCheck(CT* ct)
{
printf("%-11s%-8s%-13s%-8s%-14s\n", "姓名", "年龄", "电话", "性别", "住址");
for (int i = 0; i < ct->size; i++)
{
printf("%-11s%-8d%-13s%-8s%-14s\n", ct->sqlist[i].name, ct->sqlist[i].age, ct->sqlist[i].tel, ct->sqlist[i].sex, ct->sqlist[i].addr);
}
}
//增加
void CTAdd(CT* ct)
{
//先判断是否要扩容
if (ct->size == ct->capacity)
{
int newcapacity = ct->capacity == 0 ? 4 : 2 * ct->capacity;
SLTYPE* tmp = (SLTYPE*)realloc(ct->sqlist, newcapacity * sizeof(SLTYPE));
if (tmp == NULL)
{
perror("realloc");
exit(1);
}
ct->sqlist = tmp;
}
printf("请输入联系人的姓名:\n");
scanf("%s", (ct->sqlist+ct->size)->name);
printf("请输入联系人的年龄:\n");
scanf("%d", &(ct->sqlist+ ct->size)->age);
printf("请输入联系人的电话:\n");
scanf("%s", (ct->sqlist+ ct->size)->tel);
printf("请输入联系人的性别:\n");
scanf("%s", (ct->sqlist+ ct->size)->sex);
printf("请输入联系人的地址:\n");
scanf("%s", (ct->sqlist+ ct->size)->addr);
ct->size++;
CTSort(ct);
}
//删除
void CTDel(CT* ct)
{
printf("请输入要删除的联系人:\n");
int pos = CTFind1(ct);
if (pos == -1)
{
printf("找不到此联系人,请检查是否输入错误。\n");
return;
}
for (int i = pos; i < ct->size; i++)
{
CTAss(ct->sqlist + i, ct->sqlist + i + 1);
}
ct->size--;
printf("删除成功!\n");
}
//查找
void CTFind(CT* ct)
{
printf("请输入想要查找的联系人:\n");
int pos = CTFind1(ct);
printf("%-11s%-8s%-13s%-8s%-14s\n", "姓名", "年龄", "电话", "性别", "住址");
printf("%-11s%-8d%-13s%-8s%-14s\n", ct->sqlist[pos].name, ct->sqlist[pos].age, ct->sqlist[pos].tel, ct->sqlist[pos].sex, ct->sqlist[pos].addr);
}
//修改
void CTVice(CT* ct)
{
printf("请输入要修改的联系人:\n");
int pos = CTFind1(ct);
if (pos == -1)
{
printf("找不到此联系人,请检查是否输入错误。\n");
return;
}
char type[8] = { 0 };
printf("请输入要修改的数据类型:\n");
scanf("%s", type);
if (!strcmp(type, "姓名"))
{
printf("请输入要修改的姓名:\n");
char tmp_name[NAME_MAX] = { 0 };
scanf("%s", tmp_name);
for (int i = 0; i < NAME_MAX; i++)
(ct->sqlist+pos)->name[i] = tmp_name[i];
CTSort(ct);
}
else if (!strcmp(type, "年龄"))
{
printf("请输入要修改的年龄:\n");
int tmp_age = 0;
scanf("%d", &tmp_age);
(ct->sqlist+pos)->age = tmp_age;
}
else if (!strcmp(type, "电话"))
{
printf("请输入要修改的电话:\n");
char tmp_tel[TEL_MAX] = { 0 };
scanf("%s", &tmp_tel);
for (int i = 0; i < TEL_MAX; i++)
(ct->sqlist+pos)->tel[i] = tmp_tel[i];
}
else if (!strcmp(type, "性别"))
{
printf("请输入要修改的性别:\n");
char tmp_sex[SEX_MAX] = { 0 };
scanf("%s", tmp_sex);
for (int i = 0; i < SEX_MAX; i++)
(ct->sqlist+pos)->sex[i] = tmp_sex[i];
}
else if (!strcmp(type, "住址"))
{
printf("请输入要修改的住址:\n");
char tmp_addr[ADDR_MAX] = { 0 };
scanf("%s", tmp_addr);
}
else
{
printf("输入错误\n");
}
}
//test.c
void menu()
{
printf("**************************************\n");
printf("*****1.添加联系人 2.删除联系人*****\n");
printf("*****3.查找联系人 4.修改联系人*****\n");
printf("*****5.查看联系人 0. 退 出 *****\n");
printf("**************************************\n");
}
int main()
{
CT contect1;
CTInit(&contect1);
int choice = 1;
do
{
menu();
printf("请输入你要做的选项:\n");
scanf("%d", &choice);
switch (choice)
{
case 1:CTAdd(&contect1);
break;
case 2:CTDel(&contect1);
break;
case 3:CTFind(&contect1);
break;
case 4:CTVice(&contect1);
break;
case 5:CTCheck(&contect1);
break;
case 0:CTDestroy(&contect1);
break;
default:printf("输入错误,请重新输入:\n");
break;
}
} while (choice);
return 0;
}
顺序表的问题及思考
- 中间/头部的插入删除,时间复杂度为O(N)。
- 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
- 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
思考:如何解决以上问题呢?