数据结构·顺序表实现通讯录

目录

1 基本格式

2 结构体的声明

3 初始化 销毁 扩容 插入 删除

4 增加联系人

5 查看通讯录

6 删除联系人

7 查找联系人

8 修改联系人

9 整体代码


引言:

有了前面顺序表的基础,我们可以尝试利用顺序表实现通讯录,日常使用中,通讯录可以实现的功能有增加联系人,删除联系人,查找联系人,修改联系人,查看联系人等,我们通过本章的学习实现以上五种功能(默认通讯录包含的元素有 名称 性别 年龄 电话号码 地址 )


1 基本格式

通讯录算是一个小的程序了,人们在使用之前都习惯于有菜单,所以我们使用do-while循环,加上switch语句,可以打印菜单,并且用户可以多次选择执行的操作:

void menu()
{printf("************通讯录***************\n");printf("***1 增加联系人   2 删除联系人***\n");printf("***3 查看通讯录   4 修改联系人***\n");printf("***5 查找联系人   0 退出通讯录***\n");
}
int main()
{int input = 0;Seq con;ConInit(&con);do{menu();printf("请输入您的操作:\n");scanf("%d", &input);switch (input){case 1:ContactAdd(&con);//增加联系人break;case 2:ContactDel(&con);//删除联系人break;case 3:ContactPrint(&con);//查看通讯录break;case 4:ContactMod();//修改联系人break;case 5:ContactFind();//查找联系人break;case 0:printf("正在退出通讯录……\n");break;default:printf("操作无效,重新输入:\n");break;}} while (input);ConDestroy(&con);return 0;
}

case 对应的语句就是我们要执行的操作,大的操作有增删查改以及查找五个操作,那么在实现之前,顺序表的结构体类型,结构体的初始化,空间扩容,空间的销毁等都是要先写上的,为了方便起见,我们使用两个.c文件,一个.h文件,提高代码的整洁度,一个是contact.c文件,一个是contact.h文件(contact是通讯录的意思),同上篇文章一样,函数的声明,结构体的定义放在头文件里面,函数的具体实现放在contact.c文件里面。


2 结构体的声明

#pragma once
#define NAME_MAX 100
#define TEL_MAX 12
#define GENDER_MAX 10
#define ADDR_MAX 100typedef struct Contact
{int age;char name[NAME_MAX];char tel[TEL_MAX];char gender[GENDER_MAX];char addr[ADDR_MAX];
}Con;typedef Con Datatype;typedef struct St
{Datatype* arr;int size;//有效数据个数int capacity;//空间大小
}Seq;

在contact头文件里面我们创建好联系人对应的结构体变量Contact,为了方便起见重命名为Con,随后我们创建好一个结构体变量用来给联系人开辟空间,这里可能有点绕,重命名Contact的目的是为了之后数据的易转换,像int全转为float类型,重命名St的目的是为了之后传参方便,我们传参传的是结构体本身,可以理解为Seq*指针指向的arr是Datatype类型的,而Datatype类型又是Con结构的,Con结构体就是我们需要的联系人数据类型,开辟空间的时候就是以整个结构体开辟空间的。


3 初始化 销毁 扩容 插入 删除

void ConInit(Seq* pcon)//初始化
{pcon->arr = NULL;pcon->size = pcon->capacity = 0;
}
void ConDestroy(Seq* pcon)//销毁
{assert(pcon);pcon->arr = NULL;pcon->size = pcon->capacity = 0;free(pcon->arr);
}

初始化和销毁和顺序表的初始化销毁是一样的,当然,引用的头文件不能忘记,指针断言,空间释放都是不能忘记的。

插入数据的时候,我们这里为了方便起见,就用尾部插入,删除我们使用的是指定位置删除,因为之后的删除联系人需要系统需要知道联系人的位置,所以采用的是指定位置删除:

void ConCheckCapacity(Seq* pcon)//扩容
{if (pcon->capacity == 0){pcon->arr = (Datatype*)malloc(4 * sizeof(Datatype));pcon->capacity = 4;}if (pcon->capacity == pcon->size){Datatype* tem = (Datatype*)realloc(pcon->arr, 2 * pcon->capacity * sizeof(Datatype));if (tem != NULL){pcon->arr = tem;pcon->capacity *= 2;}else{perror("realloc fail!");return;}}
}
void ConPushBack(Seq* pcon, Datatype x)//尾插
{assert(pcon);ConCheckCapacity(pcon);pcon->arr[pcon->size++] = x;
}
void ContactErase(Seq* pcon, int pos)//指定删除
{assert(pcon);assert(pos >= 0 && pos < pcon->size);for (int i = pos; i < pcon->size - 1; i++){pcon->arr[i] = pcon->arr[i + 1];}pcon->size--;
}

这五个基本操作可以说是为了后面的几大功能做铺垫,且与之前的顺序表并无两样。


4 增加联系人

增加联系人之前,我们已经做好了初始化 判断扩容 插入等基本操作,现在增加联系人可以说是易如反掌了:
我们添加联系人之前,我们需要先创建好一个联系人,这时候就用上了之前重命名的Con结构体了,然后就是大同小异的输入,输出,最后使用尾插函数,把这个联系人存储进去就行了。

void ContactAdd(Seq* pcon)//增加联系人
{Con contact;printf("输入联系人姓名:");scanf("%s", contact.name);printf("输入联系人性别:");scanf("%s", contact.gender);printf("输入联系人年龄:");scanf("%d", contact.age);printf("输入联系人电话:");scanf("%s", contact.tel);printf("输入联系人地址:");scanf("%s", contact.addr);ConPushBack(pcon, contact);printf("添加成功!");
}

5 查看通讯录

查看通讯录无非就是打印通讯录,那么只需要用上最基本的for循环就行了:

void ContactPrint(Seq* pcon)//查看通讯录
{assert(pcon);printf("姓名  性别  年龄  电话号码  地址\n");for (int i = 0; i < pcon->size; i++){printf("%s %s %d %s %s", pcon->arr[i].name,pcon->arr[i].gender,pcon->arr[i].age,pcon->arr[i].tel,pcon->arr[i].addr);}printf("\n");
}

为了界面整洁我们可以在打印联系人数据的时候打印出联系人的基本框架出来:

最后就是换行符不要忘记就行。


6 删除联系人

在执行删除联系人之前应该先遍历整个通讯录看有没有这个联系人,如果没有,也就不存在删除的说法,所以下一个实现的函数是查找联系人,联系人有多种数据,其中重叠可能性最小的是姓名,即我们可以使用姓名来查找联系人,因为查找联系人是为了之后的删除,修改联系人做准备,查找联系人的返回值可以有正负,i -1,i就表示找到了,存在这个联系人,下标为i,-1就表示没有找到,不存在这个联系人:

int FindByname(Seq* pcon,char name[NAME_MAX])//通过姓名寻找
{for (int i = 0; i < pcon->size; i++){if (strcmp(name, pcon->arr[i].name) == 0){return i;}}return -1;
}

我们是通过联系人姓名来寻找的,所以首先遍历空空间,利用strcmp的返回值来判断是否存在

void ContactDel(Seq* pcon)//删除联系人
{assert(pcon);char name[NAME_MAX];printf("请输入要删除的联系人的姓名:");scanf("%s", name);int tem = FindByname(pcon, name);if (tem < 0){printf("要删除的联系人不存在!");return;}ContactErase(pcon, tem);printf("删除成功!\n");
}

删除就是利用的返回值,大于0呢,就删除,小于0就直接返回。


7 查找联系人

查找联系人用到的函数其实就是FIndByname函数,只不过加了一点点改变而已,通过返回值进行判断,然后进行打印就行了:

void ContactFind(Seq* pcon)//查找联系人
{assert(pcon);char name[NAME_MAX];printf("请输入联系人姓名:");scanf("%s", name);int tem = FindByname(pcon, name);if (tem >= 0){printf("找到了!\n");printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");printf("%s %s %d %s %s\n", pcon->arr[tem].name,pcon->arr[tem].gender,pcon->arr[tem].age,pcon->arr[tem].tel,pcon->arr[tem].addr);}else{printf("联系人不存在!\n");}
}

8 修改联系人

修改联系人的基础是在于能否找到,所以还是需要FindByname函数,找到这个联系人之后,我们就需要利用返回的下标,来实现修改联系人数据:

void ContactMod(Seq* pcon)//修改联系人
{assert(pcon);char name[NAME_MAX];printf("请输入要修改的联系人的姓名:");scanf("%s", name);int tem = FindByname(pcon, name);if (tem >= 0){printf("存在该联系人,请修改:\n");printf("输入联系人姓名:");scanf("%s", pcon->arr[tem].name);printf("输入联系人性别:");scanf("%s", pcon->arr[tem].gender);printf("输入联系人年龄:");scanf("%d", pcon->arr[tem].age);printf("输入联系人电话:");scanf("%s", pcon->arr[tem].tel);printf("输入联系人地址:");scanf("%s", pcon->arr[tem].addr);printf("修改成功!\n");}else{printf("不存在该联系人!\n");}
}

在每次函数开头的时候,我们都应该使用assert断言,因为我们不知道程序执行到这一步的时候指针有没有变成空指针,在使用完FindByname的时候,我们利用下标进行修改,修改为无非就是进行重新输入。


9 整体代码

以上就就是顺序表实现通讯录的全部过程,整体代码如下:

contact头文件:

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define NAME_MAX 100
#define TEL_MAX 12
#define GENDER_MAX 10
#define ADDR_MAX 100typedef struct Contact
{int age;char name[NAME_MAX];char tel[TEL_MAX];char gender[GENDER_MAX];char addr[ADDR_MAX];
}Con;typedef Con Datatype;typedef struct St
{Datatype* arr;int size;//有效数据个数int capacity;//空间大小
}Seq;void ConInit(Seq* pcon);//初始化
void ConDestroy(Seq* pcon);//销毁
void ConCheckCapacity(Seq* pcon);//扩容
void ConPushBack(Seq* pcon, Datatype x);//尾插
void ContactErase(Seq* pcon, int pos);//指定删除
void ContactAdd(Seq* pcon);// 增加联系人
void ContactPrint(Seq* pcon);//查看通讯录
void ContactDel(Seq* pcon);//删除联系人
void ContactMod(Seq* pcon);//修改联系人
void ContactFind(Seq* pcon);//查找联系人

contact.c文件: 

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"
void ConInit(Seq* pcon)//初始化
{pcon->arr = NULL;pcon->size = pcon->capacity = 0;
}
void ConDestroy(Seq* pcon)//销毁
{assert(pcon);pcon->arr = NULL;pcon->size = pcon->capacity = 0;free(pcon->arr);
}
void ContactErase(Seq* pcon, int pos)//指定删除
{assert(pcon);assert(pos >= 0 && pos < pcon->size);for (int i = pos; i < pcon->size - 1; i++){pcon->arr[i] = pcon->arr[i + 1];}pcon->size--;
}
void ConCheckCapacity(Seq* pcon)//扩容
{if (pcon->capacity == 0){pcon->arr = (Datatype*)malloc(4 * sizeof(Datatype));pcon->capacity = 4;}if (pcon->capacity == pcon->size){Datatype* tem = (Datatype*)realloc(pcon->arr, 2 * pcon->capacity * sizeof(Datatype));if (tem != NULL){pcon->arr = tem;pcon->capacity *= 2;}else{perror("realloc fail!");return;}}
}
void ConPushBack(Seq* pcon, Datatype x)//尾插
{assert(pcon);ConCheckCapacity(pcon);pcon->arr[pcon->size++] = x;
}
void ContactAdd(Seq* pcon)//增加联系人
{Con contact;printf("输入联系人姓名:");scanf("%s", contact.name);printf("输入联系人性别:");scanf("%s", contact.gender);printf("输入联系人年龄:");scanf("%d", &contact.age);printf("输入联系人电话:");scanf("%s", contact.tel);printf("输入联系人地址:");scanf("%s", contact.addr);ConPushBack(pcon, contact);printf("添加成功!\n");
}
void ContactPrint(Seq* pcon)//查看通讯录
{assert(pcon);printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");for (int i = 0; i < pcon->size; i++){printf("%s %s %d %s %s\n", pcon->arr[i].name,pcon->arr[i].gender,pcon->arr[i].age,pcon->arr[i].tel,pcon->arr[i].addr);}printf("\n");
}
int FindByname(Seq* pcon,char name[NAME_MAX])//通过姓名寻找
{for (int i = 0; i < pcon->size; i++){if (strcmp(name, pcon->arr[i].name) == 0){return i;}}return -1;
}
void ContactDel(Seq* pcon)//删除联系人
{assert(pcon);char name[NAME_MAX];printf("请输入要删除的联系人的姓名:");scanf("%s", name);int tem = FindByname(pcon, name);if (tem < 0){printf("要删除的联系人不存在!");return;}ContactErase(pcon, tem);printf("删除成功!\n");
}
void ContactMod(Seq* pcon)//修改联系人
{assert(pcon);char name[NAME_MAX];printf("请输入要修改的联系人的姓名:");scanf("%s", name);int tem = FindByname(pcon, name);if (tem >= 0){printf("存在该联系人,请修改:\n");printf("输入联系人姓名:");scanf("%s", pcon->arr[tem].name);printf("输入联系人性别:");scanf("%s", pcon->arr[tem].gender);printf("输入联系人年龄:");scanf("%d", pcon->arr[tem].age);printf("输入联系人电话:");scanf("%s", pcon->arr[tem].tel);printf("输入联系人地址:");scanf("%s", pcon->arr[tem].addr);printf("修改成功!\n");}else{printf("不存在该联系人!\n");}
}
void ContactFind(Seq* pcon)//查找联系人
{assert(pcon);char name[NAME_MAX];printf("请输入联系人姓名:");scanf("%s", name);int tem = FindByname(pcon, name);if (tem >= 0){printf("找到了!\n");printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");printf("%s %s %d %s %s\n", pcon->arr[tem].name,pcon->arr[tem].gender,pcon->arr[tem].age,pcon->arr[tem].tel,pcon->arr[tem].addr);}else{printf("联系人不存在!\n");}
}

  主函数.c: 

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "Contact.h"
void menu()
{printf("************通讯录***************\n");printf("***1 增加联系人   2 删除联系人***\n");printf("***3 查看通讯录   4 修改联系人***\n");printf("***5 查找联系人   0 退出通讯录***\n");
}
int main()
{int input = 0;Seq con;ConInit(&con);do{menu();printf("请输入您的操作:\n");scanf("%d", &input);switch (input){case 1:ContactAdd(&con);//增加联系人break;case 2:ContactDel(&con);//删除联系人break;case 3:ContactPrint(&con);//查看通讯录break;case 4:ContactMod(&con);//修改联系人break;case 5:ContactFind(&con);//查找联系人break;case 0:printf("正在退出通讯录……\n");break;default:printf("操作无效,重新输入:\n");break;}} while (input);ConDestroy(&con);return 0;
}

感谢阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/708780.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【论文阅读】微纳米气泡技术作为CO2-EOR和CO2地质储存技术的新方向:综述

Micro and nanobubbles technologies as a new horizon for CO2-EOR and CO2 geological storage techniques: A review 微纳米气泡技术作为CO2-EOR和CO2地质储存技术的新方向&#xff1a;综述 期刊信息&#xff1a;Fuel 2023 期刊级别&#xff1a;EI检索 SCI升级版工程技术1区…

【LeetCode-简单】69.x的平方根 + 367.有效的完全平方数 - 二分法

力扣题目链接 给定非负整数x&#xff0c;求x的算数平方根&#xff08;只保留整数部分&#xff09; 这个问题可以看成在区间 [0, x) 中寻找一个整数 target 使得 target * target 趋近于x 采用二分法&#xff0c;排除0与1这两个特殊情况后&#xff08;不排除则left 0, right…

Python实现时间序列分析进行平稳性检验(ADF和KPSS)和差分去趋势(adfuller和kpss算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 时间序列分析中的平稳性检验是评估一个时间序列是否具有稳定的均值和方差。在经济学、金融学以及其他诸…

麒麟OS:操作系统国家队

这是ren_dong的第31篇原创 1、中标软件 中标软件&#xff1a;国产操作系统龙头 中标软件有限公司成立于2003 年&#xff0c;是国产自主操作系统和办公软件产品提供商&#xff0c;拥有 国防、民用两方面的相关企业与产品资质&#xff0c;是安全操作系统旗舰企业。 中标软件的主要…

飞天使-学以致用-devops知识点3-安装jenkins

文章目录 构建带maven环境的jenkins 镜像安装jenkinsjenkins yaml 文件安装插件jenkins 配置k8s创建用户凭证 构建带maven环境的jenkins 镜像 # 构建带 maven 环境的 jenkins 镜像 docker build -t 192.168.113.122:8858/library/jenkins-maven:jdk-11 .# 登录 harbor docker …

解读人工智能的理论基石

1956年的一个夏天&#xff0c;在达特茅斯学院的一个小会议室里&#xff0c;一群充满好奇和野心的年轻科学家聚集在一起&#xff0c;他们有一个共同的梦想&#xff1a;创造能够模仿人类智能的机器。这不仅仅是科幻小说的情节&#xff0c;更是人工智能历史上一个真实的起点。从那…

基于JAVA的毕业生追踪系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 登陆注册模块2.2 学生基本配置模块2.3 就业状况模块2.4 学历深造模块2.5 信息汇总分析模块2.6 校友论坛模块 三、系统设计3.1 用例设计3.2 实体设计 四、系统展示五、核心代码5.1 查询我的就业状况5.2 初始化就业状况5.…

防御保护:防火墙内容安全

一、IAE&#xff08;Intelligent Awareness Engine&#xff09;引擎 二、深度检测技术(DFI和DPI&#xff09; 1.DPI – 深度包检测技术 DPI主要针对完整的数据包&#xff08;数据包分片&#xff0c;分段需要重组&#xff09;&#xff0c;之后对数据包的内容进行识别。&#x…

微服务 人工智能AI 物联网智慧工地云平台源码

目录 ​编辑 智慧工地架构 智慧工地系统 智慧工地云平台功能模块 1、基础数据管理 2、考勤管理 3、安全隐患管理 4、视频监控 5、塔吊监控 6、升降机监控 7、移动端数据推送 智慧工地管理平台子系统构成 智慧工地物联网解决方案&#xff0c;对工地施工安全人员、设…

2024.2.28 训练记录(3)

还有个扫描线单调栈树状数组的没有完全搞懂今天不写&#xff0c;晚上vp了下昨天的div3&#xff0c;绝佳的上分机会居然没打&#xff0c;好顺手的A-E。。。 洛谷 P1050 [NOIP2005 普及组] 循环 题目链接 按位来看&#xff0c;先看最后一位&#xff0c;假设乘x次循环&#xff…

引入本地图片报错:require is not defined

文章目录 问题分析1. 原始写法2. 最初的解决方案3. 尝试使用 require 引入4. 封装方法进行解析引入图片 问题 Vue3 Vite 使用本地图片报错&#xff1a;require is not defined 分析 1. 原始写法 刚开始我是这样写的&#xff0c;数据是这样定义的&#xff0c;但是数据没出…

【Linux深入剖析】再续环境变量 | 进程地址空间

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1.环境变量再续1.1 和…

FX110网:外汇交易中的隔夜利息该如何计算?

在交易过程中&#xff0c;我们经常能够听到 “隔夜利息”这个词&#xff0c;但不少新手依然不是很明白这个专业名词的意思。今天小编帮助大家理解这个概念。“隔夜利息”的含义 顾名思义&#xff0c;是根据持仓总数计算的每日可赚取或需支付的利息。每个货币都有他们自己的基准…

蓝桥杯备赛第三篇(图论)

1.邻接表 static class Edge {int next;int value;public Edge(int next, int value) {this.next next;this.value value;}}static HashMap<Integer, LinkedList<Edge>> graph new HashMap<>();public static void addEgde(int from, int to, int value) …

贝叶斯优化双向门控循环单元BO-BIGRU时序预测的matlab实现【源代码】

贝叶斯优化双向门控循环单元简介&#xff1a; 贝叶斯优化双向门控循环单元&#xff08;BO-BIGRU&#xff09;是一种结合了贝叶斯优化和双向门控循环单元&#xff08;BIGRU&#xff09;的神经网络模型。BIGRU是一种改进的循环神经网络&#xff08;RNN&#xff09;&#xff0c;它…

go语言通过切片实现先进后出逻辑

目录 一、go语言的通道: 二、go语言实现先进后出: 一、go语言的通道: Go的通道(Channel)是先进先出(FIFO)的数据结构,它保持了发送数据和接收数据的顺序。当你向通道发送数据时,数据会被放入通道的尾部;而从通道接收数据时,会从通道的头部取出数据。这确保了数据的…

现代信号处理学习笔记(二)参数估计理论

参数估计理论为我们提供了一套系统性的工具和方法&#xff0c;使我们能够从样本数据中推断总体参数&#xff0c;并评估估计的准确性和可靠性。这些概念在统计学和数据分析中起着关键的作用。 目录 前言 一、估计子的性能 1、无偏估计与渐近无偏估计 2、估计子的有效性 两个…

Python入门到精通(九)——Python数据可视化

Python数据可视化 一、JSON数据格式 1、定义 2、python数据和JSON数据转换 二、pyecharts 三、折线图 四、地图 五、动态柱状图 一、JSON数据格式 1、定义 JSON是一种轻量级的数据交互格式。可以按照JSON指定的格式去组织和封装数据JSON本质上是一个带有特定格式的字符…

小程序 API 能力汇总——TYML NodesRef API

NodesRef 用于获取 TYML 节点信息的对象 方法 SelectorQuery NodesRef.fields(Object fields, NodesRef.FieldsCallback callback) 获取节点的相关信息。需要获取的字段在 fields 中指定。返回值是 nodesRef 对应的 selectorQuery SelectorQuery NodesRef.boundingClientR…

嘴尚绝卤味传统与创新的完美结合

在当下这个美食文化丰富多彩的时代&#xff0c;卤味作为一种深受大众喜爱的食品&#xff0c;不仅承载着传统的烹饪智慧&#xff0c;更在不断创新中展现出新的魅力。嘴尚绝卤味&#xff0c;作为卤味市场中的佼佼者&#xff0c;凭借其独特的优势&#xff0c;正逐渐成为消费者心中…