清华主页 - 清华新闻 - 综合时讯 - 正文

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

前言 

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

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

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

目录

前言 

要用到的两个文件

正文

文件包含关系

Contact.h

Contast.c

头文件

菜单

初始化

销毁

添加

判断名字是否存在

删除

显示

修改

查找

测试文件test.c


要用到的两个文件

SeqList.h

//.h文件定义#include "Contact.h"//头文件互相包含会报错#include <malloc.h>#include <assert.h>#include <string.h>#include <stdio.h>typedef peoInfo SLDataType;//定义顺序表typedef struct SeqList{ 	SLDataType* a;//数组	int size;//有效元素	int capacity;//容量}SL;//初始化void SLinit(SL* p1);//销毁void SLdestory(SL* p1);//扩容void SLcheckCapcity(SL* p1);//尾插void SLpushBack(SL* p1, SLDataType x);//打印顺序表void SLprint(SL* p1);//头插void SLpushFront(SL* p1, SLDataType x);//尾删void SLpopBack(SL* p1);//头删void SLpopFront(SL* p1);//指定插入void SLinsert(SL* p1, int pos, SLDataType x);//指定删除void SLerase(SL* p1, int pos);//查询//int SLfind(SL* p1, SLDataType x);

SeqList.c

#include "SeqList.h"//初始化void SLinit(SL* p1){ 	p1->a = (SLDataType*)malloc((sizeof(SLDataType)) * 4);	if (p1->a == NULL)	{ 		perror("malloc fail");		return;	}	p1->capacity = 4;	p1->size = 0;}//销毁void SLdestory(SL* p1){ 	free(p1->a);	p1->a = NULL;	p1->capacity = 0;	p1->size = 0;}//扩容void SLcheckCapcity(SL* p1){ 	if (p1->size >= p1->capacity)	{ 		SLDataType* tmp = (SLDataType*)realloc(p1->a, sizeof(SLDataType) * p1->capacity * 2);		if (tmp == NULL)		{ 			perror("realloc fail");			return;		}		p1->a = tmp;		p1->capacity *= 2;	}}//尾插void SLpushBack(SL* p1, SLDataType x){ 	assert(p1);	SLcheckCapcity(p1);//检查是否需要扩容	p1->a[(p1->size)++] = x;//在size处插入数据}//打印顺序表void SLprint(SL* p1){ 	for (int i = 0; i < p1->size; i++)	{ 		printf("%d\n", p1->a[i]);	}}//头插void SLpushFront(SL* p1, SLDataType x){ 	assert(p1);	SLcheckCapcity(p1);	for (int i = p1->size; i > 0; i--)	{ 		p1->a[i] = p1->a[i - 1];	}	p1->a[0] = x;	p1->size++;}//尾删void SLpopBack(SL* p1){ 	assert(p1);	assert(p1->size);//顺序表不为空	//p1->a[p1->size - 1] = -1;	p1->size--;}//头删void SLpopFront(SL* p1){ 	assert(p1);	assert(p1->size);	for (int i = 1; i < p1->size; i++)	{ 		p1->a[i - 1] = p1->a[i];	}	p1->size--;}//指定下标添加void SLinsert(SL* p1, int pos, SLDataType x){ 	//要注意p1->size指向的是最后一个有效数据的下一位	//pos是指定的插入位置的下标(如果为0则是头插,如果为ps->size-1则为尾插)	//x是待插入的数据	assert(p1 && pos >= 0 && pos < p1->size);	SLcheckCapcity(p1);	for (int i = p1->size; i > pos; i--)	{ 		p1->a[i] = p1->a[i - 1];	}	p1->a[pos] = x;	p1->size++;}//指定下标删除void SLerase(SL* p1, int pos){ 	assert(p1 && pos >= 0 && pos < p1->size);	for (int i = pos; i < p1->size - 1; i++)	{ 		p1->a[i] = p1->a[i + 1];	}	p1->size--;}//查询//int SLfind(SL* p1, SLDataType x)//{ //	assert(p1);//	for (int i = 0; i < p1->size; i++)//	{ //		if (p1->a[i] == x)//		{ //			return i;//找到后返回下标//		}//	}//	return -1;//没有找到返回-1//}

正文

文件包含关系

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

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

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

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

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

#define NAME_MAX 20#define GENDER_MAX 5#define PHONE_MAX 20#define ADDS_MAX 20typedef struct personInfo{ 	char name[NAME_MAX];	char gender[GENDER_MAX];	int age;	char phoneNum[PHONE_MAX];	char adds[ADDS_MAX];}peoInfo;//前置声明typedef struct SeqList Contact;//将顺序表命名为"通讯录"//菜单void menu();//初始化void ContactInit(Contact* p);//销毁void ContactDestory(Contact* p);//添加void ContactAdd(Contact* p);//删除void ContactDle(Contact* p);//修改void ContactModify(Contact* p);//查找void ContactFind(Contact* p);//显示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中,这样会导致程序报错。

typedef peoInfo SLDataType;//定义顺序表typedef struct SeqList{ 	SLDataType* a;//数组	int size;//有效元素	int capacity;//容量}SL;

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

Contact.h

#define NAME_MAX 20#define GENDER_MAX 5#define PHONE_MAX 20#define ADDS_MAX 20typedef struct personInfo{ 	char name[NAME_MAX];	char gender[GENDER_MAX];	int age;	char phoneNum[PHONE_MAX];	char adds[ADDS_MAX];}peoInfo;//前置声明typedef struct SeqList Contact;//将顺序表命名为"通讯录"//菜单void menu();//初始化void ContactInit(Contact* p);//销毁void ContactDestory(Contact* p);//添加void ContactAdd(Contact* p);//删除void ContactDle(Contact* p);//修改void ContactModify(Contact* p);//查找void ContactFind(Contact* p);//显示void ContactShow(Contact* p);

Contast.c

头文件

#include "Contact.h"#include "SeqList.h"

菜单

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

初始化

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

销毁

void ContactDestory(Contact* p){ 	SLdestory(p);}

添加

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

判断名字是否存在

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

删除

void ContactDle(Contact* p){ 	char n[NAME_MAX];	printf("请输入要删除的联系人姓名:\n");	scanf("%s", n);	int ret = FindName(p, n);	if (ret < 0)	{ 		printf("删除对象不存在!\n");		return;	}	SLerase(p, ret);	printf("删除成功!\n");}

显示

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

修改

void ContactModify(Contact* p){ 	char name[NAME_MAX];	printf("请输入要修改的联系人姓名:\n");	scanf("%s", name);	int ret = FindName(p, name);	if (ret < 0)	{ 		printf("修改对象不存在!\n");		return;	}	printf("请输入新的姓名:\n");	scanf("%s", p->a[ret].name);	printf("请输入新的性别:\n");	scanf("%s", p->a[ret].gender);	printf("请输入新的年龄:\n");	scanf("%d", &p->a[ret].age);	printf("请输入新的电话:\n");	scanf("%s", p->a[ret].phoneNum);	printf("请输入新的地址:\n");	scanf("%s", p->a[ret].adds);	printf("修改成功!\n\n");}

查找

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

测试文件test.c

#include "SeqList.h"int main(){ 	Contact con;	ContactInit(&con);	while (1)	{ 		menu();		int i = 0;		printf("请选择你的操作:");		scanf("%d", &i);		switch (i)		{ 			case 1:				ContactAdd(&con);				break;			case 2:				ContactDle(&con);				break;			case 3:				ContactFind(&con);				break;			case 4:				ContactShow(&con);				break;			case 5:				ContactModify(&con);				break;			case 0:				printf("程序已退出!\n");				break;		}	}	return 0;}

2025-06-24 00:11:51

相关新闻

最新动态

清华大学新闻中心版权所有,清华大学新闻网编辑部维护,电子信箱: news@tsinghua.edu.cn
Copyright 2001-2020 news.tsinghua.edu.cn. All rights reserved.