【数据结构】利用顺序表实现通讯录

文章目录

  • 前言
  • 通讯录要求
  • 利用顺序表的现有功能
  • 代码呈现


前言

这篇文章实现的通讯录利用了笔者上一篇写的有关顺序表的应用 https://blog.csdn.net/2301_77954967/article/details/137360029?spm=1001.2014.3001.5502,需要用的朋友自行复制

通讯录要求

1)至少能够存储100个人的通讯信息
2)能够保存用户信息:名字、性别、年龄、电话、地址等
3)增加联系人信息
4)删除指定联系人
5)查找制定联系人
6)修改指定联系人
7)显示联系人信息
8)能够保存信息用于下次读取


利用顺序表的现有功能

我们现在contact.h的头文件里建立如下结构体,

#define NAME_MAX 100
#define GENDER_MAX 10  //male female
#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;

我们可以把这个通讯录中的每个人的信息看成一个顺序表中每一个数组的数据,这样一来就只需要将这里的类型名 peoInfo 给重命名成 SLDataType 就行了,需要注意的是,这里是两个头文件,不仅需要放在同一目录下,还需要在 SeqList.h 文件里附加上 Contact.h 的头文件名

#include"Contact.h"typedef peoInfo SLDataType;//将proInfo改成SLDataTypetypedef struct SeqList
{SLDataType* arr;int size;//有效数据个数int capacity;//空间大小
}SL;

再然后,如果后续的功能名仍用 SL 来命名会有些模糊,但是两个头文件之间不能互相引用,那么这里我们可以回到 Contact.h 里,进行前置声明,

typedef struct SeqList Contact;//前置声明,用顺序表里第一个创立的结构体名SeqList,而不是SL

这样一来就是要进行方案功能的实现就行了,开始工作做好了,后面就会简单很多

//初始化通讯录
void InitContact(Contact* con);//添加通讯录数据
void AddContact(Contact* con);//删除通讯录数据
void DelContact(Contact* con);//展示通讯录数据
void ShowContact(Contact* con);//查找通讯录数据
void FindContact(Contact* con);//修改通讯录数据
void ModifyContact(Contact* con);//销毁通讯录数据
void DestroyContact(Contact* con);

假设我们上面几个方法都已经完善并测验好了,我们需要思考的如何使这些数据进行保存,方便下一次读取,这里就需要用到文件了

这里我们选择用二进制文件的方式读取和写入,原因是,这里我们利用了 peoInfo 这个现有的结构体,和 SLPushBack 这个现有的方法,不需要以文本文件格式化的形式读入文件,再花费功夫去调整文本文件的格式


代码呈现

Contact.h

#pragma once//同一个文件不会被包含多次。这里所说的”同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件#define _CRT_SECURE_NO_WARNINGS  1
#pragma warning(disable:6031)
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>#define NAME_MAX 100
#define GENDER_MAX 10  //male female
#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 InitContact(Contact* con);//添加通讯录数据
void AddContact(Contact* con);//删除通讯录数据
void DelContact(Contact* con);//展示通讯录数据
void ShowContact(Contact* con);//查找通讯录数据
void FindContact(Contact* con);//修改通讯录数据
void ModifyContact(Contact* con);//销毁通讯录数据
void DestroyContact(Contact* con);//利用文件保存数据
//读取
void LoadContact(Contact* con);//写入
void SaveContact(Contact* con);

SeqList.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS  1
#pragma warning(disable:6031)
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>#include"Contact.h"//头文件之间不能互相包含typedef peoInfo SLDataType;//将proInfo改成SLDataTypetypedef struct SeqList
{SLDataType* arr;int size;//有效数据个数int capacity;//空间大小
}SL;//typedef struct SeqList SL;//将这个顺序表的类型名简化成SL//顺序表初始化
void SLInit(SL* ps);
//顺序表的销毁
void SLDestory(SL* ps);//尾部插入
void SLPushBack(SL* ps, SLDataType x);
//头部插入
void SLPushFront(SL* ps, SLDataType x);//尾部删除
void SLPopBack(SL* ps);
//头部删除
void SLPopFront(SL* ps);//扩容
void SLCheckCapacity(SL* ps);
//打印
void SLPrint(SL s);//在指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x);
//删除指定位置的数据
void SLErase(SL* ps, int pos);//查找
int SLFind(SL* ps, SLDataType x);

Contact.c

#include"Contact.h"
#include"SeqList.h"//初始化通讯录
void InitContact(Contact* con)
{//实际上要进行的是顺序表的初始化//con->arr = NULL;//con->capacity = con->size = 0;SLInit(con);LoadContact(con);
}//销毁通讯录数据
void DestroyContact(Contact* con)
{SaveContact(con);SLDestory(con);
}//添加通讯录数据
void AddContact(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);//顺序表中已有功能的复用
}//查找通讯录数据(依靠名字)
FindByName(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 DelContact(Contact* con)
{//要删除的数据必须要存在,才能执行删除操作//查找char name[NAME_MAX];printf("请输入要删除的联系人名字:\n");scanf("%s", name);int find = FindByName(con, name);if (find < 0){printf("要删除的联系人数据不存在!\n");return;}//要删除的联系人数据存在从 -> 知道了要删除联系人的下标SLErase(con, find);printf("删除成功!\n");
}//展示通讯录数据
void ShowContact(Contact* con)
{//打印表头printf("%5s %5s %5s %5s %5s\n", "姓名", "性别", "年龄", "电话", "地址");//遍历通讯录,按照格式打印每个联系人数据for (int i = 0; i < con->size; i++){printf("%5s %5s %5d %5s %5s\n",con->arr[i].name,con->arr[i].gender,con->arr[i].age,con->arr[i].tel,con->arr[i].addr);}
}//修改通讯录数据
void ModifyContact(Contact* con)
{char name[NAME_MAX];printf("请输入要修改的数据\n");scanf("%s", name);int find = FindByName(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");
}//查找通讯录数据
void FindContact(Contact* con)
{char name[NAME_MAX];printf("请输入要查找的联系人:\n");scanf("%s", name);int find = FindByName(con,name);if (find < 0){printf("要查找的联系人数据不存在\n");return;}printf("%5s %5s %5s %5s %5s\n", "姓名", "性别", "年龄", "电话", "地址");printf("%5s %5s %5d %5s %5s\n",con->arr[find].name,con->arr[find].gender,con->arr[find].age,con->arr[find].tel,con->arr[find].addr);}//利用文件保存数据
//读取
void LoadContact(Contact* con)
{FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("fopen error!\n");return;}//循环读取文件数据peoInfo info;while (fread(&info, sizeof(peoInfo), 1, pf)){SLPushBack(con, info);}fclose(pf);pf = NULL;printf("历史数据写入成功!\n");
}//写入
void SaveContact(Contact* con)
{FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("fopen error!\n");return;}for (int i = 0; i < con->size; i++){fwrite(con->arr + i, sizeof(peoInfo), 1, pf);}fclose(pf);pf = NULL;printf("通讯录数据保存成功!\n");
}

SeqList.c

#include"SeqList.h"//初始化顺序表
void SLInit(SL* ps)
{ps->arr = NULL;ps->size = ps->capacity = 0;}//顺序表的销毁
void SLDestory(SL* ps)
{if (ps->arr){free(ps->arr);}ps->arr = NULL;ps->size = ps->capacity = 0;
}//扩容
void SLCheckCapacity(SL* ps)
{//插入数据前看看空间够不够if (ps->size == ps->capacity){//扩容,申请空间int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//三目表达式SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * 2 * sizeof(SLDataType));if (tmp == NULL){perror("realloc fail!");exit(1);}//空间申请成功ps->arr = tmp;ps->capacity = newCapacity;}
}//打印
void SLPrint(SL s)
{for (int i = 0; i < s.size; i++){printf("%d ", s.arr[i]);}printf("\n");
}//在尾部插入
void SLPushBack(SL* ps, SLDataType x)
{//温柔的解决方式//if(ps == NULL)//{//	return 0;//}assert(ps);////扩容SLCheckCapacity(ps);//ps->arr[ps->size] = x;//++ps->size;ps->arr[ps->size++] = x;
}//头插
void SLPushFront(SL* ps, SLDataType x)
{//扩容SLCheckCapacity(ps);//先将顺序表中已有的数据整体往后移动一位for (int i = ps->size; i > 0; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[0] = x;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 SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);//扩容,判断空间够不够SLCheckCapacity(ps);//让pos之后及其自身往后移动一位for (int i = ps->size; i > pos; i--){ps->arr[i] = ps->arr[i - 1];}ps->size++;ps->arr[pos] = x;
}//删除指定位置的数据
void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);for (int i = pos; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}//查找
//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;
//}

test.c

#include"Contact.h"
#include"SeqList.h"通讯录测试
//void ContactTest01()
//{
//	Contact con;//创建通讯录对象
//	InitContact(&con);
//
//	//测试添加数据功能
//	AddContact(&con);
//	AddContact(&con);
//
//	//测试删除数据功能
//	DelContact(&con);
//
//	//测试打印功能
//	ShowContact(&con);
//	
//	//销毁通讯录数据
//	DestroyContact(&con);
//
//}
//
//int main1()
//{
//	ContactTest01();
//	return 0;
//}void menu()
{printf("*******************通讯录******************\n");printf("*****1.增加联系人  ******  2.删除联系人****\n");printf("*****3.修改联系人  ******  4.查找联系人****\n");printf("*****5.展示联系人  ******  0.  退  出  ****\n");printf("*******************************************\n");
}
int main()
{int op = -1;Contact con;InitContact(&con);do{menu();printf("请选择您的操作:\n");scanf("%d", &op);//要根据对应的op执行不同的操作switch (op){case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:ModifyContact(&con);break;case 4:FindContact(&con);break;case 5:ShowContact(&con);break;case 0:op = 0;printf("退出通讯录中......\n");break;default:printf("选择错误!请重新选择\n");break;}}while(op != 0);printf("退出成功\n");DestroyContact(&con);return 0;
}

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

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

相关文章

PostgreSQL入门到实战-第七弹

PostgreSQL入门到实战 PostgreSQL查询语句(四)官网地址PostgreSQL概述PostgreSQL中DISTINCT 语句介绍PostgreSQL中DISTINCT 语句实操更新计划 PostgreSQL查询语句(四) 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https:…

【测试篇】Selenium + Java环境搭建

文章目录 Selenium Java环境搭建配置系统环境变量PATH验证环境是否搭建成功常见问题&解决办法 Selenium Java环境搭建 Java版本最低要求为8&#xff0c;这里默认大家都下载好了Java。&#x1f606; 下载chrome浏览器&#xff08;点我下载&#xff09; 观察chrome版本。…

设备监控公有云

在数字化浪潮的推动下&#xff0c;越来越多的企业开始关注设备监控公有云这一重要领域。设备监控公有云通过云计算技术&#xff0c;实现对设备的远程监控、管理和维护&#xff0c;大大提高了企业的运营效率和管理水平。HiWoo Cloud平台作为领先的设备监控公有云解决方案提供商&…

【数据库】PostgreSQL源码编译安装方式与简单配置(v16.2)

PostgreSQL源码编译安装方式与简单配置&#xff08;v16.2&#xff09; 一、PostgreSQL安装基本介绍1.1 几种PostgreSQL的安装方式1.2 删除原有的PostgreSQL1.3 编译安装过程简介 二、源码编译安装方式详情2.1 下载源代码2.2 编译安装运行 configure执行 make执行 make install …

力扣207.课程表

你这个学期必须选修 numCourses 门课程&#xff0c;记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出&#xff0c;其中 prerequisites[i] [ai, bi] &#xff0c;表示如果要学习课程 ai 则 必须 先学习课程 bi 。 例如…

SSM党员管理系统

一、系统介绍 党员管理系统: 可以方便管理人员对党员管理系统的管理&#xff0c;提高信息管理工作效率及查询效率&#xff0c;有利于更好的为用户提供服务。 主要的模块包括&#xff1a; 1、后台功能&#xff1a; 管理员角色&#xff1a;首页、个人中心&#xff0c;党员管理…

前端开发语言概览:从HTML、CSS到JavaScript

随着互联网的发展&#xff0c;前端开发领域涌现出了许多不同的编程语言和技术&#xff0c;用于构建各种类型的网页和应用程序。本文将介绍几种主流的前端开发语言&#xff0c;包括 HTML、CSS 和 JavaScript&#xff0c;并简要讨论它们在前端开发中的作用和特点。 1. HTML&…

Naiveui将message挂载到axios拦截器

最近在做项目&#xff0c;需要将后端的请求结果打印出来 但是想着&#xff0c;要是这样一个一个手动引入naiveui的msg&#xff0c;那不得累死 于是灵机一动&#xff0c;想着既然所有接口要通过拦截器&#xff0c;为什么不将msg写在拦截器呢 一、定义一个消息挂载文件 // The…

【java面试题-Redis篇-2024】

##java面试题大全 详细面试题-持续更新中-点击跳转 点赞、收藏、加关注 java基础面试题 ##java面试题大全1、什么是 Redis2、Redis 的数据结构类型3、Redis 为什么快4、什么是跳跃表5、什么是 I/O 多路复用6、什么是缓存击穿、缓存穿透、缓存雪崩7、什么是布隆过滤器8、热…

经典文章:卷积神经网络的运作原理

https://brohrer.mcknote.com/zh-Hans/how_machine_learning_works/how_convolutional_neural_networks_work.html 参考资料 https://aitechtogether.com/article/38900.html https://www.ruanyifeng.com/blog/2017/07/neural-network.html http://neuralnetworksanddeeplea…

golang 使用 cipher、aes 实现 oauth2 验证

在Go语言中&#xff0c;crypto/cipher包提供了加密和解密消息的功能。这个包实现了各种加密算法&#xff0c;如AES、DES、3DES、RC4等&#xff0c;以及相应的模式&#xff0c;如ECB、CBC、CFB、OFB、CTR等。以下是如何使用crypto/cipher包进行加密和解密操作的基本步骤&#xf…

快速入门Kotlin④集合

集合概述 继承关系(List、Set和Map均继承了Collection) List List 是一个接口,用于表示列表(List)数据结构。它是一个有序的集合,允许重复元素。 listOf 创建的列表是不可变的,而 mutableListOf 创建的列表是可变的,允许对其进行添加、删除和更新操作。 fun main()…

fast_bev 学习笔记

目录 一. 简述二. 输入输出三. github资源四. 复现推理过程4.1 cuda tensorrt 版 训练修改图像数 一. 简述 原文:Fast-BEV: A Fast and Strong Bird’s-Eye View Perception Baseline FAST BEV是一种高性能、快速推理和部署友好的解决方案&#xff0c;专为自动驾驶车载芯片设计…

插入排序解读

在众多的排序算法中&#xff0c;插入排序以其直观易懂和在某些特定场景下的高效性而备受青睐。今天&#xff0c;我们就来深入探索一下插入排序的原理、实现方式以及它的优缺点。 一、算法原理 插入排序相当于打牌中抓牌插入的方式。插入排序的工作方式是通过构建有序序列&…

功能测试_验证qq账号的合法性

案例&#xff1a;验证qq账号的合法性&#xff08;要求&#xff1a;6-10位的自然数&#xff09; 使用等价类设计用例案例&#xff1a; 步骤&#xff1a; 1:明确需求&#xff1a;qq账号的合法性 2:划分等价类&#xff1a;有效等价类、有效取值、无效等价类、无效取值 3&…

三、SpringBoot3 整合 SpringMVC

本章概要 实现过程web 相关配置静态资源处理自定义拦截器(SpringMVC 配置) 3.1 实现过程 创建程序引入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www…

双目运算符和单目运算符的重载

目录 题目 源码 结果示例 题目 建立一个矩阵类&#xff0c;可以完成指定的操作或运算。 说明&#xff1a; 矩阵为2行3列&#xff0c;基类型为整型&#xff1b;操作或运算&#xff1a;初始化&#xff08;>>&#xff09;、输出&#xff08;<<&#xff09;、赋值…

SpringBoot学习笔记(一)

SpringBootSpringBoot学习笔记&#xff08;一&#xff09; 1.SpringBoot配置2.yml3.SpringBoot配置&#xff08;1&#xff09;Value注解获取配置参数&#xff08;2&#xff09;Environment获取配置参数&#xff08;3&#xff09;ConfigurationProperties方式&#xff08;4&…

使用 Meltano 将数据从 Snowflake 导入到 Elasticsearch:开发者之旅

作者&#xff1a;来自 Elastic Dmitrii Burlutskii 在 Elastic 的搜索团队中&#xff0c;我们一直在探索不同的 ETL 工具以及如何利用它们将数据传输到 Elasticsearch&#xff0c;并在传输的数据上实现 AI 助力搜索。今天&#xff0c;我想与大家分享我们与 Meltano 生态系统以及…

WPF Pack

在WPF中&#xff0c;Pack URI&#xff08;Uniform Resource Identifier&#xff09;是一种特殊格式的统一资源标识符&#xff0c;用于定位和访问应用程序内部或外部的各种资源&#xff0c;如XAML文件、图像、样式、字体等。这种机制允许开发者以标准化、平台无关的方式引用和打…