1.顺序表的概念与结构
在了解顺序表之前,我们先了解一下线性表。
1.1线性表
线性表( linear list )是n个具有相同特性的数据元素的有限序列。简单来说是具有相同特性的数据结构的集合, 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑结构上是 线性结构,也就说是连续的一条直线 。但是在物理结构上并不一定是连续的,线性表在物理上存储时, 通常以数组和链式结构的形式存储 。
肯定又有人有疑问了,什么是物理结构,什么又是逻辑结构?
1.1.1物理结构
物理结构就是数据在内存中存储的结构,比如数组,数组中这一块块空间地址就是物理地址,这种在内存中存储的方式就是物理的。
1.1.2逻辑结构
逻辑结构是我们想象出来的结构,是一种抽象式结构,对与线性表来说,它的逻辑结构我们就把它想象成像直线一样的线性结构,所以线性表的逻辑结构就是线性结构。那线性表的逻辑结构就一定是连续的,我们举个生活中的例子,比如:你排队去商店买书在门口排队
那这支队伍竖着来看是不是就是线性表的线性结构,虽然可能这只队伍在排队时排的没那么齐,但线性结构是想象出来的,我们可以把它抽象成一条直线。
1.2顺序表的特性
我们知道了物理结构与逻辑结构,以及线性表在物理结构不一定连续,在逻辑结构一定连续,那我们重新分析什么是顺序表,那它的特性我们无疑也可以从物理结构与逻辑结构两方面来分析:
首先,顺序表是线性表的一种,那它的逻辑结构一定是连续的。这一点无疑是肯定的,既然你是属于线性表里的一种,那线性表在逻辑结构上规定是连续的,所以顺序表在逻辑结构上也必须连续,关键是在物理结构上,顺序表是不是连续的。
我们知道顺序表底层就是数组,既然数组在物理结构上是连续的,那顺序表在物理结构上就是连续的。
总结来看,顺序表在物理结构上是连续的,在逻辑结构上也是连续的
1.2.1顺序表与数组的区别
有人可能有疑问,既然顺序表的底层是数组,那它和数组有什么区别那?
其实顺序表是对数组的封装,实现了常用的增删改查等接口,赋予了数组很多功能,成为了一个数据结构。
1.3顺序表的分类
1.3.1静态顺序表
注意这里的数组大小是确定的,无法后期修改,但是我们存储信息大小可能会一直增加,那么很显然,静态顺序表不太好,所以有了动态顺序表
1.3.2动态顺序表
2.动态顺序表的实现
首先我们要知道,在打一个项目时,我们要有个头文件和源文件,头文件用来声明顺序表的方法,源文件用来实现顺序表的方法
首先在顺序表.h的文件里,把顺序表这个结构体先定义下来,定义完后,可以用typedef改名,
然后,我们要想这个数组里必须是int型的吗,不一定,那我就用typedef提前把int重类型一下,这样我们就可以不仅仅停留在int,若想改成其他类型,直接在typedef后将int改成你想在顺序表放的类型就可以了
然后我们要想在头文件里声明些什么函数那,根据顺序标的功能,最起码要增删查的功能吧,若空间不够也要有扩容功能的函数吧。也要有初始化函数和用于将动态内存开辟的空间归还给操作系统的销毁空间的函数,那我们可以总结一下
1.初始化函数
2.插入函数
3.扩容函数
分为头插入函数和尾插入函数
4.删除函数
分为头删除和尾删除函数
5.查找函数
6.在指定位置前插入函数
7.在指定位置处删除函数
8.销毁空间函数
9.打印顺序表
所以.h文件里有这些声明
# define INIT_CAPACITY 4
typedef int SLDataType;
// 动态顺序表 -- 按需申请
typedef struct SeqList
{
SLDataType* a;
int size; // 有效数据个数
int capacity; // 空间容量
}SL;
// 初始化和销毁
void SLInit (SL* ps);
void SLDestroy (SL* ps);
void SLPrint (SL* ps);
// 扩容
void SLCheckCapacity (SL* ps);
// 头部插⼊删除 / 尾部插⼊删除
void SLPushBack (SL* ps, SLDataType x);
void SLPopBack (SL* ps);
void SLPushFront (SL* ps, SLDataType x);
void SLPopFront (SL* ps);
// 指定位置之前插⼊ / 删除数据
void SLInsert (SL* ps, int pos, SLDataType x);
void SLErase (SL* ps, int pos);
int SLFind (SL* ps, SLDataType x);
首先是初始化
注意:我们要对结构体进行修改,所以要传址!
申请的动态内存一定要free释放掉,free也只能释放申请动态内存!
打印就很简单了
在插入之前我们要想咱们现在初始化容量数为0,得扩容呀,那我们就扩容。如何来扩容呢?我们一般规定扩容到原空间的两倍,扩容用到的函数是realloc函数,但刚开始是0,我们可以用三目操作符来判断如果空间为0,我们要给它4个空间数,若不是0,直接capacity乘2,接着再使用新的容量数乘每个类型的字节数放到realloc里就是开辟了新的空间
接下来是头插
进行移动有两种方式:一是从前往后,二是从后往前。从前往后的话,如果先是把1后移到2的位置,那么就变成了
2就被覆盖了,所以第一种不行
从后往前就很OK
最后再把第一个位置赋值为要插入的数就OK了
代码就是:
尾插就很简单了
接下来是头删和尾删
先看头删
头删就是把第一个删除然后整体前移
整体前移和整体后移类似,从后往前不行,选择从前往后(大家可以自己画图体会一下)
尾删就很简单了,直接ps->size--;就行了
接下来就是在指定位置插入/删除
首先先找到指定的位置pos,如果是插入的话就是整体后移再插入,删除的话就是该位置之后的整体前移,这不就是头插头删的应用嘛
写好一个功能别忘了检测啊!
3.代码展示
顺序表听着很高大上,其实就是数组,只不过存储不一样了,多加练习其实很简单
今天的分享就到这里了,希望大家都能学有所成!拜拜拉~~~