顺序表的简单介绍

news2024/11/27 16:34:42

目录

前提须知:

数据结构:

什么是数据结构?

数据结构特点:

 为什么需要数据结构:

顺序表:

线性表:

与数组区别:

静态顺序表与动态顺序表:

二者之间的区别:

编译器的实现:(以下使用头文件和源文件的书写方式)

初始化:

头文件:

源文件:

 销毁开辟空间:

头文件:

源文件: 

尾插:(在上述代码的基础上进行尾插操作)

尾插要考虑的因素:

头文件:

回答问题:

 1)空间是否足够:

2)空间足够如何进行尾插:

如何扩容?

怎么扩容?

那如何申请空间呢?

注意事项:

头插:(在上诉代码的基础上进行尾插操作)

 头插的所需要进行思考的问题:

头文件: 

回答问题:

 怎么将原先的数据往后移,腾出第一个空间的位置:

尾删:(在上诉的基础上进行尾删操作)

头文件:

需要注意的问题:

头删:(在上诉代码的基础上进行头删)

 头文件:


前提须知:

数据结构:

什么是数据结构?

答:数据结构是计算机存储、组织数据的⽅式,举例:数组是最简单的一种数据结构。

数据结构特点:
  •  能够存储数据(如顺序表、链表等结构)
  • 存储的数据能够⽅便查找 
 为什么需要数据结构:
  • 最基础的数据结构能够提供的操作已经不能完全满⾜复杂算法实现。
  • 假设数据量⾮常庞⼤,频繁的获取数组有效数据个数会影响程序执⾏效率。
  • 数据的多样性,以数组为例,数组只能满足同一种类型的数据,不能满足其他类型的数据。

顺序表:

 在顺序表之前,我们要先明白什么是线性表。

线性表:

  • 线性表是一种总称, 指的是具有相同特性的一类数据结构的统称。

线性表特点:

  • 线性表在逻辑上是线性结构,也就说是连续的一条直线。
  • 但是在物理结构上并不一定是连续的线性表在物理上存储时,通常以数组和链式结构的形式存储。
  • 逻辑结构:人为想象的。
  • 物理结构:内存存储上,不一定是连续的,连续的举例是数组,数组地址是连续的。

而顺序表是线性表的一种,相当于苹果是水果的一种,且因为顺序表的底层结构是数组,所以顺序表在逻辑结构上是线性的,在物理结构上也是线性的。

与数组区别:

 先前讲诉过,数组是同种类型数据的集合。

而且数组分为两种,定长数组和动态数组,定长数组是一开始就设定了数组大小,动态数组是数组的大小不确定,详情看柔性数组。

柔性数组_明 日 香的博客-CSDN博客

 而顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口,这是顺序表与数组的区别。

同时也可以通过数组的分类将顺序表分为两种,静态顺序表和动态顺序表。

静态顺序表与动态顺序表:

静态顺序表和动态顺序表的声明结构,其实顺序表的声明结构就是一种结构体。

结构体的简单介绍(1)_明 日 香的博客-CSDN博客

//静态顺序表
 struct SeqList
{
   int a[100];//定长数组
   int size; //有效个数
   
}
  •  int a[100]表示这个顺序表的大小是100个int类型的字节数大小,也可以说是400个字节大小。
  • 而int size 表明了该顺序表中放入了多少有效的数据。
  • struct是结构体的关键字,表明了顺序表的声明结构其实就是结构体。
//动态顺序表
 struct SeqList
{
   int* a;
   int size;//有效数据的个数
   int capacity;//空间大小
}
  • int*a 指向的是一个数组空间的首个元素地址,间接表明了顺序表的底层结构是数组。
  • int capacity 指向的是开辟空间的大小,也就是顺序表空间的大小,因为是动态的,所以需要开辟空间。
  • 在使用的过程中,可以将a直接当成数组名使用,这是允许的。

二者之间的区别:

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

编译器的实现:(以下使用头文件和源文件的书写方式)

注意:顺序表是一种声明,所以应该在头文件中输写。 

 

以动态顺序表为例子。

在图中,typedef 将int 类型 和 顺序表 进行了重新命名。

int 类型 定义命名的意义是为了方便以后进行类型的更改,这是顺序表和数组的区别之一。

而顺序表 struct SeqList重命名为SL 为了以后方便书写。


 

初始化:

创建一个void 类型的函数SLInit 该函数的参数是SL*类型的,形参是ps

头文件:

 

源文件:

结构体的赋值,详情:结构体的简单介绍(1)_明 日 香的博客-CSDN博客 

将顺序表的空间大小和有效数字初始化为0,将顺序表的指针指向NULL 

因为局部变量的关系,以及传值调用中,形参的改变不会影响实参的因素,所以我们这里使用传址调用。

C语言 实参与形参 传值调用与传址调用-CSDN博客


 

 销毁开辟空间:

销毁开辟的空间,在销毁之前我们必须判断这个空间是否存在,或者说是否开辟,如果存在,则需要使用free释放空间,free的本质是将开辟的空间交还给内存。

free详情:malloc与free_明 日 香的博客-CSDN博客

头文件:

源文件: 


 

尾插:(在上述代码的基础上进行尾插操作)

在尾部插入数据。

如图所示,在下标为6的位置上插入数据,这种就是尾插。

尾插要考虑的因素:
  1. 空间是否足够的问题?
  2. 足够应该如何进行尾插?
  3. 如若空间不够应该如何扩容的问题?
  4. 扩容时需要注意什么?
  5. 需要扩容多少空间合适?
头文件:

回答问题:
 1)空间是否足够:

在动态顺序表中,capacity是表示顺序表的空间的大小,size是表示顺序表中的有效数据的个数,所以当capacity==size的时候,就可以说明顺序表的空间是否满了。

  • 顺带一提,capacity表示的是空间大小,而size表示的是有效数据的个数,所以当二者相同时,二者均可以代表顺序表这个数组的数组大小,而不相同时,反倒是size可以代表顺序表这个数组的数组大小,而顺序表这个数组的最大下标则就是size-1 

使用if进行判断二者是否相等,如若相等,准备进行空间的扩容,若不相等则直接进行尾插。 

2)空间足够如何进行尾插:

 因为空间足够使用,所以在顺序表这个数组中插入数据即可。

且,因为size无论在何时都表明了数组的大小,而size-1表明了当前顺序表这个数组的最大下标,所以在顺序表这个数组中,若要插入数据,直接在size这个位置中插入数据即可。 

当然,在最后别忘了将 有效数据个数+1,这是为了进行多次的尾插所必要的代码,且直接插入是基于capacity 够的情况下,所以capacity不需要进行改动。

如何扩容?怎么扩容?需要扩大多少空间合适?

如何扩容?
  • 使用realloc函数进行扩容,realloc函数详情:realloc-CSDN博客 
怎么扩容?
  • 每次插入一个数据就申请一个空间?插入100个数据申请一百个空间?
  • 但是如果频繁的扩容,会降低程序的性能。
那如何申请空间呢?
  • 答:一般以2倍或者1.5倍进行扩容,比如一开始申请4个空间,当插入第五个数据的时候,扩容成八个空间,插入第九个数据的时候,扩容成16个空间,以此类推··················

图中的代码类比,realloc函数的调整空间大小,基于realloc函数的特性,如若调整空间大小失败,那么这个空间则会丢失,所以直接赋予ps->a有可能造成原空间地址失效,所以需要使用tmp进行中间赋值,然后判断,判断成功后在赋予ps->a


扩容:

  • ps->a表示需要扩容空间的起始地址
  • ps->capacity*2*sizeof(SLDataType),前者表示当前的空间大小,sizeof表示计算当前顺序表的字节大小,*2表示我们的扩容方法。
  • (需要注意的是,空间大小是有类型的,所以空间大小不能代表字节数的多少) 

注意:

当扩容成功后,记得地址的转移以及当前空间需要扩大到原来的两倍,以便下次扩容的时候不会出错。 

注意事项:

 有些人会将capacity 初始化为0,导致后面的代码出错,所以这里新建立一个代码进行判断。

 

 这是一个三目表达式,使用该表达式进行判断空间大小是否为0,如果是0则赋予初值4,如果不是0则将空间进行扩容。

也因此,其余部分也需要进行整改。

完整的代码是:当空间不够后进行扩容,扩容后空间足够,进行尾插操作 


 

头插:(在上诉代码的基础上进行尾插操作)

头插,在头部插入数据,但是放在数组中,就相当于将原先的首元素变为第二个元素,原先的第二个元素变成第三个元素······在不覆盖其他元素的基础上腾出第一个空间的位置。

 头插的所需要进行思考的问题:
  1. 空间不够(已解决)
  2. 怎么将原先的数据往后移,腾出第一个空间的位置。
头文件: 

回答问题:
 怎么将原先的数据往后移,腾出第一个空间的位置:

  • 因为size-1对应的是顺序表这个数组的最大下标,所以将这个最大下标所对应的数据往后移一个位置,也就是size表示的这个数字下,并且进行持续性的进行下标-1的循环,进行不断的挪到。
  • 挪动到最后下标为0后停止,并且对下标为0的位置空间进行数据的插入。
  • 最后别忘记有效数字的+1

 

尾删:(在上诉的基础上进行尾删操作)

头文件:

 因为尾删不用管空间是否足够,所以我们需要删除最后一个数据就行了。

也因为不用管空间大小,所以直接进行有效数据的个数-1使得最后尾部的数据失效即可。

需要注意的问题:

 注意在尾删的同时要注意顺序表是否为空,我们需要进行判断,判断是否为空要判断p->size==0是否成立,成立就为空的。

在这里我们使用断言进行判断预警 


头删:(在上诉代码的基础上进行头删)

 头文件:


 

 总结:

  • 顺序表的声明结构其实是一种结构体
  • 顺序表的底层结构是数组,所以更多的时候我们可以将顺序表当作数组来进行使用

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

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

相关文章

应用安全系列之四十:登录常见问题以及预防方法

对于所有系统而言,登录是一个必备的而且最重要的功能。随着系统越来越复杂,服务越来越多,为了方便用户使用系统的服务,SSO应运而生,SSO虽然方便了用户使用系统,也增加了风险。因为一旦登录出现问题,就很容易通过登录访问整个系统。可见,对于登录如果没有控制好,攻击者…

HALCON的基础运用案例:- 例1- 3D点云的分割

前言: 在这个例子里面展示了用HALCON的操作函数segment_object_model_3d,来把一个输入的2.5D的3D图像进行分割。这里因为图像是一组圆柱体,有运用了一个物体的判别操作函数:dev_display_fitting_results。然后,自动给…

Python 代码调试

from pdb import set_trace as stx 是一个Python代码中常用的调试技巧之一,它用于在代码中插入断点以进行调试。这行代码的作用是将Python标准库中的 pdb(Python Debugger)模块中的 set_trace 函数导入,并将其重命名为 stx&#x…

ArcMap:第二届全国大学生GIS技能大赛(广西师范学院)详解-上午题

目录 01 题目 1.1 第一小题 1.2 第二小题 1.3 第三小题 1.4 数据展示 02 思路和实操 2.1 第一问思路 2.2 第一问操作过程 2.2.1 地理配准 2.2.2 镶嵌 2.2.2.1 第一种镶嵌方法 2.2.2.2 第二种镶嵌方法 2.2.3 裁剪 2.2.4 DEM信息提取 2.2.5 分类 2.3 第二问思路 …

DependsOn注解失效问题排查

文章目录 前言一、现象描述1.1.背景描述1.2.第一次修改,使用DependsOn注解1.3.第二次修改,设置方法入参 二、看看源码2.1.Spring实例化的源码2.2.调试2.3.验证 总结 前言 最近几天遇到一个比较有意思的问题,发现Spring的DependsOn注解失效&a…

强化学习框环境 - robogym - 学习 - 4

强化学习环境 - robogym - 学习 - 4 文章目录 强化学习环境 - robogym - 学习 - 4项目地址为什么选择 robogym如何消去目标位置的阴影?如何让物体颜色变得正确? 项目地址 https://github.com/openai/robogym 为什么选择 robogym 自己的项目需要做一些机…

小白自学笔记—网络安全(黑客笔记)

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高; 二、则是发展相对成熟入…

29 WEB漏洞-CSRF及SSRF漏洞案例讲解

目录 CSRF漏洞解释,原理等CSRF漏洞检测,案例,防御等防御方案2、设置随机Token3、检验referer来源 SSRF漏洞会比csrf漏洞重要一些SSRF_PHP,JAVA漏洞代码协议运用演示案例:SSRF_漏洞代码结合某漏洞利用测试 如何查找ssrf漏洞 SSRF漏…

测量温度的优选模块:新型设备M-THERMO3 16

| 具有16个自由选择通道的新型温度测量设备M-THERMO3 16 IPETRONIK推出的温度测量设备——M-THERMO3 16作为新一代设备的首个模块,它为模块化测量技术确立了标准。该模块具有16个通道,各通道不仅分辨率高达24位ADC,而且能够自由选择热电偶类…

2023Q3数据安全政策、法规、标准及报告汇总(附下载)

数据安全处罚事件逐年升高,2023年呈爆发式增长。 截至2023年8月31日,南都大数据研究院通过各地行政执法公示平台、媒体报道等公开渠道收集到146起依据《数据安全法》作出行政处罚决定的案例。2021年公示5起,2022年公示11起,2023年…

如何通过设备维护管理系统实现全员生产维护TPM

前面我们介绍了《什么是全员生产维护TPM?》,接下来我们探讨如何结合PreMaint的设备维护管理系统来实现全员生产维护TPM。 在现代制造业中,设备的可靠性和生产效率对企业的竞争力至关重要。为了实现全员生产维护(Total Productive …

记录vue开发实例

封装的表格组件 <template><div><div style"width: 100%" v-if"showList"><el-table v-loading.lock"loading" :data"dataList":header-cell-style"{background: #F2FCFE,fontSize: 14px,color: #50606D}&…

8.2 JUC - 6.CyclicBarrier

目录 一、是什么&#xff1f;二、使用demo三、注意 一、是什么&#xff1f; CyclicBarrier &#xff1a; 循环栅栏&#xff0c;用来进行线程协作&#xff0c;等待线程满足某个计数。构造时设置计数个数&#xff0c;每个线程执行到某个需要“同步”的时刻调用 await() 方法进行…

【数据结构】栈和队列-- OJ

目录 一 用队列实现栈 二 用栈实现队列 三 设计循环队列 四 有效的括号 一 用队列实现栈 225. 用队列实现栈 - 力扣&#xff08;LeetCode&#xff09; typedef int QDataType; typedef struct QueueNode {struct QueueNode* next;QDataType data; }QNode;typedef struct …

数据结构 | (三) Stack

栈 &#xff1a;一种特殊的线性表&#xff0c;其 只允许在固定的一端进行插入和删除元素操作 。 进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO &#xff08; Last In First Out &#xff09;的原则。 压栈&#xff1a;栈…

c#学习系列相关之多线程(三)----invoke和begininvoke

一、invoke和BeginInvoke的作用 invoke和begininvoke方法的初衷是为了解决在某个非某个控件创建的线程中刷新该控件可能会引发异常的问题。说的可能比较拗口&#xff0c;举个例子&#xff1a;主线程中存在一个文本控件&#xff0c;在一个子线程中要改变该文本的值&#xff0c;此…

(四)列表、元组、字典和集合

Python列表&#xff08;list&#xff09;、元组&#xff08;tuple&#xff09;、字典&#xff08;dict&#xff09;和集合&#xff08;set&#xff09;详解 Python 序列&#xff08;Sequence&#xff09;是指按特定顺序依次排列的一组数据&#xff0c;它们可以占用一块连续的内…

【C/C++】关于vector迭代器失效问题

​&#x1f47b;内容专栏&#xff1a; C/C编程 &#x1f428;本文概括&#xff1a; vector迭代器失效问题 &#x1f43c;本文作者&#xff1a; 阿四啊 &#x1f438;发布时间&#xff1a;2023.10.8 迭代器的主要作用就是让算法能够不用关心底层数据结构&#xff0c;其底层实际就…

C++变量默认初始化

初始化不是赋值&#xff0c;初始化是指创建变量时赋予一个初始值&#xff0c;赋值是指将变量的当前值擦除&#xff0c;赋予新值。 如果定义变量时没有初始化&#xff0c;则变量会被系统默认初始化。“默认值”取决于变量的&#xff1a;类型位置 startmindmap * C变量默认初始…

邮件群发工具哪个好

邮件群发是一种通过电子邮件向多个收件人发送邮件的方式。同时&#xff0c;邮件群发也是一种低成本、高回报的营销手段。因此邮件群发被广泛应用于各种营销活动中&#xff0c;例如活动邀请、新品上线、产品促销等等。而群发邮件最有效的方式就是借助邮件群发工具&#xff0c;而…