✨✨小新课堂开课了,欢迎欢迎~✨✨
🎈🎈养成好习惯,先赞后看哦~🎈🎈
所属专栏:http://t.csdnimg.cn/oHJAK(数据结构与算法)
小新的主页:编程版小新-CSDN博客
今天就和小新一起来实现超级有意思的通讯录项目吧。通讯录其实就是顺序表,对通讯录的实现其实就是对顺序表的实现,只是我们又给顺序表起了一个新的名字叫通讯录。这一点一定要记住,不然在下面实现代码的时候就很容易晕头转向。
在上一篇文章中我们实现的顺序表中存放的是整型数据,现在我们要实现通讯录,根本不同就是存放的数据不同,要实现通讯录,我们存放的是结构体,结构体里包含了联系人的信息。
顺序表(通讯录)的实现是基于结构体,指针,动态内存开辟的,如果不是很理解的话,可以先收藏。http://t.csdnimg.cn/Oytke (这个是C语言的专栏,有需要的话可以看一下)
1.顺序表
我们先看顺序表的实现:
SeqList.c:
#include"SeqList.h"
//顺序表的初始化
void SLInit(SL* ps)//传址调用
{
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
//顺序表的销毁
void SLDestroy(SL* ps)
{
if (ps->arr != NULL)//ps->arr
{
free(ps->arr);
}
ps->arr = NULL;//避免访问野指针
ps->size = ps->capacity = 0;
}
//检查是否用足够的空间
void SLCheck(SL* ps)
{
if (ps->size == ps->capacity)//空间不够
{
//申请空间
//三目操作符
int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//少了等号。一个是赋值
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));//需要申请多大的空间
if (tmp == NULL)
{
perror("realloc fail");
return;
}
//申请成功
ps->arr = tmp;
ps->capacity = newcapacity;
}
}
//打印顺序表
void SLPrint(SL ps)
{
for (int i = 0; i < ps.size; i++)
{
printf("%d ", ps.arr[i]);
}
printf("\n");
}
//顺序表的尾插
void SLPushBack(SL* ps, SLDataType x)
{
assert(ps);
//插入之前要检查是否有空间
SLCheck(ps);
//插入
ps->arr[ps->size++] = x;//细节之后置++
}
//头插
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps);
//插入之前要检查是否有足够的空间
SLCheck(ps);
//先让顺序表中已有的数据整体往后移动一位
for (int i = ps->size; i > 0; i--)
{
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[0] = x;
ps->size++;//不要忘记++
}
//在指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos <= ps->size);
//插入之前要检查空间够不够
SLCheck(ps);
//先让pos及其之后的数据整体往后挪动一位
for (int i = ps->size; i > pos; i--)
{
ps->arr[i] = ps->arr[i - 1];//ps->arr[pos+1]=ps->arr[pos]
}
ps->arr[pos] = x;
ps->size++;
}
//删除指定位置的数据
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
//让pos之后的数据整体往前挪动一位
for (int i = pos; i< ps->size - 1; i++)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
//顺序表的尾删
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size);//顺序表不能为空
--ps->size;
}
//顺序表的头删
void SLPopFront(SL* ps)
{
assert(ps);
assert(ps->size);
//整体往前挪动一位
for (int i = 0; i < ps->size - 1; i++)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
//修改指定位置的数据
void SeqListModify(SL* ps, int pos, SLDataType x)
{
assert(ps); //断言
assert(ps->size > 0); //顺序表不能为空
assert(pos >= 0 && pos < ps->size); //检查pos下标的合法性
ps->arr[pos] = x; //修改pos下标处对应的数据
}
//查找指定数据
int SLFind(SL* ps, SLDataType x)
{
assert(ps);
for (int i = 0; i < ps->size; i++)
{
if (ps->arr[i] == x)
{
//找到了
return i;//返回下标
}
}
//没有找到
return -1;
}
SeqList.h:
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//定义顺序表
//静态顺序表
//#define N 100
//
//struct SeqList
//{
// int arr[N];
// int size;//有效数据个数
//};
//动态顺序表
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* arr;
int size;//有效数据个数
int capacity;//空间大小
}SL;
//顺序表的初始化
void SLInit(SL* ps);
//顺序表的销毁
void SLDestroy(SL* ps);
//尾部插入
void SLPushBack(SL* ps, SLDataType x);
//尾部删除
void SLPopBack(SL* ps);
//头部插入
void SLPushFront(SL* ps, SLDataType x);
//头部删除
void SLPopFront(SL* ps);
//指定位置插入
void SLInsert(SL* ps, int pos, SLDataType x);
//指定位置删除
void SLErase(SL* ps, int pos);
//打印顺序表
void SLPrint(SL ps);
//查找数据
int SLFind(SL* ps, SLDataType x);
//修改指定位置的数据
void SeqListModify(SL* ps, int pos, SLDataType x);
如果不能理解的话: 数据结构:去发现顺序表的魅力所在-CSDN博客
既然通讯录就是顺序表,我们要实现通讯录就是基于在顺序表的基础上去扩展的。
2.通讯录的功能
1.通讯录的声明
2.通讯录的初始化
3.添加联系人
4.删除联系人
5.查找联系人
6.修改联系人
7.展示通讯录
8.销毁通讯录
3.通讯录的功能实现
一定要理解对通讯录的实现就是对顺序表的实现,在顺序表中实现的功能,下面我们会直接调用使用。
3.1通讯录的声明
#pragma once//防止重复引入产生问题
#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100
//定义联系人数据 结构
//姓名 性别 年龄 电话 地址
typedef struct personInfo//方便书写,给结构体起一个简单的名字peoInfo
{
char name[NAME_MAX];
char gender[GENDER_MAX];
int age;
char tel[TEL_MAX];
char addr[ADDR_MAX];
}peoInfo;
3.2通讯录的初始化
对通讯录的实现其实就是就是对顺序表的实现
通讯录就是顺序表,只是又给顺序表起了一个新的名字叫通讯录
实现通讯录要用到顺序表的方法,下面就给顺序表起一个新的名字叫通讯录Contact
typedef struct SeqList Contact;
//通讯录的初始化
void ContactInit(Contact* con)
{
//对通讯录的初始化其实就是对顺序表的初始化
//顺序表的初始化前面已经实现好了,直接调用就好了
SLInit(con);
}
3.3添加联系人数据
//通讯录添加数据
void ContactAdd(Contact* con)
{
//获取用户的内容:姓名+性别+年龄+电话+住址
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.tel);
printf("请输入要添加的联系人的住址\n");
scanf("%s", info.addr);
//往通讯录里添加用户即联系人的信息
//这里采用尾插
SLPushBack(con, info);
}
3.4查找联系人
//通讯录的查找
void ContactFind(Contact* con)
{
char name[NAME_MAX];
printf("请输入要查找的联系人姓名\n");
scanf("%s", name);
int find = FindName(con,name);
if (find < 0)
{
printf("没有该联系人\n");
return;
}
else
{
printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");
printf("%3s %3s %3d %3s %3s\n",
con->arr[find].name,
con->arr[find].gender,
con->arr[find].age,
con->arr[find].tel,
con->arr[find].addr
);//这里根据需要修改格式
}
}
3.5删除联系人数据
//查找联系人姓名
int FindName(Contact* con ,char name[])
{
for (int i = 0; i < con->size; i++)
{
if (0 == strcmp(con->arr[i].name, name))
{
//找到了
return i;
}
}
//没有找到
return -1;
}
//通讯录删除数据
void ContactDel(Contact* con)
{
//要删除的数据必须存在
//查找要删除的联系人
//这里我们按名字进行查找
char name[NAME_MAX];
printf("请输入要删除的联系人姓名\n");
scanf("%s", name);
int find = FindName(con, name);
if (find < 0)
{
printf("要删除的联系人信息不存在\n");
}
//要删除的联系人信息存在
SLErase(con, find);
printf("删除成功\n");
}
3.6修改联系人信息
//修改联系人信息
void ContactModity(Contact* con)
{
//要修改的联系人数据存在
printf("请输入要修改的联系人姓名\n");
char name[NAME_MAX];
scanf("%s", name);
int find = FindName(con, name);
if (find < 0)
{
printf("要修改的联系人信息不存在\n");
return;
}
//直接修改
printf("请输入新的姓名:\n");
scanf("%s", con->arr[find].name);
printf("请输入新的性别:\n");
scanf("%s", con->arr[find].gender);
printf("请输入新的年龄:\n");
scanf("%d",&con->arr[find].age);
printf("请输入新的电话:\n");
scanf("%s", con->arr[find].tel);
printf("请输入新的住址:\n");
scanf("%s", con->arr[find].addr);
printf("修改成功\n");
}
3.7展示通讯录
//展示通讯录
void ContactShow(Contact* con)
{
//打印表头
printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");
//遍历通讯录,打印通讯录的联系人信息
for (int i = 0; i < con->size; i++)
{
printf("%3s %3s %3d %3s %3s\n",
con->arr[i].name,
con->arr[i].gender,
con->arr[i].age,
con->arr[i].tel,
con->arr[i].addr
);//这里根据需要修改位置,让打印的更加美观
}
}
3.9销毁通讯录
//通讯录的销毁
void ContactDestroy(Contact* con)
{
SLDestroy(con);
}
4.整体代码
Contact.h:
#pragma once//防止重复引入问题
#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100
//定义联系人数据 结构
//姓名 性别 年龄 电话 地址
typedef struct personInfo
{
char name[NAME_MAX];
char gender[GENDER_MAX];
int age;
char tel[TEL_MAX];
char addr[ADDR_MAX];
}peoInfo;
//对通讯录的实现其实就是就是对顺序表的实现
//通讯录就是顺序表,只是又给顺序表起了一个新的名字叫通讯录
//实现通讯录要用到顺序表的方法,下面就给顺序表起一个新的名字叫通讯录
typedef struct SeqList Contact;
//通讯录的相关方法
//通讯录的初始化
void ContactInit(Contact* con);
//通讯录的销毁
//void ContactDestroy(Contact* con);
//通讯录添加数据
void ContactAdd(Contact* con);
//通讯录删除数据
void ContactDel(Contact* con);
//通讯录的修改
void ContactModity(Contact* con);
//展现通讯录
void ContactShow(Contact* con);
//查找通讯录
void ContactFind(Contact* con);
Contact.c:
#include"SeqList.h"
#include"Contact.h"
//通讯录的初始化
void ContactInit(Contact* con)
{
//对通讯录的初始化其实就是对顺序表的初始化
//顺序表的初始化前面已经实现好了,直接调用就好了
SLInit(con);
}
//通讯录的销毁
void ContactDestroy(Contact* con)
{
SLDestroy(con);
}
//通讯录添加数据
void ContactAdd(Contact* con)
{
//获取用户的内容:姓名+性别+年龄+电话+住址
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.tel);
printf("请输入要添加的联系人的住址\n");
scanf("%s", info.addr);
//往通讯录里添加用户即联系人的信息
//这里采用尾插
SLPushBack(con, info);
}
//查找联系人
int FindName(Contact* con ,char name[])
{
for (int i = 0; i < con->size; i++)
{
if (0 == strcmp(con->arr[i].name, name))
{
//找到了
return i;
}
}
//没有找到
return -1;
}
//通讯录删除数据
void ContactDel(Contact* con)
{
//要删除的数据必须存在
//查找要删除的联系人
//这里按名字进行查找
char name[NAME_MAX];
printf("请输入要删除的联系人姓名\n");
scanf("%s", name);
int find = FindName(con, name);
if (find < 0)
{
printf("要删除的联系人信息不存在\n");
}
//要删除的联系人信息存在
SLErase(con, find);
printf("删除成功\n");
}
//修改联系人信息
void ContactModity(Contact* con)
{
//要修改的联系人数据存在
printf("请输入要修改的联系人姓名\n");
char name[NAME_MAX];
scanf("%s", name);
int find = FindName(con, name);
if (find < 0)
{
printf("要修改的联系人信息不存在\n");
return;
}
//直接修改
printf("请输入新的姓名:\n");
scanf("%s", con->arr[find].name);
printf("请输入新的性别:\n");
scanf("%s", con->arr[find].gender);
printf("请输入新的年龄:\n");
scanf("%d",&con->arr[find].age);//scanf传入咋用的,好好想想,看下之前的例子,这个得好好记住了,再检查下
printf("请输入新的电话:\n");
scanf("%s", con->arr[find].tel);
printf("请输入新的住址:\n");
scanf("%s", con->arr[find].addr);
printf("修改成功\n");
}
//展示通讯录
void ContactShow(Contact* con)
{
//打印表头
printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");
//遍历通讯录,打印通讯录的联系人信息
for (int i = 0; i < con->size; i++)
{
printf("%3s %3s %3d %3s %3s\n",
con->arr[i].name,
con->arr[i].gender,
con->arr[i].age,
con->arr[i].tel,
con->arr[i].addr
);
}
}
//通讯录的查找
void ContactFind(Contact* con)
{
char name[NAME_MAX];
printf("请输入要查找的联系人姓名\n");
scanf("%s", name);
int find = FindName(con,name);
if (find < 0)
{
printf("没有该联系人\n");
return;
}
else
{
printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");
printf("%3s %3s %3d %3s %3s\n",
con->arr[find].name,
con->arr[find].gender,
con->arr[find].age,
con->arr[find].tel,
con->arr[find].addr
);
}
}
SeqList.h:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include"Contact.h"
//定义数据结构
//静态数据结构
//#define N 100
//
//struct SeqList
//{
// int arr[N];
// int size;//有效数据个数
//};
//动态数据结构
typedef peoInfo SLDataType;
typedef struct SeqList
{
SLDataType* arr;
int size;//有效数据个数
int capacity;//空间大小
}SL;
//顺序表的初始化
void SLInit(SL* ps);
//顺序表的销毁
void SLDestroy(SL* ps);
//尾部插入
void SLPushBack(SL* ps, SLDataType x);
//尾部删除
void SLPopBack(SL* ps);
//头部插入
void SLPushFront(SL* ps, SLDataType x);
//头部删除
void SLPopFront(SL* ps);
//指定位置插入
void SLInsert(SL* ps, int pos, SLDataType x);
//指定位置删除
void SLErase(SL* ps, int pos);
SeqList.c:
#include"SeqList.h"
//顺序表的初始化
void SLInit(SL* ps)//传址调用
{
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
//顺序表的销毁
void SLDestroy(SL* ps)
{
if (ps->arr != NULL)//ps->arr
{
free(ps->arr);
}
ps->arr = NULL;//避免访问野指针
ps->size = ps->capacity = 0;
}
//检查是否用足够的空间
void SLCheck(SL* ps)
{
if (ps->size == ps->capacity)//空间不够
{
//申请空间
//三目操作符
int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));//需要申请多大的空间
if (tmp == NULL)
{
perror("realloc fail");
return;
}
//申请成功
ps->arr = tmp;
ps->capacity = newcapacity;
}
}
//顺序表的尾插
void SLPushBack(SL* ps, SLDataType x)
{
assert(ps);
//插入之前要检查是否有空间
SLCheck(ps);
//插入
ps->arr[ps->size++] = x;//细节之后置++
}
//头插
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps);
//插入之前要检查是否有足够的空间
SLCheck(ps);
//先让顺序表中已有的数据整体往后移动一位
for (int i = ps->size; i > 0; i--)
{
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[0] = x;
ps->size++;//不要忘记++
}
//在指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos <= ps->size);
//插入之前要检查空间够不够
SLCheck(ps);
//先让pos及其之后的数据整体往后挪动一位
for (int i = ps->size; i > pos; i--)
{
ps->arr[i] = ps->arr[i - 1];//ps->arr[pos+1]=ps->arr[pos]
}
ps->arr[pos] = x;
ps->size++;
}
//删除指定位置的数据
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
//让pos之后的数据整体往前挪动一位
for (int i = pos; i< ps->size-1; i++)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
//顺序表的尾删
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size);//顺序表不能为空
--ps->size;
}
//顺序表的头删
void SLPopFront(SL* ps)
{
assert(ps);
assert(ps->size);
//整体往前挪动一位
for (int i = 0; i < ps->size - 1; i++)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
text.c:
#include"SeqList.h"
#include"Contact.h"
通讯录的测试方法
//void SLTest01()
//{
// Contact con;//创建通讯录对象其实实际上就是顺序表对象 等同于SL sl
// SLInit(&con);
// ContactAdd(&con);
// ContactAdd(&con);
// ContactShow(&con);
//
//
//}//大家在实现通讯录的功能的时候,可以写完一个功能就去测试一个功能,避免堆在一起难找到错误
void menu()
{
printf("****************通讯录****************\n");
printf("******1.增加联系人 2.删除联系人******\n");
printf("******3.修改联系人 4.查找联系人******\n");
printf("******5.展示联系人 0. 退出 *******\n");
printf("**************************************\n");
}
int main()
{
int op = 0;
Contact con;
ContactInit(&con);
do{
menu();
printf("请选择菜单:");
scanf("%d", &op);
switch (op)
{
case 1:
ContactAdd(&con);
break;
case 2:
ContactDel(&con);
break;
case 3:
ContactModity(&con);
break;
case 4:
ContactFind(&con);
break;
case 5:
ContactShow(&con);
break;
case 0:
printf("退出通讯录...\n");
break;
default:
printf("输出错误,请重新选择你的操作\n");
break;
}
} while (op != 0);
//SLTest01();
ContactDestroy(&con);
return 0;
}
下课了~
下次别忘了来哦