自学内容网 自学内容网

数据结构(初阶):顺序表实战通讯录

前言 

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

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

        本文将以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)!