C语言—顺序表(含通讯录项目)

news2024/9/29 14:11:34

目录

一、顺序表的概念及结构

二、顺序表的分类

(2.1)静态顺序表

(2.2)动态顺序表

三、动态顺序表的实现

(3.1)基本结构定义

(3.2)初始化和销毁

(3.2.1)初始化—SLInit

(3.2.2)销毁—SLDestroy

(3.2.3)打印函数—SLPrint

(3.3)检查扩容

(3.4)头部插入删除\尾部插入删除

(3.4.1)尾部插入

(3.4.2)尾部删除

(3.4.3)头部插入

(3.4.4)头部删除

(3.5)指定位置插入\删除数据

(3.5.1)指定位置插入数据

(3.5.2)指定位置删除数据

(3.6)查找指定数据

四、通讯录项目

(4.1)通讯录功能

(4.2)动态顺序表的改变

(4.2.1)存储数据类型的改变

(4.2.2)打印函数的改变

(4.2.3)查找函数的改变

(4.2.4)添加SLSize函数

(4.2.5)添加SLAt函数

(4.3)通讯录基本结构定义

(4.4)通讯录项目实现的函数

(4.4.1)初始化通讯录

(4.4.2)添加通讯录数据

(4.4.3)删除通讯录数据

(4.4.4)展示通讯录数据

(4.4.5)查找通讯录数据

(4.4.6)修改通讯录数据

(4.4.7)销毁通讯录数据

(4.5)测试


一、顺序表的概念及结构

要想了解顺序表,首先我们要知道线性表,因为顺序表也是线性表的一种。

线性表:线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是⼀种在实际中⼴泛使⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串...,线性表在逻辑上是线性结构,也就说是连续的⼀条直线。但是在物理结构上并不⼀定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

二、顺序表的分类

(2.1)静态顺序表

概念:使用定长数组存储元素。

基本定义格式如下:

静态顺序表缺点:空间给少了不够用,给多了造成空间浪费。

(2.2)动态顺序表

动态顺序表底层仍是数组,但不像静态顺序表那样给出指定大小的数组,而是给一个需要存储的数据类型的指针,使用时通过动态开辟内存,并让指针指向动态开辟的空间,前面文章说过,动态开辟的内存是可以通过realloc函数进行扩容的,这样就达到了按需申请的效果,避免了空间不够用,也一定程度上缓解了空间的浪费。

基本定义格式如下:

注意:顺序表和数组的区别在于顺序表的底层结构是数组,对数组进行封装,实现了常用的增删改查等接口。

三、动态顺序表的实现

(3.1)基本结构定义

这里一共创建了三个文件,SeqList.h是用来放头文件,结构体定义,函数声明的;SeqList.c是用来对声明的函数进行定义的;test.c是对写好的动态顺序表进行测试的。

第一部分是在整个顺序表程序中需要用到的头文件(assert.h是为了使用断言 - assert(),assert函数中可以放表达式,若表达式为假,则终止程序并给出错误提示信息,如果想让程序中的断言失效可以定义宏#define NDEBUG)。

第二部分是为了让程序更具有通用性,如果写死指针 a 指向的数据类型,那么当前顺序表就只能应用于这种数据类型,如果想应用于其他数据类型,只能重新写一个顺序表或者对当前顺序表进行彻底的更改,而对当前需要存储的数据类型进行重命名,后面接口都是使用重命名后的名字,这样应用于其他数据类型是只需要将 2 语句中的 int 改成想存储的数据类型就可以了。

第三部分是对动态顺序表结构的定义,一个指向存储数据空间的指针—a,一个记录数组中的有效元素的个数—size,一个记录整个数组的大小(即最多可以存储多少个数据)—capacity。

(3.2)初始化和销毁

(3.2.1)初始化—SLInit

如上图所示,动态顺序表的底层是动态开辟出来的数组,因为这里我们实现的动态顺序表是在第一个数据插入时才为其中的数组开辟空间,而初始化又是对刚创建好的顺序表中的数据进行一个使用前的设置,所以在初始化函数中我们可以先将指针置空,size和capacity置0。

函数使用场景:

在创建好动态顺序表后直接进行初始化。(前面将struct SeqList重命名为了SL)

测试:

(3.2.2)销毁—SLDestroy

使用完动态顺序表后我们需要主动对动态顺序表进行销毁,因为动态顺序表中数组空间是利用动态开辟内存函数在堆上开辟的,系统并不会主动释放,如果我们也不释放,就会造成内存泄漏,所以这里我们在销毁函数中主动通过free函数释放指针指向的空间,并将指针置空,size和capacity置回0。

使用场景:

测试:

(3.2.3)打印函数—SLPrint

因为我们测试时经常需要打印动态顺序表中的数据,所以这里我们直接写一个打印函数方便后续的测试。因为我们前面写的SLDataType代表的是int类型的数据,所以这里的打印函数也是针对int类型的,如果想存储其他类型的数据并使用打印函数进行测试,可以将 printf () 中的%d进行更换。

这里size是动态顺序表中有效元素的个数,而动态顺序表底层是数组,下标是从0开始的,所以最后一个元素下标是size-1,所以循环条件如图中所示。

(3.3)检查扩容

在前面的初始化函数中,我们并没有为数组开辟空间,而是将指向数组的指针置空了,所以后续插入第一个数据时我们一定需要为数组开辟空间,而且如果数据量较大,已经开辟的空间存满了,我们还需要对原空间进行扩容。这里我们通过扩容函数解决这两个问题。

具体实现:

size代表动态顺序表的有效元素个数,capacity代表动态顺序表的总容量,当它们相等时,代表动态顺序表存满了,最开始size = capacity = 0,所以插入第一个数据时也会判断需要扩容,当判断需要扩容后,定义一个newcapacity表示扩容后的容量大小,通过一个三目运算符,如果capacity为0则给4,否则扩容到原空间的二倍(注意:capacity不是数组占多少个字节,而是数组最多能存储的当前类型的数据的个数)。然后通过realloc函数对空间进行扩容,这里扩容可能失败,如果用ps中的a指针接收,一旦扩容失败,函数返回空指针,那么连原来的空间也找不到了,所以先定义一个临时的指针,当判断指针不为空(即空间扩容成功)后,在将该地址赋回给管理动态顺序表中数组的指针(即ps中的a),同时更新动态顺序表容量。

(3.4)头部插入删除\尾部插入删除

(3.4.1)尾部插入

要往动态顺序表中插入数据,动态顺序表肯定要存在,所以先断言一下ps不可以为空(这里不一定非要用断言,用 if 语句判断也可以),然后检查一下动态顺序表是否需要扩容,最后将数据插入尾部即可,同时有效数据个数加1(注意:size是有效数据个数,所以原有数据的下标是从0到size - 1,所以数据插在尾部就是插在下标为size处)。具体过程可参考下图:

测试:

(3.4.2)尾部删除

只有顺序表存在且不为空的情况下才能进行删除,所以这里先对ps不为空和顺序表中的数据个数size不为0进行断言,然后直接将动态顺序表中的有效数据个数size减1就可以了,没有必要对删除的数据赋特殊值。具体过程可参考下图:

测试:

(3.4.3)头部插入

前面还是一样,断言指向动态顺序表的指针不为空,检查是否扩容,但是接下来如果直接将数据插入头部位置,那么原来的头部位置的数据将被覆盖,所以我们需要移动数据,将数组的起始位置空出来,然后在将数据插入,有效数据个数size加1。具体过程可参考下图:

测试:

(3.4.4)头部删除

只有顺序表存在且不为空的情况下才能进行删除,所以先断言ps指针不为空,size不为0,如果像尾删那样直接进行size-1,删除的是最后一个数据,所以要先进行数据移动,将头部后面的数据都向前移动一个位置,在进行size-1。具体过程可参考下图:

测试:

(3.5)指定位置插入\删除数据

(3.5.1)指定位置插入数据

插入数据首先动态顺序表要存在,其次插入的位置(这里的位置指的是数组下标)要合法,不能为负数,同时最远只能插入到数组最后一个有效数据的后面,所以pos还要小于等于size。这里还是用两个断言来控制这两个问题,然后检查是否需要扩容,在将pos位置及之后的数据向后移动一个位置,将pos位置空出来,最后将数据插入pos位置,并将有效数据个数size加1。具体过程可参考下图:

测试:

(3.5.2)指定位置删除数据

只有顺序表存在且不为空的情况下才能进行删除,并且指定删除的位置要合理,只能在有数据的位置进行删除,这里通过三个断言来控制上述条件,然后把要删除位置后面的数据向前移动一个位置,并将有效数据个数减1。具体过程可参考下图:

测试:

(3.6)查找指定数据

具体实现:

查找数据动态顺序表必须存在,但数据不一定在顺序表中,所以这里只需要断言一下ps不为空就可以,然后就是遍历当前顺序表中的数据,如果找到就返回下标,如果遍历已经结束还没有返回说明顺序表中没有该数据,那么返回-1。

测试:

四、通讯录项目

(4.1)通讯录功能

1)至少能够存储100个⼈的通讯信息
2)能够保存用户信息:名字、性别、年龄、电话、地址等
3)增加联系⼈信息
4)删除指定联系⼈
5)查找制定联系⼈
6)修改指定联系⼈
7)显⽰联系⼈信息

(4.2)动态顺序表的改变

因为通讯录项目存储的是联系人信息,而联系人信息需要用到结构体,所以要想复用前面写好的动态顺序表需要进行一定的改动。

(4.2.1)存储数据类型的改变

这里将SLDataType代表的数据从 int 改为存储联系人信息的结构体PersonInfo。

(4.2.2)打印函数的改变

因为动态顺序表存的是结构体,所以不能直接对顺序表中的数据进行打印,需要像图中一样,先通过数组下标访问到结构体,在访问结构体里的数据。

(4.2.3)查找函数的改变

同理,因为顺序表存储的是结构体,所以比较是否为相同元素时需要比较结构体里的每一个数据,这里存储联系人数据的结构体中的name,sex,tel,adder都是char类型数据的数组,比较是否相同需要用到strcmp函数,age是int类型的,直接比较就可以。

(4.2.4)添加SLSize函数

通过上述函数返回动态顺序表中有效数据个数。

(4.2.5)添加SLAt函数

该函数是用来修改指定位置的值的。在修改值之前要先断言一下顺序表不为空,并且修改位置合法。然后直接将数据放入该位置即可。

(4.3)通讯录基本结构定义

将前面定义好的动态顺序表重命名为contact,定义一个存储联系人信息的结构体,里面包含姓名—name,性别—sex,年龄—age,电话—tel,地址—addr,除了年龄是int类型其余都是char类型的数组,在前面通过宏定义出这些数组的大小。

(4.4)通讯录项目实现的函数

(4.4.1)初始化通讯录

初始化分为两个部分,第一部分是初始化动态顺序表,前面已经讲过了,第二部分是将文件中的数据导入动态顺序表中,如下图:

首先打开存储联系人信息的文件(这个文件需要我们自己创建好),当打开成功后,先创建一个用来存储联系人信息的临时变量,通过fread函数将读到的信息放到临时变量里,再将临时变量的信息放到动态顺序表中,再去读取下一个人的信息,重复上述操作,直到所有联系人信息都被放到动态顺序表中。

(4.4.2)添加通讯录数据

先创建一个临时变量存储要添加的联系人信息,然后通过打印提示信息让用户输入,并将读取到的用户输入放到临时变量中,当所有信息都录入完毕后将信息尾插到动态顺序表中,并提示用户插入成功。

(4.4.3)删除通讯录数据

删除通讯录数据主要通过联系人姓名,当用户输入要删除的联系人姓名后,通过FindByName方法找到要删除的联系人在动态顺序表中存储的位置(即在数组中的下标),如果用户存在,调用顺序表的删除方法将其删除。

FindByName:

在该函数中,我们需要遍历动态顺序表并比较联系人姓名,strcmp函数比较如果相等会返回0,找到后返回下标,否则返回-1。

(4.4.4)展示通讯录数据

该函数只需要遍历打印就可以了,在打印联系人数据前先打印提示信息,使用户知道展示的都是哪些信息。效果如图:

(4.4.5)查找通讯录数据

查找也是通过联系人姓名,当用户输入联系人姓名后通过复用FindByName函数进行查找,如果找到通过返回的下标打印其所有信息。效果如图:

(4.4.6)修改通讯录数据

修改也是通过联系人姓名,用户输入要修改的联系人姓名,复用FindByName函数进行查找,如果要修改的联系人是存在的,打印提示信息并让用户输入直接覆盖原内容。

(4.4.7)销毁通讯录数据

销毁分为两部分,先将动态顺序表中的联系人信息放入文件中,再销毁动态顺序表。SaveContact函数具体实现如下图:

(4.5)测试

测试中写了一个菜单函数,菜单的打印,通讯录的创建,初始化,以及各个接口的调用都在这个函数中完成,这里选择使用do—while循环,因为不管用户想进行何种操作,菜单一定会先打印一次,然后用户选择操作,定义一个变量op接受用户要进行的操作,通过switch—case跳转到相应的接口,输入不合法时会提醒重新输入。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2176956.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【MWORKS专业工具箱系列教程】控制系列工具箱第四期:时域分析

本工具箱教程以控制系统模型创建、分析与设计流程为主线,通过大量示例介绍MWORKS控制系统工具箱的功能和具体使用。共计10篇文章,上一篇主要介绍了控制系统连接与化简。 同元软控:【MWORKS专业工具箱系列教程】控制系 列工具箱第三期&#x…

Shopline对接需要注意的问题

Shopline对接是一项复杂而细致的工作,为了确保对接的顺利进行,并保证系统的稳定性和可靠性,需要注意以下几个方面。 1.API文档的详细阅读 功能理解: 仔细阅读Shopline提供的API文档,全面了解每个接口的功能、参数、返…

一起发现CMake太美-01-CMake是什么CMake的前世今生

本系列课程的主要内容包括: 点击本课程的 链接 可以进入视频课程的学习。 下面介绍本系列课程的第一课的主要内容,本节课从CMake是什么,能做什么,以及CMake的远亲近邻入手,让大家对CMake有一个大致的了解。 随后&am…

SpringBoot+MyBatisPlus实现多数据源动态切换

场景: 假设有一个项目,产品数据存放在new数据库中,公告信息存放在mini数据库中,我们要怎么去查询两个数据库中不同的数据呢? 这个时候我们就要用到mybatisplus提供的多数据源,仅需要如下配置即可实现相关…

【C语言从不挂科到高绩点】24-C语言中的枚举【重点知识】

Hello!彦祖们,俺又回来了!!!,继续给大家分享 《C语言从不挂科到高绩点》课程!! 本节将为大家讲解C语言中非常重要的知识点-枚举: 本套课程将会从0基础讲解C语言核心技术,适合人群: 大学中开设了C语言课程的同学想要专升本或者考研的同学想要考计算机等级证书的同学想…

Anzo Capital昂首资本官网:掌握止损单的艺术,优化交易策略

通过在Anzo Capital昂首资本官网的深入研究,投资者发现宝贵的交易策略,尤其是在市场不活跃的时期,止损单的触发时机往往相当微妙。很多时候,主力的动作似乎开始得更晚,这种情况在交易市场中并不罕见。尽管没有人能够确…

【数据库文档】数据库设计说明书(Word原件参考)

一、 总述 (一) 编写目的 二、 外部设计 (一) 环境说明 (二) 指导 三、 物理实现 (一) 物理结构 (二) 安全设计 四、 表设计结构 (一)…

AutoGen实现多代理—AI Agentic Design Patterns with AutoGen(二)

1. AutoGen顺序对话在客户入职案例上的应用 如图,客户入职前会经历三个阶段,一个代理收集客户的信息,一个代理收集客户的感兴趣话题,一个代理根据前两个代理的基础信息与客户代理对话,产生聊天信息。 本节实验的地址&…

基于SSM+小程序的会议发布与预约管理系统(会议1)(源码+sql脚本+视频导入教程+文档)

👉文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 本基于微信小程序的会议发布与预约系统管理员功能有个人中心,发布者管理,用户管理,发布会议管理,会议预约管理,留言板管理&…

C++远端开发环境手动编译安装(centos7)

背景 直接使用yum安装,无法安装指定的版本,因为很多版本并没有在镜像仓库中,所以此处进行手动安装指定版本 使用VMWare安装centos7 准备centos镜像 可以自行搜索下载地址,阿里云的也可以 下载VmWare,社区版即可 可…

【第十四周】PyTorch深度学习实践1

目录 摘要Abstract1.反向传播2.线性回归2.1.准备数据集2.2.设计模型2.3.定义损失函数和优化器2.4.模型训练 3.逻辑回归4.处理多维特征的输入5.加载数据集5.1.导入必要的库5.2.准备数据集5.3.定义模型5.4.构建损失函数和优化器5.5.训练模型 总结 摘要 本周主要通过B站刘二大人的…

酒店新科技,飞睿智能毫米波雷达人体存在感应器,智能照明创新节能新风尚

在这个日新月异的时代,科技正以未有的速度改变着我们的生活。从智能手机到智能家居,每一个细微之处都渗透着科技的魅力。而今,这股科技浪潮已经席卷到了酒店行业,为传统的住宿体验带来了翻天覆地的变化。其中,引人注目…

基于SpringBoot+Vue的茶园茶农文化交流平台

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏:Java精选实战项目…

对已经运行的flask服务测试代码覆盖率

上一篇文章《用pytest-cov获取flask项目的测试代码覆盖率》展示了用pytest的测试用例验证flask的函数,获取代码覆盖率信息。但是上述方法要求web服务没有提前启动,而是由pytest来启动,然后运行测试用例。 那么对于已经启动的web服务&#xff…

【STM32-HAL库】MQ2烟雾传感器使用(STM32F407ZET6)

MQ2可燃气体传感器介绍 MQ2是一种广谱气体传感器,能够检测多种可燃气体和烟雾。它是一种低成本、高灵敏度的传感器,广泛应用于家庭和工业环境中的气体监测。 原理 MQ2传感器的工作原理基于金属氧化物半导体(MOX)技术。当传感器暴露…

俄罗斯市场合格评定准入认证要求

前言 国内厂家想要把自己的产品顺利出口到俄罗斯市场,就需要基本了解俄罗斯的市场合格评定准入要求。俄罗斯主要实行的认证有EAC(TR-CU/CU-TR)认证、GOST R认证、计量认证和医疗产品国家注册。下面就分别简单介绍一下这几个产品认证。 一、EAC(TR-CU/CU-TR)认证介绍…

LVGL 笔记

在显示GUI的过程中需要对某些对象进行临时隐藏或临时显示,因此需要对该对象的FLAG进行配置就可以实现对象的显示和隐藏了. lv_obj_add_flag(user_obj, LV_OBJ_FLAG_HIDDEN);//隐藏对象 lv_obj_clear_flag(user_obj, LV_OBJ_FLAG_HIDDEN);//取消隐藏 GUI-Guider 中的选项卡 注意…

Linux驱动开发(速记版)--驱动基础

第一章 初识内核源码 Linux系统源码提供了操作系统的核心功能,如进程管理、内存管理、文件系统等。 BusyBox这类的文件系统构建工具,则提供了在这些核心功能之上运行的一系列实用工具和命令,使得用户能够执行常见的文件操作、文本处理、网络配…

MaxKB知识库问答系统入选Gitee最有价值开源项目

2024年9月19日,飞致云旗下开源项目MaxKB成功加入Gitee平台主导的GVP计划,入选2024年GVP——Gitee最有价值开源项目。MaxKB也是继MeterSphere、DataEase和1Panel之后,飞致云旗下第四个入选GVP的开源项目。 ▲图1 MaxKB入选2024年Gitee最有价值…

软机器人咋模仿生物?响应式水凝胶Aquabots有啥用?快来了解一下!

大家好,今天我们要来了解一项关于响应式水凝胶Aquabots的研究——《Responsive‐Hydrogel Aquabots》发表于《Advanced Science》。在当今科技发展中,制造能像生物体一样具有响应适应性的软机器人是个挑战。而Aquabots为解决这个问题带来了新的突破。它通…