【数据结构】顺序表与通讯录的实现(C)
文章目录一、顺序表的概念与结构1. 线性表的基础2. 顺序表与数组的区别二、顺序表的分类三、顺序表的结构设计四、核心功能实现1. 初始化与销毁2. 空间检查与扩容3. 插入操作尾插头插指定位置之前插入4. 删除操作尾删头删指定位置删除5. 查找与打印五、测试代码与运行结果六、顺序表的应用通讯录1. 项目需求2. 核心设计思路1数据结构设计2核心功能实现七、顺序表的问题与思考优点缺点数据结构的作用高效存储数据方便快速查找支持灵活的增删改查操作最基础的数据结构是数组但它的局限性很大。比如当数组已满时插入新数据需要手动扩容频繁计算有效元素个数还会降低效率。这就是我们需要学习更高级结构的原因——顺序表就是数组的升级版。一、顺序表的概念与结构1. 线性表的基础顺序表属于线性表的一种。线性表是由n个相同特性的数据元素组成的有限序列常见的还有链表、栈、队列等。它的逻辑结构是一条连续的直线但物理存储方式可以是数组或链式结构。线性表物理结构不一定连续逻辑结构是连续的。顺序表物理结构和逻辑结构都是连续的2. 顺序表与数组的区别顺序表的底层基于数组实现但它对数组进行了封装提供了更完善的操作接口。简单说数组是原料顺序表是加工后的成品。比如数组只能通过下标访问而顺序表会额外记录有效元素个数和容量让数据管理更可控。二、顺序表的分类顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构通常采用数组存储。根据存储空间的分配方式可分为两类静态顺序表使用固定大小的数组存储数据空间一旦确定无法更改动态顺序表使用动态开辟的数组存储数据可根据需要动态扩容更灵活实用本文重点实现动态顺序表因为它能更好地适应数据量变化的场景。三、顺序表的结构设计首先我们需要定义顺序表的结构体动态顺序表需要包含三个核心要素typedefintSLDataType;// 数据类型别名方便后续修改存储类型structSeqList{SLDataType*arr;// 指向动态开辟的数组intsize;// 有效数据个数intcapacity;// 容量大小能存储的最大数据个数};typedefstructSeqListSL;// 重命名简化代码这样的设计有几个好处使用SLDataType统一数据类型后续要存储char或float只需修改这里分离size和capacity清晰区分当前数据量和总容量用指针指向动态数组实现存储空间的动态管理四、核心功能实现1. 初始化与销毁初始化函数将顺序表初始化为空状态voidSLInit(SL*p)// 传地址而不是传值因为要修改结构体内容{p-arrNULL;p-sizep-capacity0;// 初始状态无数据容量为0}销毁函数释放动态开辟的空间避免内存泄漏voidSLDes(SL*p){if(p-arr)// 如果数组存在则释放{free(p-arr);}p-arrNULL;// 置空指针避免野指针p-sizep-capacity0;// 重置状态}2. 空间检查与扩容动态顺序表的关键在于自动扩容我们实现一个专门的函数来处理voidcheckCapacity(SL*p){assert(p);// 确保指针有效// 当有效数据个数等于容量时需要扩容if(p-sizep-capacity){// 初始容量为4之后每次翻倍intnewCapacityp-capacity0?4:2*p-capacity;// 使用realloc进行扩容首次调用时相当于mallocSLDataType*tmp(SLDataType*)realloc(p-arr,newCapacity*sizeof(SLDataType));if(tmpNULL)// 检查扩容是否成功{perror(realloc fail!!);exit(1);// 扩容失败则退出程序}// 扩容成功更新指针和容量p-arrtmp;p-capacitynewCapacity;}}为什么选择2倍扩容这是一种时间和空间效率平衡的策略既能减少频繁扩容的开销又不会过度浪费空间。3. 插入操作尾插voidSLPushBack(SL*p,SLDataType x){assert(p);checkCapacity(p);// 先检查空间p-arr[p-size]x;// 直接在末尾赋值p-size;// 有效数据个数加 1}头插voidSLPushFront(SL*p,SLDataType x){assert(p);checkCapacity(p);// 从最后一个元素开始依次向后移动一位for(intip-size;i1;i--){p-arr[i]p-arr[i-1];}p-arr[0]x;// 头部位置赋值p-size;// 更新数据个数}指定位置之前插入voidSLInsert(SL*p,intpos,SLDataType x){assert(p);assert(pos0posp-size);// 确保位置有效checkCapacity(p);// 从最后一个元素到pos位置依次后移for(intip-size;ipos;i--){p-arr[i]p-arr[i-1];}p-arr[pos]x;// 在pos位置插入新元素p-size;}4. 删除操作尾删voidSLPopBack(SL*p){assert(p);assert(p-size);// 确保顺序表不为空p-size--;// 只需将有效数据个数减1逻辑删除}头删voidSLPopFront(SL*p){assert(p);assert(p-size);// 确保顺序表不为空// 从第二个元素开始依次向前移动一位for(inti0;ip-size-1;i){p-arr[i]p-arr[i1];}p-size--;// 更新数据个数}指定位置删除voidSLErase(SL*p,intpos){assert(p);assert(p-size);// 确保顺序表不为空assert(pos0posp-size);// 确保位置有效// 从pos位置开始依次用后一个元素覆盖前一个for(intipos;ip-size-1;i){p-arr[i]p-arr[i1];}p-size--;}5. 查找与打印查找元素返回元素所在位置未找到返回-1intSLFind(SL*p,SLDataType x){assert(p);for(inti0;ip-size;i){if(p-arr[i]x)returni;}return-1;// 未找到}打印顺序表遍历输出所有元素voidSLPrint(SL s){for(inti0;is.size;i){printf(%d ,s.arr[i]);}printf(\n);}五、测试代码与运行结果我们编写测试函数来验证各个功能voidSLtest01(){SL s1;SLInit(s1);// 初始化// 尾插测试SLPushBack(s1,1);SLPushBack(s1,2);SLPushBack(s1,3);SLPushBack(s1,4);SLPushBack(s1,5);SLPrint(s1);// 输出1 2 3 4 5// 指定位置插入测试SLInsert(s1,0,9);// 头部插入SLPrint(s1);// 输出9 1 2 3 4 5SLInsert(s1,s1.size,6);// 尾部插入等价于尾插SLPrint(s1);// 输出9 1 2 3 4 5 6// 指定位置删除测试SLErase(s1,1);// 删除索引1的元素SLPrint(s1);// 输出9 2 3 4 5 6SLErase(s1,2);// 删除索引2的元素SLPrint(s1);// 输出9 2 4 5 6SLErase(s1,s1.size-1);// 删除最后一个元素SLPrint(s1);// 输出9 2 4 5// 查找测试intfindSLFind(s1,4);printf(%d\n,find);// 输出2元素4在索引2位置SLDes(s1);// 销毁}六、顺序表的应用通讯录1. 项目需求实现一个具有以下功能的通讯录存储至少100个人的通讯信息保存信息包括名字、性别、年龄、电话、地址等支持增加、删除、查找、修改、显示联系人等操作程序结束后通讯录信息不丢失2. 核心设计思路1数据结构设计首先定义联系人信息结构体#defineNAME_MAX100#defineSEX_MAX4#defineTEL_MAX11#defineADDR_MAX100typedefstructPersonInfo{charname[NAME_MAX];// 姓名charsex[SEX_MAX];// 性别intage;// 年龄chartel[TEL_MAX];// 电话charaddr[ADDR_MAX];// 地址}PeoInfo;然后基于动态顺序表实现通讯录// 数据类型为PersonInfotypedefstructPersonInfoSQDataType;// 动态顺序表typedefstructSeqList{SQDataType*a;// 存储联系人数据intsize;// 有效联系人个数intcapacity;// 容量}SLT;// 通讯录类型定义typedefstructSeqListcontact;2核心功能实现初始化通讯录voidInitContact(contact*con){SeqListInit(con);// 初始化顺序表LoadContact(con);// 加载历史数据}添加联系人voidAddContact(contact*con){PeoInfo 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);SeqListPushBack(con,info);// 尾插printf(插入成功!\n);}删除联系人voidDelContact(contact*con){charname[NAME_MAX];printf(请输入要删除的用户姓名:\n);scanf(%s,name);intposFindByName(con,name);// 查找位置if(pos0){printf(要删除的用户不存在,删除失败!\n);return;}SeqListErase(con,pos);// 删除指定位置元素printf(删除成功!\n);}数据持久化为了保证程序结束后数据不丢失需要将数据保存到文件voidSaveContact(contact*con){FILE*pffopen(contact.txt,wb);if(pfNULL){perror(fopen error!\n);return;}// 将通讯录数据写入文件for(inti0;icon-size;i){fwrite(con-ai,sizeof(PeoInfo),1,pf);}printf(通讯录数据保存成功!\n);fclose(pf);}程序启动时加载数据voidLoadContact(contact*con){FILE*pffopen(contact.txt,rb);if(pfNULL){printf(fopen error!\n);return;}// 循环读取文件数据PeoInfo info;while(fread(info,sizeof(PeoInfo),1,pf)){SeqListPushBack(con,info);}printf(历史数据导入通讯录成功!\n);fclose(pf);}菜单交互voidmenu(){contact con;InitContact(con);intop-1;do{printf(********************************\n);printf(*****1、添加用户 2、删除用户*****\n);printf(*****3、查找用户 4、修改用户*****\n);printf(*****5、展示用户 0、退出 *****\n);printf(********************************\n);printf(请选择您的操作:\n);scanf(%d,op);switch(op){case1:AddContact(con);break;case2:DelContact(con);break;case3:FindContact(con);break;case4:ModifyContact(con);break;case5:ShowContact(con);break;case0:printf(退出程序\n);break;default:printf(输入有误,请重新输入\n);break;}}while(op!0);// 销毁通讯录,同时保存数据DestroyContact(con);}七、顺序表的问题与思考优点随机访问可以通过下标直接访问任意元素时间复杂度O(1)缓存友好数据存储连续充分利用CPU缓存访问效率高实现简单相比链表结构和操作更简单缺点插入删除效率问题中间或头部的插入删除操作需要移动大量元素时间复杂度为O(N)增容消耗增容时需要申请新空间、拷贝数据、释放旧空间会产生额外消耗空间浪费增容通常是2倍增长可能导致部分空间闲置例如容量从100增到200却只再插入5个数据就浪费了95个空间这些问题也引出了另一种重要的数据结构——链表它在解决上述问题上有独特优势。在实际开发中我们需要根据具体场景选择合适的数据结构。

相关新闻

【C语言】编译与链接过程

【C语言】编译与链接过程

文章目录一、程序的两种环境二、翻译环境2.1 多文件项目的构建流程2.2 编译的三个步骤2.2.1 预处理(预编译)2.2.2 编译2.2.3 汇编2.3 链接三、运行环境一、程序的两种环境 在ANSI C的任何一种实现中,都存在两个不同的环境,它们共…

2026/10/18 3:26:03 阅读更多 →
windows错误解决方案大全(不定期更新)

windows错误解决方案大全(不定期更新)

一、0x8007007ewindows更新错误winr→downlevel→回车→确认大多数文件修改日期(比如我的是2024/4/1 15:22)→移出/删除修改日期不是上述日期(2024/4/1 15:22)的→安装更新

2026/10/18 20:45:12 阅读更多 →
浏览器里同时跑 99 个 AI 和 2100+ 粒子:WebGL2、Canvas 与固定时间步优化实战

浏览器里同时跑 99 个 AI 和 2100+ 粒子:WebGL2、Canvas 与固定时间步优化实战

我在做《星团大作战》时,遇到的性能问题并不是"Canvas 能不能画几个圆",而是下面这些工作会同时出现: 1 名玩家和 99 个 AI 持续移动、追击、逃跑、分裂与吞噬;76007600 的世界里,基础食物对象有 2100 个&a…

2026/10/18 0:06:57 阅读更多 →

最新新闻

Python入门配套教程PDF:从验货到自主产出的完整指南

Python入门配套教程PDF:从验货到自主产出的完整指南

简介:一份面向Python初学者的入门配套索引文档,由千锋教育课程资料整理而来,适合零基础或刚接触Python的读者快速获取系统学习路径。文档核心价值在于汇总了千锋Python课程体系的多条百度云下载链接,覆盖基础教程、高手晋级视频总…

2026/10/18 21:13:42 阅读更多 →
Drools 7.48规则引擎实战:轻量嵌入、DRL编写与热更新

Drools 7.48规则引擎实战:轻量嵌入、DRL编写与热更新

简介:本资源为 Drools 规则引擎 7.48.0 Final 正式发行版完整分发包,面向 Java 开发者、业务规则系统设计人员及企业级规则引擎实践者,适用于构建可维护、可解释的业务规则管理(BRMS)解决方案,如风控策略引…

2026/10/18 21:13:42 阅读更多 →
油井产量预测模型对比:LSTM/CNN/Attention与ARIMA实战源码解析

油井产量预测模型对比:LSTM/CNN/Attention与ARIMA实战源码解析

简介:面向油田生产优化与人工智能交叉场景,源码围绕油井生产动态预测任务,完整实现了多种深度学习模型的建模与对比,适合石油工程技术人员、数据挖掘工程师及深度学习初学者参考。压缩包共232个文件,约12.38MB&#xf…

2026/10/18 21:13:42 阅读更多 →
Drools 7.48.0.Final 环境搭建避坑指南:JDK11+、KIE Server 启动与 Maven 集成

Drools 7.48.0.Final 环境搭建避坑指南:JDK11+、KIE Server 启动与 Maven 集成

简介:本资源为 Drools 规则引擎 7.48.0 Final 正式发行版完整分发包,面向 Java 开发者、企业级规则系统设计人员及中间件集成工程师,用于构建可维护、可扩展的业务规则管理与执行环境。压缩包为标准 ZIP 格式,大小 64.01MB&#x…

2026/10/18 21:13:42 阅读更多 →
YOLOv11管道泄漏检测系统全流程开发实战

YOLOv11管道泄漏检测系统全流程开发实战

管道泄漏检测这个方向,我接触了好几年,说实话在工业现场对它的认知一直在刷新。最早以为泄漏检测就是装个流量计、传感器的事,后来真正做过图像识别类项目才明白,视觉方案在管道巡检场景里有不可替代的位置——不用停产、不用接触…

2026/10/18 21:13:42 阅读更多 →
宝塔Nginx安装lua-cjson实战:从编译到接入OpenResty全指南

宝塔Nginx安装lua-cjson实战:从编译到接入OpenResty全指南

1. 需求场景:为什么要在宝塔 Nginx 里用 lua-cjson如果你的业务里已经有 Lua 脚本在跑,或者你正在用 OpenResty 做接口网关,那“JSON 编解码”就是一个绕不开的基本功。很多流量处理逻辑需要在请求阶段把 body 读出来、转成 table、做字段判断…

2026/10/18 21:12:41 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →