顺序表的简单介绍

目录

前提须知:

数据结构:

什么是数据结构?

数据结构特点:

 为什么需要数据结构:

顺序表:

线性表:

与数组区别:

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

二者之间的区别:

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

初始化:

头文件:

源文件:

主函数部分:

 销毁开辟空间:

头文件:

源文件: 

主函数部分:

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

尾插要考虑的因素:

头文件:

回答问题:

 1)空间是否足够:

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

如何扩容?

怎么扩容?

那如何申请空间呢?

注意事项:

主函数部分:

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

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

头文件: 

回答问题:

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

主函数部分:

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

头文件:

需要注意的问题:

主函数部分:

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

 头文件:

 怎么删呢?

 注意的问题:

源文件:

​编辑 主函数部分:

​编辑

 在任意位置插入数据:

头文件:

 图示:​编辑

 源文件:

插入部分:

完整版:

主函数部分:

​编辑

 删除指定位置的数据:

头文件:

源文件: 

主函数部分:

​编辑

​编辑

 查找指定的数据是否存在:

头文件:

 源文件:

主函数部分:

​编辑

​编辑

使用打印顺序表的函数调用:

头文件:

源文件:

主函数部分:

 总结:


顺序表的简单介绍_第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直接当成数组名使用,这是允许的。

二者之间的区别:

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

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

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

 顺序表的简单介绍_第3张图片

以动态顺序表为例子。

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

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

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


 顺序表的简单介绍_第4张图片

初始化:

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

头文件:

 顺序表的简单介绍_第5张图片

源文件:

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

顺序表的简单介绍_第6张图片

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

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

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

主函数部分:

  顺序表的简单介绍_第7张图片 


 顺序表的简单介绍_第8张图片

 销毁开辟空间:

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

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

头文件:

源文件: 

顺序表的简单介绍_第9张图片

主函数部分:

 顺序表的简单介绍_第10张图片


 顺序表的简单介绍_第11张图片

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

在尾部插入数据。

顺序表的简单介绍_第12张图片

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

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

x表示插入的数据,SL*ps是插入空间的地址 

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

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

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

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

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

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

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

顺序表的简单介绍_第13张图片

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

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

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

顺序表的简单介绍_第14张图片

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


扩容:

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

注意:

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

注意事项:

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

 

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

顺序表的简单介绍_第15张图片

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

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

主函数部分:

 顺序表的简单介绍_第16张图片


 顺序表的简单介绍_第17张图片

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

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

顺序表的简单介绍_第18张图片

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

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

顺序表的简单介绍_第19张图片

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

 顺序表的简单介绍_第20张图片


 顺序表的简单介绍_第21张图片

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

头文件:

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

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

需要注意的问题:

 注意在尾删的同时要注意顺序表是否为空,我们需要进行判断,判断是否为空要判断ps->a==NULL是否成立,成立就为空的地址。

顺序表的简单介绍_第22张图片

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

主函数部分:

 顺序表的简单介绍_第23张图片


顺序表的简单介绍_第24张图片

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

 头文件:

顺序表的简单介绍_第25张图片

 怎么删呢?

因为必须把第一个数据删了,然后之后的数据补上,所以可以直接覆盖,将第一个位置的数据用第二个位置的数据直接覆盖,而后,第二个位置的数据被第三个位置的数据覆盖,第三个位置的数据被第四个位置的数据覆盖,以此类推············

 注意的问题:

在此之前判断数据空间是否为空。

源文件:

顺序表的简单介绍_第26张图片

为何是isize-1呢因为要把p->size-2的数据被p->size-1的数据覆盖,且因为p->size-1的数据因为往前挪,且因为头删,有效数据会减少,所以挪动后,在顺序表这个数组中下标是p->size-1的位置的数据应该是空的,然整体的有效数据个数-1,size-1变成了size 

顺序表的简单介绍_第27张图片 主函数部分:

顺序表的简单介绍_第28张图片


顺序表的简单介绍_第29张图片

 在任意位置插入数据:

头文件:

SL*ps是顺序表这个空间的地址,int pos是顺序表这个数组的下标位置,x是指插入的数据 

 图示:顺序表的简单介绍_第30张图片

顺序表的简单介绍_第31张图片

 以上图举例:要把原来下标1的数据往后移动,这个和头插有些类似,要把下标为1的数据和它之后的数据都往后移动,让出下标1的位址空间。

注意事项:还是得先查看空间是否足够,不够进行空间的扩展,空间扩展参考尾插。

 源文件:

顺序表的简单介绍_第32张图片

插入部分:

完整版:

顺序表的简单介绍_第33张图片

主函数部分:

顺序表的简单介绍_第34张图片


顺序表的简单介绍_第35张图片

 删除指定位置的数据:

头文件:

 删除指定位置的数据,和头删有些类似,直接将指定的位置,被指定位置的后一位进行覆盖,然后后一位被后两位覆盖

 顺序表的简单介绍_第36张图片

 注意事项:需要进行空间是否为空的判断。

源文件: 

顺序表的简单介绍_第37张图片

主函数部分:

顺序表的简单介绍_第38张图片

 查找指定的数据是否存在:

头文件:

 源文件:

顺序表的简单介绍_第39张图片

注意事项:先判断空间是否为空 ,且bool类型是只能返回true和flase的。

主函数部分:
顺序表的简单介绍_第40张图片

顺序表的简单介绍_第41张图片

使用打印顺序表的函数调用:

头文件:

源文件:

顺序表的简单介绍_第42张图片

主函数部分:

 顺序表的简单介绍_第43张图片


顺序表的简单介绍_第44张图片

 总结:

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

顺序表的缺点:

  • 从之前的博客中,我们得知,顺序表的本质实际上是一种数组。
  • 而数组的最大特征就是连续的空间。
  • 也因此,在线性表中,顺序表是一种物理上和逻辑上都连续的直线。

你可能感兴趣的:(数据结构,C语言,数据结构,顺序表)