【数据结构】2.顺序表实现通讯录

文章目录

  • 一、通讯录的要求
  • 二、通讯录的具体实现
    • 0、 准备工作
    • 1、通讯录的初始化
    • 2、通讯录的销毁
    • 3、通讯录的展示
    • 4、通讯录添加数据
    • 5、通讯录删除数据
    • 6、通讯录的查找
    • 7、通讯录的修改
    • 8、保存通讯录数据到文件
    • 9、读取文件内容到通讯录
  • 三、 通讯录的完整实现

一、通讯录的要求

通讯录所能实现的功能要求如下:
1)⾄少能够存储100个⼈的通讯信息
2)能够保存⽤⼾信息:名字、性别、年龄、电话、地址等
3)增加联系⼈
4)删除指定联系⼈
5)查找指定联系⼈
6)修改指定联系⼈
7)显⽰联系⼈信息

二、通讯录的具体实现

0、 准备工作

:本文所有的SeqList文件均在上文讲解过,如果有不懂的可以点击蓝色字体查看上文。

通讯录的实现是基于动态顺序表实现的,可以理解为在动态顺序表上面套了一层壳子叫做通讯录,里面的核心还是动态顺序表。

由此图可以理解为原来动态顺序表的一个元素,现在变成了一个结构体(包含了联系人的信息)。

由于是在动态顺序表的基础上实现的,所以还需要包含前文所写的SeqList.h和SeqList.c文件,因此要实现通讯录需要包含5个文件:
SeqList.h
SeqList.c:
Contact.h:通讯录函数的声明,结构体构造,宏定义。
Contact.c:通讯录函数的实现。
test.c:通讯录函数的测试

如果要实现通讯录,那我们首先需要定义一个联系人的结构体,包含联系人的各种信息。

即:

这些信息仅做参考,还可以根据需求自己定义一些相关信息。

结构体在通讯录的头文件Contact.h中定义:

typedef struct PersonInfo
{char name[10];//姓名char sex[10];//性别int age;//年龄char tel[20];//电话char addr[100];//地址
}Peo

但是为了便于维护,我们可以将数组的最大值用宏定义来替代,提高代码的便利性。
即:

#define NAME_MAX 10
#define SEX_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100typedef struct PersonInfo
{char name[NAME_MAX];//姓名char sex[SEX_MAX];//性别int age;///年龄char tel[TEL_MAX];//电话char addr[ADDR_MAX];//地址
}PeoInfo;

之前在顺序表中,一个元素的类型一般是int类型,现在我们用结构体替代原来的元素,元素类型应该变成结构体类型PeoInfo。
因此需要将SeqList.h文件中的:

typedef int SLDataType;

改为:

typedef PeoInfo SLDataType;

而在SeqList.h文件中引用Contact.h文件中的内容,需要在SeqList.h中添加#include"Contact.h"

由于我们实质上是对顺序表进行操作,所以需要对在Contact.h中为顺序表重新起个名字叫做通讯录:

typedef struct SeqList Contact;

接下来就进入正式部分,首先对需要实现的通讯录相关的方法在Conatct.h中进行声明:

//通讯录的初始化
void ContactInit(Contact* con);//通讯录的销毁
void ContactDestroy(Contact* con);//通讯录的展示
void ContactShow(Contact* con);//通讯录添加数据
void ContactAdd(Contact* con);//通讯录删除数据
void ContactDel(Contact* con);//通讯录的查找
void ContactFind(Contact* con);//通讯录的修改
void ContactModify(Contact* con);//保存通讯录数据到文件
void SaveContact(Contact* con);//读取文件内容到通讯录
void LoadContact(Contact* con);

接下来再在Contact.c文件中来实现方法,首要需要引用头文件:#include"Contact.h",同时实现的部分方法是直接使用的顺序表的方法,因此还需要引用顺序表:#include"SeqList.h"
现在完事具备,可以来实现方法了。

1、通讯录的初始化

通讯录的初始化:直接调用顺序表的初始化。

void ContactInit(Contact* con)
{//调用顺序表的初始化SLInit(con);
}

在test.c中进行测试:

int main()
{Contact con;ContactInit(&con);return 0;
}

通过测试发现通讯录初始化成功!

2、通讯录的销毁

通讯录的销毁:同样直接调用顺序表的销毁即可。

void ContactDestroy(Contact* con)
{//调用顺序表的销毁SLDestroy(con);
}

再进行测试:

int main()
{Contact con;ContactInit(&con);ContactDestroy(&con);return 0;
}

3、通讯录的展示

通讯录的展示:先打印表头,再依次打印通讯录中每一个结构体里的五个通讯录信息。

void ContactShow(Contact* con)
{//打印表头printf("%-10s %-4s %-4s %-11s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");//for循环依次打印通讯录中每一个(元素)结构体里的5个通讯录信息for (int i = 0; i < con->size; i++){printf("%-10s %-4s %-4d %-11s %-20s\n",con->arr[i].name,con->arr[i].sex,con->arr[i].age,con->arr[i].tel,con->arr[i].addr);}
}

:-号表示左对齐,10表示输出的数据占10个字符。

再进行测试:

int main()
{Contact con;ContactInit(&con);ContactShow(&con);return 0;
}

通过测试发现通讯录展示成功!

4、通讯录添加数据

通讯录添加数据:输入一个元素的通讯录信息,再尾插到通讯录(顺序表)中。

void ContactAdd(Contact* con)
{//输入一个元素(结构体)的通讯录信息PeoInfo info;printf("请输入要添加的联系人姓名:");scanf("%s", info.name);//数组不用取地址&printf("请输入要添加的联系人性别:");scanf("%s",info.sex);printf("请输入要添加的联系人年龄:");scanf("%d", &info.age);printf("请输入要添加的联系人电话:");scanf("%s", info.tel);printf("请输入要添加的联系人地址:");scanf("%s", info.addr);//将其尾插到通讯录(顺序表)中SLPushBack(con, info);printf("联系人数据添加成功!\n");
}

再进行测试:

int main()
{Contact con;ContactInit(&con);ContactAdd(&con);ContactShow(&con);return 0;
}

通过测试发现通讯录添加数据成功!

5、通讯录删除数据

在进行删除、查找等操作的时候,我们需要通过姓名这个唯一性元素来得到其整个信息,然后再进行操作。
根据姓名查找:遍历通讯录,找到返回下标,否则返回-1

int 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 ContactDel(Contact* con)
{//输入要删除的姓名char Name[NAME_MAX];printf("请输入你要删除的联系人姓名:");scanf("%s", Name);//找到下标int find = FindByName(con, Name);if (find < 0){printf("你要删除的联系人数据不存在!\n");}//调用顺序表指定位置的删除  删除下标对应的数据SLErase(con, find);printf("联系人数据删除成功!\n");
}

再进行测试:

int main()
{Contact con;ContactInit(&con);ContactAdd(&con);ContactShow(&con);ContactDel(&con);ContactShow(&con);return 0;
}

通过测试发现通讯录数据删除成功!

6、通讯录的查找

通讯录的查找:输入姓名,找到下标,打印下标对应的数据。

void ContactFind(Contact* con)
{//输入要查找的姓名char Name[NAME_MAX];printf("请输入你要查找的联系人姓名:");scanf("%s", Name);//找到下标int find = FindByName(con, Name);if (find < 0){printf("你要查找的联系人数据不存在!\n");}//打印下标对应的数据printf("%-10s %-4s %-4s %-11s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");printf("%-10s %-4s %-4d %-11s %-20s\n",con->arr[find].name,con->arr[find].sex,con->arr[find].age,con->arr[find].tel,con->arr[find].addr );
}

再进行测试:

int main()
{Contact con;ContactInit(&con);ContactAdd(&con);ContactShow(&con);ContactFind(&con);return 0;
}

通过测试发现通讯录查找成功!

7、通讯录的修改

通讯录的修改:输入姓名,找到下标,修改下标对应的数据。

void ContactModify(Contact* con)
{//输入姓名char Name[NAME_MAX];printf("请输入你要修改的联系人姓名:");scanf("%s", Name);//找到下标int find = FindByName(con, Name);if (find < 0){printf("你要修改的联系人数据不存在!\n");}//修改下标对应的数据printf("请输入新的联系人姓名:");scanf("%s", con->arr[find].name);printf("请输入新的联系人性别:");scanf("%s", con->arr[find].sex);printf("请输入新的联系人年龄:");scanf("%d", &con->arr[find].age);printf("请输入新的联系人电话:");scanf("%s", con->arr[find].tel);printf("请输入新的联系人地址:");scanf("%s", con->arr[find].addr);printf("联系人数据修改成功!\n");
}

再进行测试:

int main()
{Contact con;ContactInit(&con);ContactAdd(&con);ContactShow(&con);ContactModify(&con);ContactShow(&con);return 0;
}

经过测试通讯录的修改成功!

8、保存通讯录数据到文件

保存数据到文件:打开文件,联系人数据写入文件,关闭文件。

void SaveContact(Contact* con)
{//打开文件FILE* pf = fopen("Contact.txt", "ab");//如果打开失败{if (pf == NULL){perror("fopen fail");}}//将联系人数据写入文件for (int i = 0; i < con->size; i++){fwrite(con->arr + i, sizeof(PeoInfo), 1, pf);}printf("通讯录数据保存成功!\n");//关闭文件fclose(pf);
}

再进行测试:

int main()
{Contact con;ContactInit(&con);ContactAdd(&con);ContactShow(&con);SaveContact(&con);return 0;
}

同时我们可以点击添加源文件,添加现有项,将Contact.txt文件添加进来,再将txt文件的打开方式设置为二进制编辑器。‘’
就可以在Contact.txt文件中看到;

说明数据已经以二进制的形式保存在文件中了。

9、读取文件内容到通讯录

读取文件内容到通讯录:打开文件,读取文件,尾插到通讯录中,关闭文件。

void LoadContact(Contact* con)
{//打开文件FILE* pf=fopen("Contact.txt","rb");//如果打开失败if (pf == NULL){perror("fopen fail");}//读取文件数据PeoInfo info;while (fread(&info, sizeof(PeoInfo), 1, pf)){//文件数据尾插到通讯录中SLPushBack(con, info);}//关闭文件fclose(pf);
}

再进行测试:

int main()
{Contact con;ContactInit(&con);ContactShow(&con);LoadContact(&con);ContactShow(&con);return 0;
}

可以观察到,一开始原本没有数据,但是在我们读取文件到通讯录之后,就有了数据,说明读取文件内容到通讯录成功了!

三、 通讯录的完整实现

在我们实现了通讯录的所有方法之后,我们可以将其集合起来做成完整的通讯录。
再在test.c中来实现这个完整的程序:

#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h"//打印通讯录界面
void menu()
{printf("**************      通讯录    **************\n");printf("*******  1.增加联系人   2.删除联系人  ******\n");printf("*******  3.修改联系人   4.查找联系人  ******\n");printf("*******  5.展示联系人   6.保存联系人  ******\n");printf("*******  7.导入联系人   0.退出        ******\n");printf("********************************************\n");
}int main()
{//通讯录初始化int input = -1;Contact con;ContactInit(&con);//用do while先执行一次循环,输入0循环结束do{menu();//输入序号printf("请选择你要执行的操作:");scanf("%d", &input);//根据输入的序号执行对应的操作 switch (input){case 1:ContactAdd(&con);break;case 2:ContactDel(&con);break;case 3:ContactModify(&con);break;case 4:ContactFind(&con);break;case 5:ContactShow(&con);break;case 6:SaveContact(&con);break;case 7:LoadContact(&con);break;case 0:printf("退出通讯录...\n");break;default:printf("输入错误,请重新选择你的操作:\n");break;}	} while (input != 0);//通讯录销毁ContactDestroy(&con);return 0;
}

效果如下:

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

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

相关文章

程序化广告行业(79/89):技术革新与行业发展脉络梳理

程序化广告行业&#xff08;79/89&#xff09;&#xff1a;技术革新与行业发展脉络梳理 大家好&#xff01;一直以来&#xff0c;我都热衷于在技术领域不断探索&#xff0c;也深知知识共享对于进步的重要性。写这篇博客&#xff0c;就是希望能和大家一起深入研究程序化广告行业…

【C++游戏引擎开发】第9篇:数学计算库GLM(线性代数)、CGAL(几何计算)的安装与使用指南

写在前面 两天都没手搓实现可用的凸包生成算法相关的代码&#xff0c;自觉无法手搓相关数学库&#xff0c;遂改为使用成熟数学库。 一、GLM库安装与介绍 1.1 vcpkg安装GLM 跨平台C包管理利器vcpkg完全指南 在PowerShell中执行命令&#xff1a; vcpkg install glm# 集成到系…

python文件打包无法导入ultralytics模块

&#x1f4a5;打包的 .exe 闪退了&#xff1f;别慌&#xff01;教你逐步排查 PyInstaller 打包的所有错误&#xff01; &#x1f6e0; 运行 .exe 查看报错信息✅ 正确姿势&#xff1a; ⚠ importlib 动态导入导致打包失败❓什么是动态导入&#xff1f;✅ 解决方式&#xff1a; …

【React框架】什么是 Vite?如何使用vite自动生成react的目录?

什么是 Vite&#xff1f; Vite 是一个基于原生 ES Modules 开发的前端构建工具&#xff0c;由 Evan You&#xff08;Vue 的作者&#xff09;开发。它最大的特点包括&#xff1a; 极速冷启动&#xff1a;因为利用了浏览器原生的 ES Modules&#xff0c;所以在开发时无需等待整…

深入解读 React 纯组件(PureComponent)

什么是纯组件&#xff1f; React 的纯组件(PureComponent)是 React.Component 的一个变体&#xff0c;它通过浅比较(shallow comparison)props 和 state 来自动实现 shouldComponentUpdate() 方法&#xff0c;从而优化性能。 核心特点 1. 自动浅比较&#xff1a; PureCompon…

JavaScript数组方法:`some()`的全面解析与应用

文章目录 JavaScript数组方法&#xff1a;some()的全面解析与应用一、some()方法的基本概念语法参数说明返回值 二、some()方法的核心特点三、基础用法示例示例1&#xff1a;检查数组中是否有大于10的元素示例2&#xff1a;检查字符串数组中是否包含特定子串 四、实际应用场景1…

判断两个 IP 地址是否在同一子网 C

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> // 将点分十进制的 IP 地址转换为 32 位无符号整数 unsigned int ip_to_uint(const char *ip) { struct in_addr addr; if (inet_pton(AF_INET, ip, &am…

React 组件样式

在这里插入图片描述 分为行内和css文件控制 行内 通过CSS中类名文件控制

尚硅谷Java第 4、5 章IDEA,数组

第 4 章&#xff1a;IDEA的使用 第 5 章&#xff1a;数组 5.1 数组的概述 数组(Array)&#xff1a;就可以理解为多个数据的组合。 程序中的容器&#xff1a;数组、集合框架&#xff08;List、Set、Map&#xff09;。 数组中的概念&#xff1a; 数组名 下标&#xff08;或索…

SQL注入基本原理靶场实现

↵ 一、前言 SQL注入漏洞(SQL injection)是WEB层面高危的漏洞之一&#xff0c;也是常见的攻击方式。 二、本质 1、什么是SQL注入 SQL 注入是一种利用应用程序对用户输入数据过滤不严格&#xff0c;将恶意 SQL 代码插入到正常 SQL 语句中&#xff0c;从而操控数据库查询逻辑的…

图像预处理(OpenCV)

1 图像翻转(图像镜像旋转) 在OpenCV中&#xff0c;图片的镜像旋转是以图像的中心为原点进行镜像翻转的。 cv2.flip(img,flipcode) 参数 img: 要翻转的图像 flipcode: 指定翻转类型的标志 flipcode0: 垂直翻转&#xff0c;图片像素点沿x轴翻转 flipcode>0: 水平翻转&…

PCDN收益高低的关键因素

PCDN&#xff08;P2P内容分发网络&#xff09;收益好的三个主要关键因素是&#xff1a;硬件配置与性能、网络环境与质量、业务调度与策略。 1. 硬件配置与性能 设备稳定性与兼容性 PCDN节点需长时间稳定运行&#xff0c;硬件性能直接影响收益。例如&#xff0c;使用高性能CPU、…

『生成内容溯源系统』详解

生成内容溯源系统详解 1. 定义与核心目标 生成内容溯源系统&#xff08;Generative Content Provenance System&#xff09;是指能够追踪AI生成内容的来源、生成过程、版权归属及修改历史的技术体系。其核心目标是&#xff1a; 验证真实性&#xff1a;证明内容由特定AI模型生…

conda如何安装和运行jupyter

在Conda环境中安装和运行Jupyter Notebook是一项常见且实用的任务&#xff0c;特别是在数据科学和机器学习项目中。以下是使用Conda安装和运行Jupyter Notebook的步骤&#xff1a; 安装Jupyter Notebook 首先&#xff0c;确保你的Conda是最新的。打开终端或Anaconda Prompt&a…

QML之Flickable(滚动区域)

Flickable 是 QML 中用于创建可滚动区域的基础组件&#xff0c;它比 ScrollView 提供更底层的控制&#xff0c;适合需要自定义滚动行为的场景。 基本用法 qml import QtQuick 2.15Flickable {width: 200height: 200contentWidth: 400 // 内容总宽度contentHeight: 800 // 内…

【NumPy科学计算引擎:从基础操作到高性能实践】

目录 前言&#xff1a;技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析关键技术模块说明技术选型对比 二、实战演示环境配置核心代码实现运行结果验证 三、性能对比测试方法论量化数据对比结果分析 四、最佳实践推荐方案 ✅常见错误 ❌调试技巧 五、应用…

PandaGPT实战(1): 环境配置及效果演示

文章目录 1. 环境安装2. 数据准备2.1 模型权重获取2.2 训练数据准备3. 效果演示3.1 训练3.2 部署效果PandaGPT是首个无需显式监督即能跨六种模态执行指令微调任务的基础模型。它展现出多样化的多模态能力,包括复杂理解/推理、基于知识的描述以及多轮对话交互。 作为通用型指令…

spring security oauth2.0 使用GitHub

在 Spring Security 中集成 GitHub 的 OAuth 2.0 登录&#xff0c;可以实现用户通过 GitHub 账号快速认证。以下是完整的分步实现指南和代码示例&#xff1a; 一、前置准备 1. 在 GitHub 注册 OAuth 应用 访问 GitHub Settings → Developer settings → OAuth Apps点击 New …

QT聊天项目DAY01

1.新建初始项目 2.修改UI格式 运行效果 3.创建登录界面 设计登录界面UI 设计布局 调整布局间距 往水平布局中拖入标签和文本输入框 更换控件名称并固定高度 添加窗口部件 往现有的资源文件中导入图片 添加水平布局 4.设置登陆界面为主窗口的核心组件 #pragma once#include &l…

检测到目标URL存在http host头攻击漏洞

漏洞描述 修复措施 方法一&#xff1a; nginx 的 default_server 指令可以定义默认的 server 去处理一些没有匹配到 server_name 的请求&#xff0c;如果没有显式定义&#xff0c;则会选取第一个定义的 server 作为 default_server。 server { …