【数据结构】顺序表与通讯录的实现(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/7/19 19:06:07阅读更多 →
Ohook:三步解锁Microsoft 365完整功能的终极免费指南

Ohook:三步解锁Microsoft 365完整功能的终极免费指南

Ohook:三步解锁Microsoft 365完整功能的终极免费指南 【免费下载链接】ohook An universal Office "activation" hook with main focus of enabling full functionality of subscription editions 项目地址: https://gitcode.com/gh_mirrors/oh/ohook …

2026/7/20 20:30:51阅读更多 →
如何用QNAP多云盘挂载工具实现云存储统一管理:3步快速配置指南

如何用QNAP多云盘挂载工具实现云存储统一管理:3步快速配置指南

如何用QNAP多云盘挂载工具实现云存储统一管理:3步快速配置指南 【免费下载链接】qnap-openlist-webdav 一款挂载多个云盘的工具 项目地址: https://gitcode.com/gh_mirrors/qn/qnap-openlist-webdav 你是否也曾为管理多个云存储平台而烦恼?阿里云…

2026/7/19 19:04:07阅读更多 →
如何快速配置阅读APP书源:26个高质量书源一键导入教程

如何快速配置阅读APP书源:26个高质量书源一键导入教程

如何快速配置阅读APP书源:26个高质量书源一键导入教程 【免费下载链接】Yuedu 📚「阅读」自用书源分享 项目地址: https://gitcode.com/gh_mirrors/yu/Yuedu 阅读APP作为一款强大的开源小说阅读工具,本身不提供小说内容,而…

2026/7/21 1:48:10阅读更多 →
EasyOCR参数调优终极指南:从新手到专家的8个实战技巧

EasyOCR参数调优终极指南:从新手到专家的8个实战技巧

EasyOCR参数调优终极指南:从新手到专家的8个实战技巧 【免费下载链接】EasyOCR Ready-to-use OCR with 80 supported languages and all popular writing scripts including Latin, Chinese, Arabic, Devanagari, Cyrillic and etc. 项目地址: https://gitcode.co…

2026/7/21 1:48:10阅读更多 →
终极岛屿规划指南:如何使用Happy Island Designer免费在线工具打造梦想岛屿

终极岛屿规划指南:如何使用Happy Island Designer免费在线工具打造梦想岛屿

终极岛屿规划指南:如何使用Happy Island Designer免费在线工具打造梦想岛屿 【免费下载链接】HappyIslandDesigner "Happy Island Designer (Alpha)",是一个在线工具,它允许用户设计和定制自己的岛屿。这个工具是受游戏《动物森友会…

2026/7/21 1:48:10阅读更多 →
企业级.NET平台开发实战:权限、流程与实时通信

企业级.NET平台开发实战:权限、流程与实时通信

1. 项目概述:企业级.NET平台的核心价值这个基于.NET 8/9/10的企业级开发平台,真正解决了企业信息化建设中的三大痛点:权限管理混乱、业务流程僵化、系统间通信滞后。我在多个大型企业级项目中验证过,这种整合了权限控制、流程引擎…

2026/7/21 1:48:10阅读更多 →
Delphi异常处理机制与最佳实践详解

Delphi异常处理机制与最佳实践详解

1. Delphi异常处理基础与核心机制Delphi的异常处理机制建立在Object Pascal语言强大的面向对象特性之上,其核心是通过异常类体系来封装和处理程序运行时的各种错误情况。与C等语言的异常处理相比,Delphi的实现更加简洁直观,同时又不失灵活性。…

2026/7/21 1:48:10阅读更多 →
数据科学家五大核心能力:从业务理解到模型落地的工程化路径

数据科学家五大核心能力:从业务理解到模型落地的工程化路径

1. 这不是一份“技能清单”,而是一份数据科学家的生存地图你点开这篇文章,大概率正站在职业转型的十字路口:可能是刚学完Python和SQL的应届生,对着招聘JD里“熟练掌握机器学习算法”发懵;也可能是做了三年业务分析的职…

2026/7/21 1:46:10阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/21 0:51:49阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/21 0:51:49阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/21 0:51:49阅读更多 →
Windows+macOS 通用 OpenClaw 部署流程,内置依赖一键启动智能桌面助手

Windows+macOS 通用 OpenClaw 部署流程,内置依赖一键启动智能桌面助手

📌教程适配:OpenClaw v2.7.9 | 兼容 Windows10/11、macOS 双系统 📖前言 当下各类本地 AI 工具层出不穷,多数产品仅能完成文字问答交互,很难直接操控电脑执行实际操作。OpenClaw,业内常称小龙虾 AI&#…

2026/7/21 0:01:46阅读更多 →
Codex 接入后 Bug 反增?复盘从个人演示到团队协作的“流程陷阱”

Codex 接入后 Bug 反增?复盘从个人演示到团队协作的“流程陷阱”

聊《一次Codex项目复盘,问题最后出在流程而不是模型》之前,先说一句实在的:别急着背概念,先看它在真实项目里到底解决什么问题。摘要先把这篇文章的目标说清楚:看完之后,你应该能判断这件事值不值得做&…

2026/7/21 0:01:46阅读更多 →
手把手搓一个五子棋游戏,零代码也能当“游戏开发者”

手把手搓一个五子棋游戏,零代码也能当“游戏开发者”

大家好,还是我。前几期带大家做了心情日记本和可视化大屏,后台有朋友留言:“能不能教点好玩的?我想做游戏,但一行代码都不会。”行,这期就安排。今天的目标:从零做一个五子棋游戏。 带AI对战、三…

2026/7/21 0:03:46阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/20 22:51:39阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/20 18:51:18阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/20 18:51:18阅读更多 →