数据结构(初阶):顺序表实战通讯录
前言
数据结构(初阶)第一节:数据结构概论-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 20typedef 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 20typedef 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;
}
相关文章:
数据结构(初阶):顺序表实战通讯录
前言 数据结构(初阶)第一节:数据结构概论-CSDN博客 数据结构(初阶)第二节:顺序表-CSDN博客 本文将以C语言和顺序表实现通讯录基础管理,实现功能包括增、删、改、查等,在实现相关功能…...

Outlook会议邀请邮件在答复后就不见了
时常会有同事找到我说,Outlook答复会议邀请邮件后收件箱就找不到会议邀请的邮件了。 这其实是Outlook的的一个机制,会把应答后的会议邀请邮件从收件箱自动删除,到已删除的邮件那里就能找到。如果不想要自动删除,改一个设置即可。…...

【C++】list模拟实现
个人主页 : zxctscl 如有转载请先通知 文章目录 1. 前言2. list源码3. 初始化3.1 构造3.2 拷贝构造3.3 赋值3.4 析构 4. 迭代器4.1 后置加加和前置加加4.2 后置减减和前置减减4.3 解引用4.4 !和4.5 begin 和 end4.6 const迭代器4.7 迭代器优化 5. Modifi…...

ETL工具-nifi干货系列 第八讲 处理器PutDatabaseRecord 写数据库(详细)
1、本节通过一个小例子来讲解下处理器PutDatabaseRecord,该处理器的作用是将数据写入数据库。 如下流程通过处理器GenerateFlowFile 生成数据,然后通过处理器JoltTransformJSON转换结构,最后通过处理器PutDatabaseRecord将数据写入数据库。如…...

【MySQL】如何判断一个数据库是否出问题
在实际的应用中,其实大多数是主从结构。而采用主备,一般都需要一定的费用。 对于主备,如果主机故障,那么只需要直接将流量打到备机就可以,但是对于一主多从,还需要将从库连接到主库上。 对于切换的操作&a…...
SQLite数据库的性能问题并不是单纯地由数据量的大小决定的,而是受到多种因素的综合影响。以下是一些可能导致SQLite性能问题的因素
SQLite数据库的性能问题并不是单纯地由数据量的大小决定的,而是受到多种因素的综合影响。以下是一些可能导致SQLite性能问题的因素: 数据量:当SQLite数据库中的数据量增长到一定程度时,查询、插入和更新等操作可能会变得缓慢。这…...

Blender怎么样启动默认移动和Cavity效果
在使用Blender的过程中,有一些特殊的技巧很重要。 比如默认地设置blender打开时,就是移动物体,这样怎么样设置的呢? 需要在界面里打开下面的菜单: 这样就找到默认设置的地方,把下面的移动勾选起来,这样点…...
Android 解决TextView多行滑动与NestedScrollView嵌套滑动冲突的问题
关键计算地方: 1.当前是上滑动还是下滑动(相对于屏幕) ,使用ev.getRawY()获得当前滑动位置在屏幕哪个地方 2. 计算文本客滑动到哪里即可停止, (行高*总文本行数)- (行高 * 最多显示行数) int sum getLineHeight() * getLineCount() - getLineHeight() * getMaxLines(); …...
Laravel 开发Api规范
一,修改时区 配置 config/app.php 文件 // 时区修改,感觉两者皆可,自己根据实际情况定义 timezone > PRC, // 大陆时间二,设置 Accept 头中间件 accept头即为客户端请求头,做成中间件来使用。Accept 决定了响应返…...

蓝色wordpress外贸建站模板
蓝色wordpress外贸建站模板 https://www.mymoban.com/wordpress/7.html...

windos环境,使用docker容器运行项目的,新增外部访问地址配置
对于运行在 Docker 容器中的项目,你需要在容器内部编辑 resolv.conf 文件。以下是一种常见的方法: 进入正在运行的 Docker 容器:docker exec -it [container_id] bash其中 [container_id] 是你正在运行的 Docker 容器的 ID。 在容器内部使…...
设计模式:生活中的组合模式
想象一下,你正在组织一个大型的家庭聚会。在这个聚会中,你需要准备各种菜肴,每个菜肴又包含不同的食材。你的目标是能够以统一的方式处理整个聚会的准备工作,不论是处理单个食材还是一整道菜肴。 在这个场景中,我们可…...
WPF OnStartup
在Windows Presentation Foundation (WPF)框架中,OnStartup 是 System.Windows.Application 类的一个受保护的虚方法,它是应用程序启动过程中的一个重要环节。当一个 WPF 应用程序启动时,其入口点通常是 App.xaml 文件和对应的后台代码文件 A…...
docker-相关
打镜像 1、编写dockfile文件,请自行百度 2、docker build -t 镜像名称:版本号 dockerFile路径 3、docker save -o 镜像压缩包名称.tar 镜像名称:镜像版本号 部署镜像 1、将镜像tar包放到部署机器上 2、加载镜像:docker load -i 镜像tar包路径 3、dock…...
二十、Rust AOP 切面增强
用过 java spring 的同学,应该会对 AspectJ 的 前置、后置、环绕 增强 念念不忘,巧了 rust 也有类似能力,稍显不同的是,为了向 “零成本抽象” 靠齐,Rust 的 “增强” 是在编译期 完成的。 编译期生成,则离…...
掌握Go语言:Go语言精细错误,清晰、高效的错误处理实践(32)
错误处理是任何编程语言中都至关重要的一部分,Go 语言提供了一套简单而强大的错误处理机制,使得处理错误变得高效而清晰。 Go 错误类型 在 Go 中,错误是一个普通的接口类型,即 error 接口,其定义如下: t…...
Spring与Web环境的集成
1. ApplicationContext应用上下文获取方式 应用上下文对象是通过new ClasspathXmlApplicationContext(spring配置文件) 方式获取的,但是每次从容器中获得Bean时都要编写new ClasspathXmlApplicationContext(spring配置文件) ,这样的弊端是配置文件加载多…...

二叉树的遍历——bfs广度优先搜索
1、BinNode类的创建 (1)代码总览 ##(2)测试示例 2、二叉树的遍历 (1)图示 (2)代码总览 (3)测试示例...

飞鸟写作可靠吗 #职场发展#经验分享#经验分享
飞鸟写作是一个非常便捷的论文写作工具,不仅可以帮助用户高效地完成论文写作,还可以提供查重降重的功能,帮助用户确保论文的原创性。那么,飞鸟写作到底可靠吗?答案是肯定的。 首先,飞鸟写作提供的查重降重功…...

Java 实现自定义注解
一、interface 关键字 我们想定义一个自己的注解 需要使用 interface 关键字来定义。 如定义一个叫 MyAnnotation 的注解: public interface MyAnnotation { } 二、元注解 光加上 interface 关键字 还不够,我们还需要了解5大元注解 RetentionTargetDo…...

【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...