顺序表的概念和特点
顺序表是一种线性数据结构,它由一组数据元素构成,这些元素具有相同的特性,并按照一定的顺序排列。在顺序表中,数据元素通常存储在连续的内存空间中,这使得通过索引可以直接访问到表中的任意元素。
顺序表的特点如下:
-
连续的存储空间:顺序表中的元素在内存中占据一段连续的空间,这使得访问任何一个元素的时间复杂度都为O(1),即访问速度快。
-
动态性:顺序表可以是静态的,也可以是动态的。静态顺序表一旦初始化后,其空间大小就不能更改;而动态顺序表则可以根据需要动态地调整空间大小,即在空间不足时可以自动扩容,空间过多时可以缩容。
-
随机访问:由于元素存储是连续的,顺序表支持随机访问,即可以直接通过索引来访问元素,这一点与链表不同,链表需要遍历才能访问到指定位置的元素。
-
插入和删除操作:顺序表的插入和删除操作可能需要移动大量的元素,尤其是在插入或删除中间的元素时,时间复杂度为O(N),其中N是表中元素的数量。因此,顺序表在执行插入和删除操作时效率较低,这是它的一个缺点。
-
内存预分配与动态调整:在动态顺序表中,内存可以根据需要预先分配或动态调整。预分配指的是在创建顺序表时指定一个初始大小,后续根据实际情况可能进行扩容;动态调整则是在运行时根据需要增大或减小内存空间。
顺序表的实现
对比静态顺序表,动态顺序表更有优势,同样在项目中,动态顺序表的应用远远大于静态顺序表,下面我们就来实现动态顺序表。
首先创建三个文件:
- SeqList.h —— 用于声明函数的头文件
- SeqList.c —— 顺序表主要函数的实现
- test.c——测试顺序表。
创建顺序表
typedef int SLDataType;//方便后续使用更改类型
typedef struct SeqList
{
SLDataType* arr;//数组指针
int size;//记录当前有效的数组大小
int capacity;//记录当前总空间大小
}SL;
对顺序表初始化
void InitSeqList(SL* ps)//初始化顺序表
{
ps->arr = NULL;
ps->capacity = ps->size = 0;
}
顺序表的销毁
void SLDestroy(SL* ps)//销毁顺序表
{
free(ps->arr);
ps->arr = NULL;
ps->capacity = ps->size = 0;
}
打印顺序表
void SLPrint(const SL* ps)//打印顺序表的数据
{
assert(ps);
assert(ps->size);
for (int i = 0; i < ps->size; i++)
{
printf("%d", ps->arr[i]);
}
}
在给数据表增加数据前,我们先封装一个函数,用来判断顺序表是否已满,如果满则需要开辟新空间。
判断扩容
void SLCheckCapacity(SL* ps)//判断是否需要增容
{
assert(ps);
if (ps->capacity == ps->size)//数组已满
{
int newcapacity = (ps->capacity == 0) ? 4 : 2 * ps->capacity;//如果空间为0则开辟4个空间,否则开辟原空间二倍
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity*sizeof(SLDataType));
if (tmp == NULL)
{
perror("realloc");
exit(1);
}
ps->arr = tmp;
ps->capacity = newcapacity;
}
}