数据结构(初阶):顺序表实战通讯录
前言
本文将以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 20 typedef 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 20
typedef 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;
}
原文地址:https://blog.csdn.net/zwznzje/article/details/137512646
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!