数据结构——基于顺序表实现通讯录
一、. 基于动态顺序表实现通讯录
1.1 功能要求
1)⾄少能够存储100个⼈的通讯信息
2)能够保存⽤⼾信息:名字、性别、年龄、电话、地址等3)增加联系⼈信息4)删除指定联系⼈5)查找制定联系⼈6)修改指定联系⼈7)显⽰联系⼈信息
1.2 思路分析
我们之前创建的顺序表可以实现连续存储数据(类型可以为整型、字符等),但无论是哪种类型,存储信息都比较单一,但是通讯录存储信息比较多,有联系人姓名、性别、年龄等,所以我们把一个联系人的所有信息作为一个整体存储到顺序表,原来我们写的是整型作为数据存储每个数组元素空间,现在转化通讯录,把一个人的所有信息打包变为结构体然后存储到数组元素元素的空间,然后基于顺序表实现通讯录功能。
1.3 通讯录的实现
因为我们是基于顺序表实现通讯录,先将顺序表写好
1.3.1 顺序表
1.3.1.1 SeqList.h
#define _CRT_SECURE_NO_WARNINGS
#include<stdlib.h>
//#include"Contact.h"
#define NAME_MAX 100
#define SEX_MAX 10
#define TEL_MAX 15
#define ADDR_AMX 20
struct ContactInfo
{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_AMX];
};
typedef struct ContactInfo SLDateType;
typedef struct SeqList
{SLDateType* a;int size;//空间有效数据int capacity;//空间大小
}SL;//初始化和销毁
void SLInit(SL* ps);
void SLDestory(SL* ps);//尾插和头插
void SLPushBack(SL* ps, SLDateType x);
void SLPushFront(SL* ps, SLDateType x);
//void SLPrint(SL* ps);//头删和尾删
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);//在指定位置之前插入
void SLInsert(SL* ps, int pos, SLDateType x);
//删除指定位置
void SLDel(SL* ps, int pos);
注:这里值得注意的是我们将通讯信息结构体定义在SeqList.h中,然后重命名,后面的顺序表结构也是这样,那为什么不把通讯信息结构体定义在Contact.h,然后再SeqList.h中包含Contact.h,对typedef struct ContactInfo SLDateType
这样看似没问题,实际会造成重命名的问题,所以我们字书时要规范。
输出结果:
1.3.1.2 SeqList.c
#define _CRT_SECURE_NO_WARNINGS
#include "SeqList.h"
#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
void SLInit(SL* ps)
{ps->a = NULL;ps->size = ps->capacity = 0;
}
void SLDestory(SL* ps)
{if (ps->a)free(ps->a);ps->a = NULL;ps->size = ps->capacity = 0;
}
int SLCheckCapacity(SL* ps)
{assert(ps);int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;if (ps->size == ps->capacity)//进行扩容{SLDateType* ret = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));if (ret == NULL){perror("realloc fail:");return 1;}ps->a = ret;ps->capacity = newcapacity;}
}void SLPushBack(SL* ps, SLDateType x)//1.若空间足够,进行插入 2.若空间不够,进行扩容(以1.5或2倍原来大小进行扩容)
{assert(ps);SLCheckCapacity(ps);ps->a[ps->size] = x;ps->size++;
}
//void SLPrint(SL* ps)
//{
// assert(ps);
// for (size_t i = 0; i < ps->size; i++)
// {
// printf("%d ", ps->a[i]);
// }
// printf("\n");
//}
void SLPushFront(SL* ps, SLDateType x)
{assert(ps);SLCheckCapacity(ps);for (size_t i = ps->size; i > 0; i--){ps->a[i] = ps->a[i-1];}ps->a[0] = x;ps->size++;
}bool SLIsEmpty(SL * ps)//若返回值为假,则有数据,反之,则无
{assert(ps);return ps->size == 0;
}
void SLPopBack(SL* ps)
{assert(ps);//还需要判断是否有数据assert(!SLIsEmpty(ps));ps->size--;
}
void SLPopFront(SL* ps)
{assert(ps);//还需要判断是否有数据assert(!SLIsEmpty(ps));for (size_t i = 0; i < ps->size-1; i++){ps->a[i] = ps->a[i + 1];}ps->size--;
}// 在指定位置之前插入
void SLInsert(SL* ps, int pos, SLDateType x)
{assert(ps);SLCheckCapacity(ps);//防止越界访问assert(pos>= 0 && pos<= ps->size);//端点位置为头插和尾插for (size_t i = ps->size; i >pos; i--){ps->a[i] = ps->a[i - 1];}ps->a[pos] = x;ps->size++;
}
//删除指定位置
void SLDel(SL* ps, int pos)
{assert(ps);assert(!SLIsEmpty(ps));assert(pos>= 0 && pos< ps->size);//端点位置为头删和尾删for (size_t i = pos; i < ps->size-1; i++){ps->a[i] = ps->a[i + 1];}ps->size--;
}
1.3.2 通讯录的初始化+销毁
1.3.2.1 Contact.h
#define _CRT_SECURE_NO_WARNINGStypedef struct ContactInfo CInfo;
typedef struct SeqList Contact;//将顺序表重命名为通讯录(这里只是声明,无需包含Seqlist.h)//通讯录的初始化和销毁
void ContactInit(Contact* con);
void ContactDestroy(Contact* con);
注:这里没有包含SeqList.h,为什么可以重定义结构体和顺序表呢?
因为这里我们只是声明,没有使用,当在text.c使用时,它就会将Contact.h的CInfo和Contact
展开。
1.3.2.2 Contact.c
#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
#include"SeqList.h"
#include <stdlib.h>
#include<stdio.h>
#include<assert.h>
void ContactInit(Contact* con)
{SLInit(con);
}
void ContactDestroy(Contact* con)
{SLDestory(con);
}
这里直接借用顺序表实现
1.3.3 通讯录的添加+删除
1.3.3.1 Contact.h
//通讯录的初始化和销毁
void ContactInit(Contact* con);
void ContactDestroy(Contact* con);
1.3.3.2 Contact.c
void ContactAdd(Contact* con)
{assert(con);CInfo info;printf("请输入姓名:\n");scanf("%s", info.name);printf("请输入性别:\n");scanf("%s", info.sex);printf("请输入年龄:\n");scanf("%d", &info.age);printf("请输入电话号码:\n");scanf("%s", info.tel);printf("请输入地址:\n");scanf("%s", info.addr);//将数据进行尾插SLPushBack(con,info);}
int FindByName(Contact* con,char name[])
{for (int i = 0; i < con->size; i++){if (strcmp(con->a[i].name, name)==0){return i;}}return -1;
}void ContactDel(Contact* con)
{assert(con);char name[NAME_MAX];printf("需要删除的姓名:\n");scanf("%s", name);//先查找该信息位置int ret=FindByName(con,name);if (ret < 0){printf("没找到该联系人\n");return 1;}SLDel(con, ret);//删除指定位置
}
注: info.name这个是数组名,所以不用取地址
1.3.4 查看通讯录
1.3.4.1 Contact.h
//查看通讯录
void ContactShow(Contact* con);
1.3.4.2 Contact.c
void ContactShow(Contact* con)
{assert(con);assert(con->a);printf("%-4s%-4s%-4s%-4s%-4s\n", "姓名", "性别", "年龄", "电话", "住址");for (int i = 0; i < con->size;i++){printf("%-4s %-4s %-4d%-4s%-4s\n",con->a[i].name, con->a[i].sex, con->a[i].age, con->a[i].tel, con->a[i].addr);}
}
1.3.5 修改通讯录
1.3.5.1 Contact.h
//修改通讯录
void ContactChange(Contact* con);
1.3.5.2 Contact.c
void ContactChange(Contact* con)
{assert(con);char name[NAME_MAX];printf("需要修改的姓名:\n");scanf("%s",name);//先查找该信息位置int ret = FindByName(con, name);if (ret < 0){printf("没找到该联系人\n");return 1;}printf("请输入修改的姓名:\n");scanf("%s",con->a[ret].name);printf("请输入修改的性别:\n");scanf("%s", con->a[ret].sex);printf("请输入修改的年龄:\n");scanf("%d", &con->a[ret].age);printf("请输入修改的电话号码:\n");scanf("%s", con->a[ret].tel);printf("请输入修改的地址:\n");scanf("%s", con->a[ret].addr);printf("修改成功!\n");}
1.3.6 查找指定联系人
1.3.6.1 Contact.h
//查找指定联系人
void ContactFind(Contact* con);
1.3.6.2 Contact.c
void ContactFind(Contact* con)
{assert(con);char name[NAME_MAX];printf("需要查找的姓名:\n");scanf("%s", name);//先查找该信息位置int ret = FindByName(con, name);if (ret < 0){printf("没找到该联系人\n");return 1;}printf("%-4s%-4s%-4d%-4s%-4s\n",con->a[ret].name, con->a[ret].sex, con->a[ret].age, con->a[ret].tel, con->a[ret].addr);
}
1.3.7 菜单界面
为方便调用通讯录的各种功能,我们做一个菜单界面
1.3.7 .1 text.c
void menu()
{ printf("****************** 通讯录 **********************\n");printf("*** 1.添加联系人 2.删除联系人 ******\n");printf("*** 3.修改通讯录 4.查看指定联系人 ******\n");printf("*** 5.查看通讯录 0.退出通讯录 ******\n");printf("*****************************************************\n");}
int main()
{int n = -1;Contact con;ContactInit(&con);do{menu();printf("请输入你的选择;\n");scanf("%d", &n);switch (n){case 1:ContactAdd(&con);break;case 2:ContactDel(&con);break;case 3:ContactChange(&con);break;case 4:ContactFind(&con);break;case 5:ContactShow(&con);break;case 0:break;default:printf("输入错误,请从新输入!\n");break;}}while (n);ContactDestroy(&con);return 0;
}
1.3.8 测试界面
相关文章:

数据结构——基于顺序表实现通讯录
一、. 基于动态顺序表实现通讯录 1.1 功能要求 1)⾄少能够存储100个⼈的通讯信息 2)能够保存⽤⼾信息:名字、性别、年龄、电话、地址等 3)增加联系⼈信息 4)删除指定联系⼈ 5)查找制定联系⼈ 6&…...

行业追踪,2023-11-03
自动复盘 2023-11-03 凡所有相,皆是虚妄。若见诸相非相,即见如来。 k 线图是最好的老师,每天持续发布板块的rps排名,追踪板块,板块来开仓,板块去清仓,丢弃自以为是的想法,板块去留让…...

JSPv2之El
(一)EL的基本语法 1优点 1 jsp的java太长了,el自己的语言${ 开始 }结束 2el直接返回空字符转,而java直接报错 3使用“lt”代替“<”运算符,如果运算符后面是数字,在运算符 *EL取值时,没有数组的下标越界,没有…...
出现 gpg: cancelled by user时的处理方法
今天在使用git commit -S -m "comment" check in 代码的时候, 莫名其妙出现了以下错误: gpg: cancelled by user经过在网上查询资料, 本质原因是GnuPG没有$(tty)的读写权限,有以下两种解决方法是靠谱的: c…...

MySQL中表的增删改查
目录 一、CRUD 二、新增(Create) (1)语法 (2)单行数据全列插入 (3)多行数据指定列插入 三、查询(Retrieve) (1)语法 …...
web.py python服务器两种模板template使用方法
【版权声明】 本文为博主原创文章,未经博主允许严禁转载,我们会定期进行侵权检索。 更多python应用或算法总结请关注我的博客:https://blog.csdn.net/suiyingy,或”乐乐感知学堂“公众号。 web.py是Python Web框架之一,…...

Flutter 01 目录结构入门
一、Flutter目录结构: 二、Flutter入口文件、入口方法: 三、Flutter Demo: demo1: import package:flutter/material.dart;//MaterialApp 和 Scaffold两个组件装饰App void main() {runApp(MaterialApp(home: Scaffold(appBar: A…...

Esxi安装OpenWrt
最近折腾下软路由主要就是实现局域网内的上网。 1.StarWind V2V Converter下载 先去下载个StarWind V2V Converter,觉得麻烦我在网上有找到一个博主的地址点击这里。 这是官网地址传送门,然后一阵乱输入点击下载 然后 双击之后无脑下一步即可。 2.Op…...
tuple 简易实现(C++ 模板元编程)
std::tuple 在标准库里面,tuple主要有下面四个类模板 or 函数模板 tupletuple_sizetuple_elementget 在后续有实现:tuple_size_v tuple_size::value和tuple_element_t tuple_element::type。 事例Example: auto tup std::tuple<in…...

Http代理与socks5代理有何区别?如何选择?(二)
上篇文章我们基本分别了解了http代理与socks5代理的定义与优缺点,接下来我们继续来了解http代理与socks5代理之间的比较与区别。 一、两者的比较 1、功能比较 HTTP代理专门用于Web流量,并在处理HTTP和HTTPS协议方面非常高效。它们可以修改正在传输的数…...
java中main方法和@Test注解的区别
Java的main方法和Test注解在用途和功能上有很大的区别。 main方法是Java应用程序的入口点。当你运行一个Java程序时,JVM会首先查找具有public static void main(String[] args)签名的类,并从这个方法开始执行程序。main方法通常用于控制程序的启动、执行…...
C++进阶语法——STL 标准模板库(下)(Standard Template Library)【学习笔记(七)】
文章目录 STL 代码示例1、迭代器2、算法3、array容器示例4、vector示例5、deque(double ended queue,双端数组)示例6、list(链表)容器7、set示例8、map示例9、stack 示例10、queue示例11、priority_queue (…...
力扣:求最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 示例1: 输入: strs ["flower", "flow" , "flight"] 输出: "fl" 示例2: 输入: strs ["dog","racecar","car&…...

Redis入门04-消息通知
目录 Redis中的消息通知 命令行操作 Redis中的管道 Redis中的消息通知 Redis可以用作消息队列的中间件,它提供了一种轻量级、高性能的消息传递机制,适用于实时通信、任务队列、事件处理等各种应用。以下是有关如何使用Redis作为消息队列的一些重要信…...

关于idea使用的一些操作设置
关于idea使用的一些操作设置 1. 常用的一下设置1.1 快捷键相关1.2 配置自动生成注释(类、方法等)1.3 maven项目相关1.4 常见其他的一些操作设置 2. IntelliJ IDEA 取消param注释中参数报错提示3. idea同时打开多个文件,导航栏不隐藏、自动换行…...

CLion 2023.2.2(C ++ IDE智能代码编辑器)
CLion 2023是一款跨平台C/C集成开发环境(IDE)。它为Mac用户提供了高效的编程体验,帮助程序员们在Mac平台上进行C/C开发。 CLion 2023支持多种编译器和调试器,并具有强大的代码分析和导航功能。它还为用户提供了许多便捷的工具和插…...

企业级API资产如何管理
在当今数字化时代,API已成为企业开发和创新的重要工具,如何高效地管理和调度这些资产成为了企业发展的重要课题。API资产管理的出现,为企业解决了这一难题,通过合理管理和利用API资产,企业可以更好地推动业务发展&…...

Git https方式拉的代码IDEA推送代码报错
报错信息 fatal: could not read Username for ‘https://codehub-cn-south-1.devcloud.huaweicloud.com’: No such file or directory 18:18:39.885: [recovery_pattern] git -c credential.helper -c core.quotepathfalse -c log.showSignaturefalse push --progress --porc…...
C++ capacity()用法总结
1. 容器的容量 容器的size是指它已经保存的元素的数目;而capacity则是在不分配新的内存空间的前提下它最多可以保存多少元素。capacity(),size(),reserve(),resize()这几个都是不太容易区分的函数 functionmeancapacity()获得容…...
TensorFlow2.0教程1-Eager
文章目录 张量极其操作1 张量自定义层一、网络层layer的常见操作二、实现自定义网络层三、网络层组合自动求导一、Gradient tapes二、记录控制流三、高阶梯度自定义训练(基础)一、Variables二、示例:拟合线性模型1、定义模型2.定义损失函数3.获取训练数据4.定义训练循环张…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...