【(数据结构) —— 顺序表的应用-通讯录的实现】
(数据结构)—— 顺序表的应用-通讯录的实现
- 一.通讯录的功能介绍
- 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…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...