【(数据结构) —— 顺序表的应用-通讯录的实现】
(数据结构)—— 顺序表的应用-通讯录的实现
- 一.通讯录的功能介绍
- 1.基于动态顺序表实现通讯录
- (1). 功能要求
- (2).重要思考
- 二. 通讯录的代码实现
- 1.通讯录的底层结构(顺序表)
- (1)思路展示
- (2)底层代码实现(顺序表)
- 2.通讯录上层代码实现(通讯录结构)
- (1).思路展示
- (2).上层代码实现(通讯录)
- 3.通讯录代码运行展示(数据只用于测试,无实际意义)
- (1)测试展示
- (2)升华总结
一.通讯录的功能介绍
1.基于动态顺序表实现通讯录
C语言基础要求:结构体、动态内存管理、顺序表、文件件操作
(1). 功能要求
1)至少能够存储100个人的通讯信息
2)能够保存用户信息:名字、性别、年龄、电话、地址等
3)增加联系人信息
4)删除指定联系人
5)查找制定联系人
6)修改指定联系人
7)显示联系人信息
(2).重要思考
【思考1】用静态顺序表和动态顺序表分别如何实现
【思考2】如何保证程序结束后,历史通讯录信息不会丢失
二. 通讯录的代码实现
1.通讯录的底层结构(顺序表)
(1)思路展示
由于,通讯录是基于动态顺序表实现的,所以掌握基本的顺序表的结构代码,非常重要~!
(2)底层代码实现(顺序表)
1.
SeqList.h
#pragma once
#include"Contact.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>//typedef int SLDataType;
//更改数据类型为通讯录数据类型
//以下的方式任意选择即可
typedef struct ContactInfo SLDataType;
//typedef CInfo SLDataType;typedef struct SeqList
{SLDataType* a;int size;//当前顺序表中的数据有效个数int capacity;//顺序表的当前空间的大小
}SL;
//typedef struct SeqList SL;//对顺序表进行初始化
void SLInit(SL* ps);
void SLDestroy(SL* ps);
//头部/尾部/插入/删除
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);//任意位置/插入/删除
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);//打印
void SLPrint(SL* ps);
bool SLIsEmpty(SL* ps);//查找
bool SLFind(SL* ps, SLDataType x);
2.
SeqList.c
#include"SeqList.h"//初始化顺序表
void SLInit(SL* ps)
{ps->a = NULL;ps->size = ps->capacity = 0;
}
void SLDestroy(SL* ps)
{if (ps->a)free(ps->a);ps->a = 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->a, newCapacity * sizeof(SLDataType));if (tmp == NULL){perror("realloc Fail!\n");return 1;}ps->a = tmp;ps->capacity = newCapacity;}
}//尾插
void SLPushBack(SL* ps, SLDataType x)
{//判断顺序表是否为空//assert(ps->a = NULL);//暴力方式assert(ps);//柔和的方式/*if (ps->a == NULL)return;*///1)空间足够,直接插入//2)空间不够,需要扩容SLCheckCapacity(ps);//空间足够,直接插入ps->a[ps->size++] = x;
}
//头插
void SLPushFront(SL* ps, SLDataType 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++;
}
//尾删
void SLPopBack(SL* ps)
{assert(ps);assert(!SLIsEmpty(ps));//ps->a[ps->size - 1] = 0;ps->size--;
}//头删
void SLPopFront(SL* ps)
{assert(ps);assert(!SLIsEmpty(ps));for (size_t i = 1; i < ps->size - 1; i++){//最后一次进来的是ps->a[ps->size-2]ps->a[i] = ps->a[i + 1];//pa->a[ps->size-2]=ps->a[ps->size-1]}ps->size--;
}//任意位置插入
void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);//判断插入的位置是否在范围内assert(pos >= 0 && pos <= ps->size);SLCheckCapacity(ps);//空间足够,把pos的位置及以后的数据往后移一位//此处i<ps->size和ps->size-1都可以,但是后面的不步骤需要对应for (size_t i = ps->size; i > pos; i--){ps->a[i] = ps->a[i - 1];}/*for (size_t i = ps->size - 1; i > pos; i--){ps->a[i+1] = ps->a[i];}*/ps->a[pos] = x;ps->size++;}
//任意位置删除
void SLErase(SL* ps, int pos)
{assert(ps);assert(!SLIsEmpty(ps));assert(pos >= 0 && pos < ps->size);//pos位置及以后的数据往前移动一位for (size_t i = pos; i < ps->size - 1; i++){ps->a[i] = ps->a[i + 1];}ps->size--;}void SLPrint(SL* ps)
{for (size_t i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf("\n");
}
bool SLIsEmpty(SL* ps)
{assert(ps);//这样是不对的,这只是判断空间是否足够//return ps->size = ps->capacity;return ps->size == 0;
}//bool SLFind(SL* ps, SLDataType x)
//{
// scanf("%d", &x);
// for (size_t i = 0; i < ps->size; i++)
// {
// if (ps->a[i] == x)
// {
// return true;
// }
// }
// return false;
//}
3.
test.c
#include"SeqList.h"
#include"Contact.h"//void SLtest()
//{//SL sl;//SLInit(&sl);顺序表的具体操作尾插//SLPushBack(&sl, 1);//SLPushBack(&sl, 2);//SLPushBack(&sl, 3);//SLPushBack(&sl, 4);//SLPrint(&sl);头插//SLPushFront(&sl, 5);//SLPushFront(&sl, 6);//SLPushFront(&sl, 7);//SLPushFront(&sl, 8);//SLPrint(&sl);//尾删//SLPopBack(&sl);//SLPrint(&sl);//SLPopBack(&sl);//SLPrint(&sl);头删//SLPopFront(&sl);//SLPrint(&sl);//SLPopFront(&sl);//SLPrint(&sl);//任意位置插入删除/*SLInsert(&sl, 0, 9);SLPrint(&sl);SLErase(&sl, 8);SLPrint(&sl);bool ret = SLFind(&sl, 9);if (ret)printf("找到了\n");elseprintf("没找到\n");SLDestroy(&sl);*/
//}
void Contact01()
{contact con;ContactInit(&con);//往通讯录中插入数据ContactAdd(&con);ContactAdd(&con);ContactShow(&con);//从通讯录里删除指定的数据ContactDel(&con);ContactShow(&con);//从通讯录里查找指定的联系人ContactFind(&con);//在通讯录里修改指定的联系人ContactModify(&con);ContactDestroy(&con);}
void menu()
{printf("***************通讯录****************\n");printf("***** 1.添加联系人 2.删除联系人*****\n");printf("***** 3.修改联系人 4.查找联系人*****\n");printf("***** 5.查看通讯录 0.退出通讯录*****\n");printf("*************************************\n");}
int main()
{//SLtest();//Contact01();int op = -1;contact con;ContactInit(&con);do{menu();printf("请选择你要进行的操作:\n");scanf("%d", &op);switch (op){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 0:printf("已退出通讯录\n");break;default:printf("系统里没有找到你需要进行的操作,请重新输入:\n");break;}} while (op != 0);ContactDestroy(&con);return 0;
}
2.通讯录上层代码实现(通讯录结构)
(1).思路展示
1)由于,通讯录是基于动态顺序表实现的。
2)所以,通讯录上层代码,只需要在上上层代码的头文件代码中创建一个保存联系人的结构,然后再定义通讯录功能函数即可。
3)接着在通讯录上层代码的源文件中将这些功能函数实现即可。
4)基于前面,我们已经知道,通讯录是基于动态顺序表实现的,所以在实现通讯录功能函数时,只需要在通讯录上层代码的源文件中,加上顺序表的头文件就可以调运顺序表的函数来实现通讯录了。
(2).上层代码实现(通讯录)
1.
Contact.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1//创建保存联系人的结构
#define NAME_MAX 100
#define SEX_MAX 10
#define TEL_MAX 15
#define ADDR_MAX 100struct ContactInfo
{char name[NAME_MAX];//名字char sex[SEX_MAX];//性别int age;//年龄char tel[TEL_MAX];//电话char addr[ADDR_MAX];//家庭住址
};
typedef struct ContactInfo CInfo;//通讯录底层是用顺序表来实现的
typedef struct SeqList contact;//通讯录的初始化和销毁
void ContactInit(contact* pcon);
void ContactDestroy(contact* pcon);//添加联系人
void ContactAdd(contact* pcon);
//删除联系人
void ContactDel(contact* pcon);
//修改联系人
void ContactModify(contact* pcon);
//查看通讯录
void ContactShow(contact* pcon);
//查找联系人
void ContactFind(contact* pcon);
2.
Contact.c
#include"Contact.h"
#include"SeqList.h"//通讯录的初始化与销毁
void ContactInit(contact* pcon)
{SLInit(pcon);
}void ContactDestroy(contact* pcon)
{SLDestroy(pcon);
}//添加联系人
void ContactAdd(contact* pcon)
{//接下来获取的都是结构体CInfo结构体里要求的数据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);//联系人数据都获取到了,并保存到了结构体info中//往通讯录(顺序表)中插入数据SLPushBack(pcon, info);
}int FindByName(contact* pcon, char name[])
{for (int i = 0; i < pcon->size; i++){if (strcmp(pcon->a[i].name, name) == 0){return i;}}return -1;
}//删除联系人
void ContactDel(contact* pcon)
{//直接强制用户使用名称来查找printf("请输入要删除的联系人姓名:\n");char name[NAME_MAX];scanf("%s", name);int findidex = FindByName(pcon, name);if (findidex < 0){printf("要删除的联系人不存在!\n");return;}//找到了,要删除findidex位置的数据SLErase(pcon, findidex);printf("删除成功\n");
}//修改联系人选项
void MondifyMenu()
{printf("***************修改联系人选项****************\n");printf("***** 1.修改联系人名字 2.修改联系人性别*****\n");printf("***** 3.修改联系人年龄 4.修改联系人电话*****\n");printf("***** 5.修改联系人住址 0.退出删除选项*******\n");printf("******************************************\n");
}
//修改联系人
void ContactModify(contact* pcon)
{printf("请输入你需要修改的联系人:\n");char name[NAME_MAX];scanf("%s", name);int find = FindByName(pcon, name);if (find < 0){printf("要修改的联系人不存在!\n");return;}printf("找到了:\n");printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");printf("%-5s %-5s %-4d %-4s %-4s\n",pcon->a[find].name,pcon->a[find].sex,pcon->a[find].age,pcon->a[find].tel,pcon->a[find].addr);int val = -1;do{MondifyMenu();printf("请选择你需要修改的信息:\n");scanf("%d", &val);switch (val){case 1:printf("请输入修改后的联系人姓名:\n");scanf("%s", pcon->a[find].name);break;case 2:printf("请输入修改后的联系人性别:\n");scanf("%s", pcon->a[find].sex);break;case 3:printf("请输入修改后的联系人年龄:\n");scanf("%d", &pcon->a[find].age);break;case 4:printf("请输入修改后的联系人电话:\n");scanf("%s", pcon->a[find].tel);break;case 5:printf("请输入修改后的联系人住址:\n");scanf("%s", pcon->a[find].addr);break;case 0:printf("修改成功\n");printf("已退出删除联系人选项\n");break;default:printf("没有找到要修改的选项 请重新选择:\n");break;}} while (val != 0);}
//查看通讯录
void ContactShow(contact* pcon)
{//打印表头printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");for (int i = 0; i < pcon->size; i++){printf("%-5s %-5s %-4d %-4s %-4s\n", pcon->a[i].name,pcon->a[i].sex,pcon->a[i].age,pcon->a[i].tel,pcon->a[i].addr);}}
//查找指定联系人
void ContactFind(contact* pcon)
{printf("请输入你要查找的联系人:\n");char name[NAME_MAX];scanf("%s", name);int findidex = FindByName(pcon, name);if (findidex < 0){printf("你要查找的联系人不存在!\n");return;}printf("找到了:\n");printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");printf("%-5s %-5s %-4d %-4s %-4s\n",pcon->a[findidex].name,pcon->a[findidex].sex,pcon->a[findidex].age,pcon->a[findidex].tel,pcon->a[findidex].addr);
}
3.通讯录代码运行展示(数据只用于测试,无实际意义)
(1)测试展示
(2)升华总结
这里只是展示基于动态顺序表实现通讯录的大致框架,和一些基本功能,有兴趣,能力的小伙伴,也可以下去拓展一下通讯录的其他功能,优化的更加完善,美观的通讯录。
感谢学习!
相关文章:

【(数据结构) —— 顺序表的应用-通讯录的实现】
(数据结构)—— 顺序表的应用-通讯录的实现 一.通讯录的功能介绍1.基于动态顺序表实现通讯录(1). 功能要求(2).重要思考 二. 通讯录的代码实现1.通讯录的底层结构(顺序表)(1)思路展示(2)底层代码实现(顺序表) 2.通讯录上层代码实现(通讯录结构…...

macbook磁盘清理免费教程分享
笔记本电脑在是我们工作和生活中重要组成部分,磁盘清理是常有的事,而macbook作为其中的代表之一,也越来越受到人们的青睐。然而,如何进行macbook磁盘清理,也事许多人都会遇到的问题,特别是被提示“磁盘已满…...

cartographer_ros数据加载与处理
node_main.cc 坐标系的读取通过tf_bufferautonode类是cartographer_ros接收传感器数据,并传输到cartographer里,同时还会发布map,轨迹等node_options数据传给两个地方,一个是map_builder进行slam操作,一个是node做数据…...

设计模式-7种结构型模式
适配器模式: 将一个类的接口转换成用户希望得到的另一种接口。它使原本不相容的接口得以协同调用。 桥接模式: 将类的抽象部分和他的实现部分分离开来。是他们可以独立的变化。 它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两…...

华为李鹏:加速5G商业正循环,拥抱更繁荣的5.5G(5G-A)
2023年10月10日,在华为主办的第十四届全球移动宽带论坛上,华为高级副总裁、运营商BG总裁李鹏面向来自全球的运营商和产业伙伴,提出抓住网络需求和趋势的力量——“面向后天的业务,积极规划明天的网络,加速5G商业正循环…...

Marin说PCB之CoilcraftBourns POC 电感的性能对比
十一小长假本来是一件美好事情。可是天有不测风云,小编我却有祸兮来了。本来是公司的硬件同事强哥要回以色列了,最近他们国家那边都在打仗,强哥本着舍身为国的精神回国抗战去了。小编我就想着在他回国之前搞了篮球比赛送别一下他呢࿰…...

聊聊Maven的依赖传递、依赖管理、依赖作用域
1. 依赖传递 在Maven中,依赖是会传递的,假如在业务项目中引入了spring-boot-starter-web依赖: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>…...

centos6/7 SOCKS5 堆溢出漏洞修复(RPM方式)curl 8.4 CVE-2023-38545 CVE-2023-38546
引用 https://darkdark.top/update-curl.html centos6 rpm 升级包下载:https://download.csdn.net/download/sinat_24092079/88425840 yum update libcurl-8.4.0-1.el6.1.x86_64.rpm curl-8.4.0-1.el6.1.x86_64.rpmcentos7 rpm 升级包下载:https://down…...

C#,数值计算——数据建模Proposal的计算方法与源程序
1 文本格式 using System; namespace Legalsoft.Truffer { public class Proposal { public Normaldev gau { get; set; } null; private double logstep { get; set; } public Proposal(int ranseed, double lstep) { this.gau…...

如何使用命令生成动态链接库.dll文件(保姆级教学)
如何使用命令生成动态链接库.dll文件 /*** file 如何使用命令生成动态链接库.dll文件* author jUicE_g2R(qq:3406291309)* * brief 教学演示* tool visual studio2022(2019也适用)* * copyright 2023.10* COPYR…...

Qt之模块介绍
Qt提供了很多功能模块,我们需要知道的是这些模块有些加入了标准库,有一些并没有加入到标准库。至于为什么没有加入到标准库通过chatgpt得到的答案如下: Qt 是一个强大的跨平台 C 框架,它包括了很多核心模块和功能,以支…...

Socks5代理和代理IP
在数字时代,网络工程师必须不断掌握新技术,以解决跨界电商、爬虫数据采集、出海业务扩展、网络安全保护以及游戏性能优化等各种技术挑战。本文将深入探讨Socks5代理和代理IP技术,它们在各个领域中的应用,如何为网络工程师提供了强…...

计算机指令、机器码
目录 背景 在软硬件接口中,CPU 帮我们做了什么事? 从编译到汇编,代码怎么变成机器码? 解析指令和机器码 总结延伸 背景 上大学的时候,我们系里教 C 语言程序设计的老师说,他们当年学写程序的时候&…...

MyLife - Docker安装Consul
Docker安装Consul 个人觉得像consul之类的基础设施在线上环境直接物理机安装使用可能会好些。但是在开发测试环境用docker容器还是比较方便的。这里学习下docker安装consul使用。 1. Consul 镜像库地址 Consul 镜像库地址:https://hub.docker.com/r/hashicorp/consu…...

Leetcode刷题笔记--Hot61-70
1--课程表(207) 主要思路: 用 in 记录每一门课程剩余的先修课程个数,当剩余先修课程个数为0时,将该课程加入到队列q中。 每修队列q中的课程,以该课程作为先修课程的所有课程,其剩余先修课程个数…...

python特别篇—github基本操作手册
一、开始使用 1.1 “Hello world” 1.1.1 github介绍 GitHub是一个基于Git版本控制系统的代码托管平台。它提供了一个在线的代码仓库,使开发者可以将自己的代码存储在云端,并与其他开发者进行协作。GitHub不仅仅是一个代码托管平台,还提供了…...

tiktok直播websocket序列化与反序列化
系列文章目录 websocket训练地址:https://www.qiulianmao.com,正在搭建中 基础-websocket逆向基础-http拦截基础-websocket拦截基础-base64编码与解码基础-protobuf序列化与反序列化视频号直播弹幕采集tiktok protobuf序列化与反序列化实战一:Http轮询更新中tikto...

微信picker弹出之后 , 背景变成灰色是怎么做的
微信小程序在弹出picker组件时,会将页面背景变为半透明的灰色,这是通过设置一个全屏的蒙层来实现的。 具体实现方法如下: 在WXML文件中,添加一个view元素作为蒙层,并设置其样式和属性: <view class&q…...

通用考勤后台管理系统
考勤后台系统,包括待办事项、人员管理、任务中心、任务详情、我的任务、客户管理、考勤功能几大功能,本后台系统以考勤打卡为主要功能,采用分屏布局的方式,简洁大方,使用方便...

LeetCode75——Day5
文章目录 一、题目二、题解 一、题目 345. Reverse Vowels of a String Given a string s, reverse only all the vowels in the string and return it. The vowels are ‘a’, ‘e’, ‘i’, ‘o’, and ‘u’, and they can appear in both lower and upper cases, more t…...

面向C++模块的开源 IFC SDK
早在 VS2019 v16.10 版本的时候,我们就官宣了对 C 模块(以及几乎所有其他 C 20 特性)的全面支持,包括 MSVC 编译器工具集,静态分析,智能感知和调试器等,而实现模块需要将 C 代码实现为一种内部的临时表示形式。 今天&…...

Docker开启远程访问+idea配置docker+dockerfile发布java项目
一、docker开启远程访问 1.编辑docker服务文件 vim /usr/lib/systemd/system/docker.servicedocker.service原文件如下: [Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target docker.socke…...

基于nodejs+vue教学辅助管理系统
学生;首页、个人中心、本课程设计了线上教学辅助系统 ,学生可以此系统实现在线学习,作业提交管理、作业成绩管理。随着社会的快速发展,计算机的影响是全面且深入的。教师:首页、个人中心、课程信息管理、教学资料管理、作业信息管…...

Qt 子线程中无限递归的信号槽导致主线程槽失效的原因和解决办法
Qt 子线程中无限递归的信号槽导致主线程槽失效的原因和解决办法 问题描述 在一个 Qt6.5.3 的项目中,有一个 ImageProcessor 类负责在子线程中进行图像处理,并有一个 MainWindow 类在主线程中进行界面更新。虽然 ImageProcessor::processingDone 信号被…...

实施 DevSecOps 最佳实践
DevSecOps 是一个框架,它将开发 (Dev)、IT 运营 (Ops) 和安全 (Sec) 流程的实践融合到一个简化的流程中。使用这种方法,DevSecOps 团队能够确保将安全性集成到软件开发生命周期中,确保以“安全第一”的心态构建、部署和维护软件。在本教程中&…...

第56节——redux-toolkit中的createAction——了解
一、概念 createAction 是一个用于创建 Redux action creator 的函数,它可以让你更快地编写 Redux 相关的代码,并且更加易于阅读和维护。 二、简单示例 使用 createAction,你只需要传入一个字符串类型的 action type,然后它会返…...

【数据结构】排序--选择排序(堆排序)
目录 一 堆排序 二 直接选择排序 一 堆排序 堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是 通过堆来进行选择数据。 需要注意的是排升序要建大堆,排降序建小堆。 直接选择排…...

C# 图解教程 第5版 —— 第2章 C# 和 .NET Core
文章目录 2.1 .NET 框架的背景2.2 为什么选择 .NET Core(和 Xamarin)2.3 .NET Core 的目标2.4 多平台支持2.5 快速发展和升级2.6 程序占用空间小、部署简单、版本问题少2.7 开源社区支持(*)2.8 改进的应用程序性能2.9 全新的开始&…...

数据结构 | Huffman TreeCode
构造参考: 赫夫曼树_关于huffman树,权值相同-CSDN博客 编码参考: 【数据结构与算法】-哈夫曼树(Huffman Tree)与哈夫曼编码_数据结构哈夫曼树编码-CSDN博客...

mysql拼接字符串函数
在MySQL中,可以使用CONCAT()函数来拼接字符串。CONCAT()函数接受一个或多个字符串作为参数,并将它们连接在一起。以下是CONCAT()函数的使用示例: 拼接两个字符串: SELECT CONCAT(Hello, , World); -- 输出: Hello World 拼接列中…...