Bootstrap

数据结构之顺序表

目录:

一、线性表

二、顺序表

        2.1 C语言实现 静态顺序表

        2.2 C语言实现 动态顺序表

        2.3 顺序表问题与思考


正文开始

一、线性表

线性表是n个具有相同特性的数据元素的有限序列。常⻅的线性表:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,线性意为连续的一条直线。所谓的线性结构是人为想象出来的,例如我们在排队的时候不一定每个人都整整齐齐一个接一个站成一条直线,但就算这个队列歪歪扭扭我们人为的认为它是有先后顺序的一条直线,一个接一个的在排队。

但是在物理结构上,线性表的存储不一定是连续的,通常以数组和链式结构的形式存储。

物理结构指的是内存的存储,每次内存会自己分配空间存储,我们并不知道是否每次开辟的空间刚好都是连续的一块

二、顺序表

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。

                                        

顺序表和数组的区别?

顺序表的底层结构是数组,普通数组就只是存储一组相同类型的数据,顺序表则是对数组进行一系列封装,使其有了增删查改等接口。

例如:

2.1 C语言实现 静态顺序表

使用定长数组存储元素:

静态顺序表的缺陷:N是固定的数值,给少了空间不够用,给多了造成空间浪费。

2.2 C语言实现 动态顺序表

对于静态顺序表空间的缺陷,给出了动态顺序表。使数组的内存大小可以根据需求动态开辟。

代码实现:

首先大家创建三个文件:一个.h头文件和两个.c文件(名字可自己命名)

SL.h:函数声明头文件

SL.c:函数实现文件

test.c:测试文件

正文:

先用结构体创建顺序表的结构类型,拿着类型才能创建顺序表。

顺序表结构包含三个成员:(1)指针数组(用于动态开辟内存);(2)数组有效数据个数size;(3)数组容量大小(后期好判断是否要扩容)。所以我们定义的整个结构体类型如下图:

创建顺序表结构:

(1)顺序表初始化

用顺序表结构创建sl 顺序表,因为初始化会改变顺序表内容所以把sl 地址传过去。函数用指针的形式接收。

初始化顺序表,就是对顺序表三个成员初始化:数组一开始为空,数组容量和有效数据个数一开始为0。

通过调试可以看到sl顺序表确实如我们所愿初始化为空。

(2)尾插

顺序表的底层结构是数组,既然要插入数据就得判断是否有足够空间给我插,空间判断有两种情况:(1)空间足够直接尾插(2)空间不够要增容,增容又要增多大呢?多了就浪费,少了不够用,所以一般按倍数增加,如2倍、3倍......。这里用2倍,既能避免频繁增容,又能最大程度减少空间浪费。

如何判断是否要增容?

当数据个数size等于空间大小capacity则空间满了。

同样要函数声明、函数实现、函数测试

如果空间不够就要realloc动态增容。因为一开始初始化的capacity为0,不管增容多少倍都为0,所以先创建一个变量,用三目操作符判断如果一开始空间为0直接开辟4个字节,若已经有空间就*2按2倍增容。

realloc按比特位开辟,1个字节为8个比特位,所以要newCapacity * sizeof(SLDataType),因为realloc不一定百分百开辟成功所以不能直接将开辟的空间给arr,要先判断是否为空再赋值。因为判空后续会一直用到,所以封装为一个函数方便后续调用

空间足够直接尾插,size的位置就是要插入的位置,插入后记得让size++计算有效个数

(3)头插

头插顺序表不能为空,判断是否有足够的空间插入数据。没有增容,有就用for循环将全部数据向后移动一位,把头部空出来再进行头插。时间复杂度为O(n)

不懂时间复杂度可参考博客C语言数据结构之算法复杂度-CSDN博客

先调用SLcheckCapacity判断空间是否足够,然后将所有数据向后移动一个字节

(3)尾删

尾删数组中得有数据给我删,没有数据无法删除,所以一上来assert断言顺序表不能为空,顺序表内的元素不能为空

不能为空后让size- -则为尾删。因为size为链表有效个数,让有效个数减少等于从顺序表末尾删除数据

(4)头删

头删的原理就是:循环用后一个数据覆盖前一个数据,覆盖掉原数据自然而然为头删形式

删完数组的有效个数记得- -(前置- -和后置- -不影响结果)。时间复杂度为O(n)

(5)查找数据,返回下标

通过for循环遍历整个数组,将每个元素与要查找数据x进行比较,相同返回下标,不同返回无效下标-1。

(6)指定位置之前插入数据

插入数据首先顺序表不能为空,要插入数据的位置pos不能超出有效范围。

涉及到插入得考虑是否有足够的空间

找到插入位置后将插入位置及以后数据循环向后移动一个字节,把pos空出来插入数据

(7)删除指定位置数据

删除数据首先顺序表不能为空,要删除数据的位置pos不能超出有效范围。

找到删除位置,将删除位置以后数据循环向前移动一个字节

(8)销毁顺序表

顺序表底层是数组,销毁顺序表也就是销毁数组,数组一开始是realloc动态增容,用free释放空间再把它置为空,别忘了size和capacity置为0。

2.3 顺序表问题与思考

(1)中间/头部的插入删除时间复杂度为O(n)

(2)增容需要申请新空间,拷贝数据,释放空间会有不小消耗

(3)增容一般呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增加到200,结果再插入5个数据,后面没有数据插入了,那么就浪费了95个数据空间

如何解决以上问题?单链表


;