顺序表的使用方法
在学习顺序表之前,我们要先了解什么是数据结构:
数据结构是由“数据”和“结构”两词组合而来的。
什么是数据?
常见的数值1、2、3、4…、教务系统里保存的用户信息(姓名、性别、年龄、学历等等)、网页里肉眼可以看到的信息(文字、图片、视频等等),这些都是数据。
什么是结构?
当我们想要使用大量使用同一类型的数据时,通过手动定义大量的独立的变量对于程序来说,可读性非常差,我们可以借助数组这样的数据结构将大量的数据组织在一起,结构也可以理解为组织数据的方式。
概念:数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。数据结构反映数据的内部构成,即数据由那部分构成,以什么方式构成,以及数据元素之间呈现的解构。
总结:
- 能够存储数据(如顺序表、链表等结构)
- 存储的数据能够方便查找
一、顺序表的概述(什么是顺序表)
顺序表的底层结构就是数组,对数组的封装,实现了常用的增删改查等接口,换句话说就是对一个数组可以实现增删查改等操作。顺序表可以分为两类:静态顺序表和动态顺序表。
静态顺序表:
概念:使用定长数组存储元素
静态顺序表的缺陷:空间大小固定,给少了空间不够用,给多了造成空间浪费。
动态顺序表:动态顺序表则与静态顺序表相反,动态顺序表是按需申请空间存储数据,给一个数组存储数据,当给的数组空间不够时即可向堆申请足够大的空间去存储数据,一般在空间不够时申请原空间的2~3倍的空间大小,按需申请即可。
typedef int SLDataType;
//动态顺序表---按需申请空间
typedef struct SeqList
{
SLDataType* arr;
int size;//记录有效数据个数
int capacity;//记录当前空间大小
}SL;
二、顺序表的初始化
顺序表的初始化部分并不难,只是简单地给结构体里的每一个成员都依次进行初始化,代码的实现过程为:先定义一个结构体,然后将结构体的地址传到“顺序表的初始化”对应的函数里再进行初始化操作。
相对应的代码如下所示:
//顺序表的初始化
void SLInit(SL* ps)
{
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
//定义结构体并传参
void SLTest01()
{
SL sl;
SLInit(&sl);
}
像这样,顺序表的初始化通过这么简简单单的几行代码就完成了。
三、顺序表的销毁
由于我们使用的是动态顺序表,而动态顺序表的使用是需要不断地进行动态空间的申请,可能会用到malloc、realloc来申请空间,既然有申请,那么就有释放,如果有空间,那么我们要手动地去释放掉。
相对应的代码如下所示:
void SLDestroy(SL* ps)
{
if (ps->arr != NULL)//如果ps->arr不为NULL,那么就需要释放
{
free(ps->arr);
}
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
void SLTest01()
{
SL sl;
SLDestroy(&sl);
}
四、顺序表的插入
顺序表的插入顾名思义就是将后来需要存储的数据插入到顺序表中,那么如果需要插入数据就需要判断顺序表的空间够不够,如果不够再向堆去申请足够的空间再进行数据的存储。
顺序表的扩容首先需要判断顺序表的空间大小是否足以容纳将要存储的数据,如果空间不足,再向堆申请一定的空间;空间申请完成之后就可以将数据插入扩容后的顺序表中了。
void SLCheckCapacity(SL * ps)//顺序表的扩容
{
if (ps->size == ps->capacity)//判断空间大小是否等于有效数据个数
{
int NewCapacity = ps->capacity = 0 ? 4 : ps->capacity * 2;
SLDataType* temp = (SLDataType*)realloc(ps->arr, NewCapacity * sizeof(SLDataType));
if (temp == NULL)//申请空间失败
{
perror("realloc fail!");
return;//提前返回
}
//申请空间成功
ps->arr = temp;
ps->capacity = NewCapacity;
}
}
4.1顺序表的头插
顺序表的头插即将新的数据从顺序表的头部插入顺序表:
void SLPushFront(SL