C语言进阶|通讯录的实现

发布于:2024-04-20 ⋅ 阅读:(17) ⋅ 点赞:(0)

基于动态顺序表实现通讯录

C语言基础要求:结构体、动态内存管理、顺序表、文件操作
1、功能要求

  1. 至少能够存储100个人的通讯信息
  2. 能够保存用户信息:名字、性别、年龄、电话、地址等
  3. 增加联系人信息
  4. 删除指定联系人
  5. 查找制定联系人
  6. 修改指定联系人
  7. 显示联系人信息

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;
}

顺序表的问题及思考

  1. 中间/头部的插入删除,时间复杂度为O(N)。
  2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
  3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

思考:如何解决以上问题呢?