【数据结构与算法】解锁顺序表潜能:一站式实现高效通讯录系统

【数据结构与算法】解锁顺序表潜能:一站式实现高效通讯录系统
在这里插入图片描述
🔥小龙报:个人主页
🎬作者简介:C++研发,嵌入式,机器人等方向学习者
❄️个人专栏:《C语言》《【初阶】数据结构与算法》
永远相信美好的事情即将发生
在这里插入图片描述

文章目录

前言

本文聚焦C语言顺序表的实战应用,从零搭建功能完整的通讯录系统。通过封装顺序表的增删改查核心逻辑,实现联系人的添加、删除、修改、查找与展示功能,兼顾内存动态扩容与安全销毁机制。代码遵循模块化设计思想,清晰划分接口层与底层逻辑,既适合巩固数据结构基础,也为新手提供可直接复用的实战案例,助力快速掌握多文件编程与结构化开发思维(许多大学C语言期末大作业就是这个希望能给小伙伴们一些启发)。


一、通讯录框架Test.c

#include "seqlist.h"#include "Contacts.h"voidmenu(){printf("******************通讯录******************\n");printf("*******1.增加联系人 2.删除联系人********\n");printf("*******3.修改联系人 4.查找联系人********\n");printf("*******5.展示联系人 0. 退出 *********\n");printf("******************************************\n");}intmain(){int op;Contacts s;SLInit(&s);do{menu();printf("请输入你的选择:");scanf("%d",&op);switch(op){case1:ContactsAdd(&s);break;case2:ContactsDel(&s);break;case3:ContactsModify(&s);break;case4:ContactsFind(&s);break;case5:ContactsShow(&s);break;case0:printf("退出通讯录....\n");break;default:printf("输入错误,请重新选择您的操作!\n");break;}}while(op);ContactsDestory(&s);return0;}

二、通讯录

2.1 Contacts.h

#define max_name 20#define max_gender 20#define max_tel 30#define max_addr 50//姓名 性别 年龄 电话 地址 typedef structPersonalInfor{char name[max_name];char gender[max_gender];int age;char tel[max_tel];char addr[max_addr];}peoInfo; typedef structSeqList Contacts;//通讯录的初始化和销毁voidContactsInit(Contacts* ps);//通讯录的销毁voidContactsDestory(Contacts* ps);//通讯录的打印voidContactsShow(Contacts* ps);//通讯录的插入voidContactsAdd(Contacts* ps);//通讯录的删除voidContactsDel(Contacts* ps);//通讯录的查找voidContactsFind(Contacts* ps);//通讯录的修改voidContactsFind(Contacts* ps);
注意
(1)为什么要typedef struct SeqList Contacts;这么写
答:前置声明:因为在SeqList.h和Contacts.h里互相包含头文件会编译错误所以这么写。
前置声明:前向声明(前置声明)只是告诉编译器 “这个类型存在”,但如果要实际使用这个类型(比如访问成员、创建非指针变量、调用相关函数),就必须要有完整的定义
(2)为什么不能typedef SL Contacts;这么写
答:因为在Contacts.h里面并没有包含SeqList.h这个头文件,所以无法识别SL是什么,它只认识 int、struct XXX 这类 “基础标识”,不认识自定义的别名。

2.2 Contacts.c

本质:底层依赖顺序表的实现逻辑。

#include "SeqList.h"#include "Contacts.h"//初始化voidContactsInit(Contacts* ps){SLInit(ps);}//销毁voidContactsDestory(Contacts* ps){SLDestory(ps);}//打印voidContactsShow(Contacts* ps){SLPrint(ps);}//插入voidContactsAdd(Contacts* ps){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.tel);printf("请输入要添加的联系人住址:\n");scanf("%s", info.addr);SLPushBack(ps,info);}//删除intFindName(Contacts* ps,char* str){for(int i =0; i < ps->size; i++){if(strcmp(ps->a[i].name, str)==0)return i;}return-1;}voidContactsDel(Contacts* ps){//要删除的数据必须要存在,才能执行删除操作//查找char name[30];printf("请输入要删除的数据的姓名:\n");scanf("%s", name);int find =FindName(ps,name);if(find ==-1){printf("此数据已删除或未有此数据\n");return;}SLErase(ps, find);printf("删除成功!\n");}//通讯录的查找voidContactsFind(Contacts* ps){char name[max_name];printf("请输入要查找的数据的姓名:\n");scanf("%s", name);int find =FindName(ps, name);if(find ==-1){printf("此数据已删除或未有此数据\n");return;}printf("姓名: %s 性别 : %s 年龄 : %d 电话 : %s 地址 : %s\n", ps->a[find].name,ps->a[find].gender,ps->a[find].age,ps->a[find].tel,ps->a[find].addr);}//修改voidContactsModify(Contacts* ps){//通讯录不为空if(ps->size ==0){printf("当前通讯录为空\n");return;}//要修改的联系人数据存在char name[max_name];printf("请输入要修改的用户姓名:\n");scanf("%s", name);int find =FindName(ps, name);if(find <0){printf("要修改的联系人数据不存在!\n");return;}else{//直接修改printf("请输入新的姓名:\n");scanf("%s", ps->a[find].name);printf("请输入新的性别:\n");scanf("%s", ps->a[find].gender);printf("请输入新的年龄:\n");scanf("%d",&ps->a[find].age);printf("请输入新的电话:\n");scanf("%s", ps->a[find].tel);printf("请输入新的住址:\n");scanf("%s", ps->a[find].addr);printf("修改成功!\n");}}

三、底层逻辑

3.1 SeqList.h

#include <stdio.h>#include <assert.h>#include <stdlib.h>#include "Contacts.h" typedef peoInfo SLDateType; typedef structSeqList{ SLDateType* a;//存储数据int size;//有效数据个数int capacity;//空间容量}SL;voidSLInit(SL* ps);//初始化voidSLDestory(SL* ps);//销毁voidSLPrint(SL* ps);//打印//插入部分voidSLPushBack(SL* ps,SLDateType x);//尾插//删除部分voidSLPopback(SL* ps);//尾删voidSLPopFront(SL* ps);//头删voidSLErase(SL* ps,int pos);//任意位置删除

3.2 SeqList.c

#include "seqlist.h"#include "Contacts.h"//初始化voidSLInit(SL* ps){ ps->a = NULL; ps->size = ps->capacity =0;}//销毁voidSLDestory(SL* ps){if(ps->a){free(ps->a); ps->a = NULL;} ps->size = ps->capacity =0;}//打印voidSLPrint(SL* ps){for(int i =0; i < ps->size; i++)printf("姓名:%s 性别:%s 年龄:%d 电话:%s 地址:%s\n", ps->a[i].name,ps->a[i].gender,ps->a[i].age,ps->a[i].tel,ps->a[i].addr);}//检查是否需要扩容voidCheckCapacity(SL* ps){int newcapacity = ps->capacity ==0?4: ps->capacity *2; SLDateType* temp =realloc(ps->a, newcapacity *sizeof(SLDateType));if(temp == NULL){printf("开辟失败!\n");exit(-1);} ps->a = temp; ps->capacity = newcapacity;}//尾插voidSLPushBack(SL* ps,SLDateType x){assert(ps);if(ps->size == ps->capacity)CheckCapacity(ps); ps->a[ps->size++]= x;}//任意位置删除voidSLErase(SL* ps,int pos){assert(ps);assert(pos >=0&& pos < ps->size);for(int i = pos +1; i < ps->size; i++) ps->a[i -1]= ps->a[i]; ps->size--;}

四、基于顺序表的通讯录实现效果

4.1 添加

在这里插入图片描述

4.2 删除

在这里插入图片描述

4.3 修改

在这里插入图片描述

4.4 查找

在这里插入图片描述

4.5 展示

在这里插入图片描述

总结与每日励志

✨本文基于C语言顺序表实现通讯录管理系统,包含添加、删除、修改、查找和展示联系人功能。通过模块化设计将底层顺序表操作与通讯录业务逻辑分离,使用动态内存管理实现扩容机制。代码采用多文件结构,包含测试框架、通讯录接口和顺序表实现三部分,完整展示了数据结构的实际应用。系统具有以下特点:1)支持联系人信息的完整CRUD操作;2)采用类型封装解决头文件循环引用问题;3)提供内存安全保证;4)交互式菜单界面。该实现既可作为数据结构学习案例,也适用于C语言课程实践项目。

在这里插入图片描述

Read more

【数据结构-初阶】顺序表相关习题

【数据结构-初阶】顺序表相关习题

🎈主页传送门:良木生香 🔥个人专栏:《C语言》 《数据结构-初阶》 《程序设计》 🌟人为善,福随未至,祸已远行;人为恶,祸虽未至,福已远离 上期回顾:在上一篇文章中(【数据结构-初阶】详解线性表(1)---顺序表),我们详细介绍了线性表系列第一种数据结构---顺序表,这个数据结构是以数组为底建立的,也学习了如何用线性表进行增删查改的操作,那么我们今天就用顺序表进行解题~~~   题目一:移除元素 这是题目链接:27.移除元素,下面是具体的题目与示例: 由题意知,这道题是想让我们将数组中值为val的元素删除,我们能怎么做呢? 创建新的数组?那不行,题目已经要求我们只能在原地进行操作了,就意味着不能创建新的数组来进行辅助 那该怎么办呢?简单,我们只需用上算法中最基础的---双指针算法了 我们用双指针,不一定用真的指针指向某个元素,有时也可以用下标,讲究的是一种算法思想,并没有一定的形式 我们用两个指针,刚开始都同事之下那个num数组的第一个元素,随后将其中一个指针用于遍历数组,如果两个指针指向的内容不相同,那就将内容进行交换,两个指针同时向后移动一位;如果相同

By Ne0inhk
《算法题讲解指南:优选算法-模拟》--38.替换所有问号,39.提莫攻击,40.Z 字形变换

《算法题讲解指南:优选算法-模拟》--38.替换所有问号,39.提莫攻击,40.Z 字形变换

🔥小叶-duck:个人主页 ❄️个人专栏:《Data-Structure-Learning》 《C++入门到进阶&自我学习过程记录》《算法题讲解指南》--从优选到贪心 ✨未择之路,不须回头 已择之路,纵是荆棘遍野,亦作花海遨游 目录 38.替换所有问号 题目链接: 题目描述: 题目示例: 解法(模拟): 算法思路: C++算法代码: 算法总结及流程解析: 39.提莫攻击 题目链接: 题目描述: 题目示例: 解法(模拟+分情况讨论): 算法思路: C++算法代码: 算法总结及流程解析: 40.Z 字形变换 题目链接: 题目描述: 题目示例: 解法(模拟+找规律): 算法思路: C+

By Ne0inhk
HDFS机架感知(Rack Awareness)深度解析:原理、实现与重要性

HDFS机架感知(Rack Awareness)深度解析:原理、实现与重要性

HDFS机架感知(Rack Awareness)深度解析:原理、实现与重要性 * 引言 * 一、什么是机架感知? * 1.1 核心概念 * 1.2 节点距离计算 * 二、机架感知的实现原理 * 2.1 默认情况 vs 启用机架感知 * 2.2 机架感知的两种实现方式 * 方式一:基于脚本的拓扑映射(最常用) * 方式二:自定义Java类实现 * 2.3 机架信息在NameNode中的存储 * 三、基于机架感知的副本放置策略 * 3.1 默认3副本放置规则 * 3.2 放置策略示意图 * 四、为什么机架感知对HDFS至关重要? * 4.1 核心价值 * 4.2 可靠性提升:容忍机架级故障

By Ne0inhk

「JVM」Java 垃圾回收机制全解析:回收算法、分代流转与 G1 收集器底层拆解

在 Java 开发中,JVM 的垃圾回收(Garbage Collection, GC)机制是我们避不开的核心内功。理解 GC 不仅能帮我们在面试中游刃有余,更是日常排查 OOM 问题、进行线上服务调优的基石。 本文将带你系统地梳理 JVM 垃圾回收的核心脉络:如何判断对象已死?垃圾该怎么回收?堆内存如何分代?以及主流的垃圾回收器都有哪些,最后奉上一些宏观的调优思路。 1. 灵魂拷问:如何判断对象可以被回收? 垃圾回收的第一步,是找出内存中哪些对象已经“失去价值”。 引用计数法(已淘汰) 这是一种最直观的算法:给对象添加一个引用计数器,有其他地方引用它时计数加一,引用失效时减一。计数为 0 时即可回收。 致命缺陷:无法解决循环引用的问题(A 引用 B,B 引用 A,两者计数均为 1,导致永远无法被回收)

By Ne0inhk