顺序表的应用——通讯录

接下来我们将会使用顺序表来实现通讯录,在此无需做过多说明解释。代码逻辑清晰,条理有序,易于理解。

头文件:

#pragma once
#include 
#include 
#include 
#include 

// 用于存储联系人的信息
typedef struct People
{
	char address[50];
	char name[20];
	char tele[20];
	char sex[10];
	int age;
} People;

typedef struct Contacts
{
	People* a;
	int size;
	int capacity;
}Contacts;

// 枚举常量,便于日后的使用
enum choice { by_name = 1, by_tele, by_address, by_age };

// 一个顺序表,用于存储下标。我们将会在查找函数使用它
typedef struct Index
{
	int* a;
	int size;
	int capacity;
}Index;

// 菜单
void menu1();
void menu2();
void menu3();
void menu4();

// 加载通讯录
void LoadContacts(Contacts* ps);

// 对通讯录进行初始化
void ContactsInit(Contacts* ps);

// 打印通讯录
void ContactsPrint(Contacts ps);

// 添加和删除通讯录成员
void ContactsAdd(Contacts* ps);
void ContactsDelt(Contacts* ps);

// 通讯录查找
void ContactsFind(Contacts ps, int choice, Index* index);
void FIND(Contacts contacts, int choice);

// 修改联系人
void ContactsModify(Contacts* ps, int index);

// 排序联系人
void ContactsSort(Contacts* ps, int choice);

// 保存通讯录
void SaveContact(Contacts* pc);

// 销毁通讯录
void ContactsDestroy(Contacts* ps);

函数的实现:

#include "Contacts.h"

void menu1()
{
	printf("**********************************\n");
	printf("*** 请按下相应的数字以进行选择 ***\n");
	printf("****1.进入通讯录  0.退出通讯录****\n");
	printf("**********************************\n");
}

void menu2()
{
	printf("**********************************\n");
	printf("*** 请按下相应的数字以进行选择 ***\n");
	printf("****1.添加联系人  2.删除联系人****\n");
	printf("****3.查找联系人  4.修改联系人****\n");
	printf("****5.显示联系人  6.清空联系人****\n");
	printf("****7.排序联系人  0.退出通讯录****\n");
	printf("**********************************\n");

}

void menu3()
{
	printf("**********************************\n");
	printf("*** 请按下相应的数字以进行选择 ***\n");
	printf("**1.按照姓名查找  2.按照号码查找**\n");
	printf("**3.按照住址查找  4.按照年龄查找**\n");
	printf("**0.退出查找模式  ****************\n");
	printf("**********************************\n");
}

void menu4()
{
	printf("**********************************\n");
	printf("*** 请按下相应的数字以进行选择 ***\n");
	printf("**1.按照姓名排序  2.按照号码排序**\n");
	printf("**3.按照住址排序  4.按照年龄排序**\n");
	printf("**0.退出排序模式  ****************\n");
	printf("**********************************\n");
}

// 检查当前顺序表是否已经满了
static void CheckCapacity(Contacts* ps)
{
	assert(ps);

	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		People* tmp = (People*)realloc(ps->a, sizeof(People) * newcapacity);

		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
}

// 将通讯录信息从文件加载到顺序表中
void LoadContacts(Contacts* ps)
{
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact");
		return;
	}
	//读文件
	People tmp;
	while (fread(&tmp, sizeof(People), 1, pf))
	{
		CheckCapacity(ps);
		ps->a[ps->size] = tmp;
		ps->size++;
	}

	fclose(pf);
	pf = NULL;
}

// 初始化通讯录
void ContactsInit(Contacts* ps)
{
	assert(ps);

	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

// 打印联系人
void ContactsPrint(Contacts ps)
{
	int i = 0;
	for (i = 0; i < ps.size; ++i)
	{
		printf("姓名:%-8s", (ps.a[i]).name);
		printf("住址:%-8s", (ps.a[i]).address);
		printf("电话:%-8s", (ps.a[i]).tele);
		printf("性别:%-8s", (ps.a[i]).sex);
		printf("年龄:%-8d", (ps.a[i]).age);
		printf("\n\n");
	}
}

// 顺序表的添加
// 需要注意fgets需要自己手动添加'\0'
void ContactsAdd(Contacts* ps)
{
	assert(ps);

	while (getchar() != '\n');//清空缓存区

	CheckCapacity(ps);

	printf("请输入联系人姓名:");
	fgets(ps->a[ps->size].name, sizeof(ps->a->name), stdin);
	if (ps->a[ps->size].name[strlen(ps->a[ps->size].name) - 1] == '\n')
	{
		ps->a[ps->size].name[strlen(ps->a[ps->size].name) - 1] = '\0';
	}
	printf("请输入联系人住址:");
	fgets(ps->a[ps->size].address, sizeof(ps->a->address), stdin);
	if (ps->a[ps->size].address[strlen(ps->a[ps->size].address) - 1] == '\n')
	{
		ps->a[ps->size].address[strlen(ps->a[ps->size].address) - 1] = '\0';
	}
	printf("请输入联系人电话:");
	fgets(ps->a[ps->size].tele, sizeof(ps->a->tele), stdin);
	if (ps->a[ps->size].tele[strlen(ps->a[ps->size].tele) - 1] == '\n')
	{
		ps->a[ps->size].tele[strlen(ps->a[ps->size].tele) - 1] = '\0';
	}
	printf("请输入联系人性别:");
	fgets(ps->a[ps->size].sex, sizeof(ps->a->sex), stdin);
	if (ps->a[ps->size].sex[strlen(ps->a[ps->size].sex) - 1] == '\n')
	{
		ps->a[ps->size].sex[strlen(ps->a[ps->size].sex) - 1] = '\0';
	}
	printf("请输入联系人年龄:");
	scanf("%d", &(ps->a[ps->size].age));

	ps->size++;
}

// 删除联系人
void ContactsDelt(Contacts* ps)
{
	assert(ps);

	if (ps->size)
	{
		ps->size--;
	}

	return;
}

// 一个用于存储下标的顺序表,用于查找联系人时,
// 将多个符合条件的联系人的下标存储起来。
static void IndexInit(Index* ps)
{
	assert(ps);

	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

// 下标的添加
static void IndexAdd(Index* ps, int x)
{
	assert(ps);

	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		int* tmp = (int*)realloc(ps->a, sizeof(int) * newcapacity);

		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		ps->a = tmp;
		ps->capacity = newcapacity;
	}

	ps->a[ps->size] = x;
	ps->size++;
}

// 下标顺序表的销毁
static void IndexDestroy(Index* ps)
{
	assert(ps);

	if (ps->a != NULL)
	{
		free(ps->a);
		ps->a = NULL;
		ps->size = 0;
		ps->capacity = 0;
	}
}

void ContactsFind(Contacts ps, int choice, Index* index)
{
	int count = 0;
	int i = 0;
	char arr[50];
	int age = 0;

	while (getchar() != '\n');

	switch (choice)
	{
	case by_name:

		printf("请输入要查找的姓名:");
		fgets(arr, sizeof(arr), stdin);
		if (arr[strlen(arr) - 1] == '\n')
		{
			arr[strlen(arr) - 1] = '\0';
		}
		for (int i = 0; i < ps.size; i++) 
		{
			if (strcmp(ps.a[i].name, arr) ==0) 
			{
				IndexAdd(index, i);
			}
		}
		break;
	case by_tele:
		
		printf("请输入要查找的号码:");
		fgets(arr, sizeof(arr), stdin);
		if (arr[strlen(arr) - 1] == '\n')
		{
			arr[strlen(arr) - 1] = '\0';
		}
		for (int i = 0; i < ps.size; i++)
		{
			if (strcmp(ps.a[i].tele, arr) == 0)
			{
				IndexAdd(index, i);
			}
		}
		break;
	case by_address:
		printf("请输入要查找的住址:");
		fgets(arr, sizeof(arr), stdin);
		if (arr[strlen(arr) - 1] == '\n')
		{
			arr[strlen(arr) - 1] = '\0';
		}
		for (int i = 0; i < ps.size; i++)
		{
			if (strcmp(ps.a[i].address, arr) == 0)
			{
				IndexAdd(index, i);
			}
		}
		break;
	case by_age:
		printf("请输入要查找的年龄:");
		scanf("%d", &age);
		for (i = 0; i < ps.size; ++i)
		{
			if (ps.a[i].age == age);
			{
				IndexAdd(index, i);
			}
		}
	}
}

// 查找联系人
void FIND(Contacts contacts, int choice)
{
	if (choice < 0 || choice >4)
	{
		printf("选择错误,请重新选择!!!\n");
		return;
	}

	// 创建用于存储下标的顺序表并初始化。使用完毕记得销毁。
	Index index;
	IndexInit(&index);
	ContactsFind(contacts, choice, &index);

	printf("共查找到%d个联系人:\n", index.size);
	for (int i = 0; i < index.size; ++i)
	{
		printf("第%d个联系人:  ", index.a[i] + 1);
		printf("姓名:%-8s", (contacts.a[index.a[i]]).name);
		printf("住址:%-8s", (contacts.a[index.a[i]]).address);
		printf("电话:%-8s", (contacts.a[index.a[i]]).tele);
		printf("性别:%-8s", (contacts.a[index.a[i]]).sex);
		printf("年龄:%-8d", (contacts.a[index.a[i]]).age);
		printf("\n\n");
	}
	IndexDestroy(&index);
}

void ContactsModify(Contacts* ps, int index)
{
	assert(ps);

	while (getchar() != '\n');//清空缓存区

	printf("请输入联系人姓名:");
	fgets(ps->a[index - 1].name, sizeof(ps->a->name), stdin);
	if (ps->a[index - 1].name[strlen(ps->a[index - 1].name) - 1] == '\n')
	{
		ps->a[index - 1].name[strlen(ps->a[index - 1].name) - 1] = '\0';
	}
	printf("请输入联系人住址:");
	fgets(ps->a[index - 1].address, sizeof(ps->a->address), stdin);
	if (ps->a[index - 1].address[strlen(ps->a[index - 1].address) - 1] == '\n')
	{
		ps->a[index - 1].address[strlen(ps->a[index - 1].address) - 1] = '\0';
	}
	printf("请输入联系人电话:");
	fgets(ps->a[index - 1].tele, sizeof(ps->a->tele), stdin);
	if (ps->a[index - 1].tele[strlen(ps->a[index - 1].tele) - 1] == '\n')
	{
		ps->a[index - 1].tele[strlen(ps->a[index - 1].tele) - 1] = '\0';
	}
	printf("请输入联系人性别:");
	fgets(ps->a[index - 1].sex, sizeof(ps->a->sex), stdin);
	if (ps->a[index - 1].sex[strlen(ps->a[index - 1].sex) - 1] == '\n')
	{
		ps->a[index - 1].sex[strlen(ps->a[index - 1].sex) - 1] = '\0';
	}
	printf("请输入联系人年龄:");
	scanf("%d", &(ps->a[index - 1].age));
}

// 比较函数,用于qsort  
int compare_by_name(const void* a, const void* b)
{
	return strcmp(((People*)a)->name, ((People*)b)->name);
}
int compare_by_tele(const void* a, const void* b)
{
	return strcmp(((People*)a)->tele, ((People*)b)->tele);
}
int compare_by_address(const void* a, const void* b)
{
	return strcmp(((People*)a)->address, ((People*)b)->address);
}
int compare_by_age(const void* a, const void* b)
{
	return ((People*)a)->age - ((People*)b)->age;
}

void ContactsSort(Contacts* ps, int choice)
{
	switch (choice)
	{
	case by_name:
		qsort(ps->a, ps->size, sizeof(People), compare_by_name);
		break;
	case by_tele:
		qsort(ps->a, ps->size, sizeof(People), compare_by_tele);
		break;
	case by_address:
		qsort(ps->a, ps->size, sizeof(People), compare_by_address);
		break;
	case by_age:
		qsort(ps->a, ps->size, sizeof(People), compare_by_age);
		break;
	default:
		printf("输入错误!");
	}
}

void SaveContact(Contacts* pc)
{
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL)
	{
		perror("SaveContacts");
		return;
	}
	//写信息到文件
	int i = 0;
	for (i = 0; i < pc->size; i++)
	{
		fwrite(pc->a + i, sizeof(People), 1, pf);
	}

	fclose(pf);
	pf = NULL;
}

void ContactsDestroy(Contacts* ps)
{
	assert(ps);

	if (ps->a != NULL)
	{
		free(ps->a);
		ps->a = NULL;
		ps->size = 0;
		ps->capacity = 0;
	}
}

主函数:

#include "Contacts.h"

enum Choice{ Add = 1, Delt, Find, Modify, Display, Empty, Sort, Exit = 0 };

int main()
{
	Contacts contacts;
	ContactsInit(&contacts);
	LoadContacts(&contacts);

	int choice_1, choice_2, choice_3;
	do
	{
		menu1();
		printf("请输入你的选项:");
		scanf("%d", &choice_1);
		system("cls");

		if (choice_1 != 1 && choice_1 != 0)
		{
			printf("输入错误,请重新输入!!!\n");
			continue;
		}
		else if (choice_1 == 0)
		{
			return 0;
		}

		do
		{
			menu2();
			printf("请输入你的选项:");
			scanf("%d", &choice_2);
			system("cls");
			if (choice_2 < 0 || choice_2 > 7)
			{
				printf("输入错误,请重新输入!!!\n");
				continue;
			}

			switch (choice_2)
			{
			case Add:
				ContactsAdd(&contacts);
				printf("添加成功!\n");
				break;
			case Delt:
				ContactsDelt(&contacts);
				printf("删除成功!\n");
				break;
			case Find:
				menu3();
				printf("请输入你的选项:");
				scanf("%d", &choice_3);
				system("cls");
				FIND(contacts, choice_3);
				break;
			case Modify:
				menu3();
				printf("请输入你的选项:");
				scanf("%d", &choice_3);
				system("cls");
				FIND(contacts, choice_3);
				printf("请输入要修改的联系人所对应的下标:");
				scanf("%d", &choice_3);
				ContactsModify(&contacts, choice_3);
				printf("修改成功!");
				break;
			case Display:
				ContactsPrint(contacts);
				break;
			case Empty:
				ContactsDestroy(&contacts);
				printf("清空成功!");
				break;
			case Sort:
				menu4();
				printf("请输入你的选项:");
				scanf("%d", &choice_3);
				choice_1 = 0;
				ContactsSort(&contacts, choice_3);
				printf("排序成功!\n");
				break;
			case Exit:
				SaveContact(&contacts);
				ContactsDestroy(&contacts);
				break;
			}
		} while (choice_2);
	} while (choice_1);

	return 0;
}

你可能感兴趣的:(数据结构,算法)