线性表的概念
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
顺序表的概念
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。![]()
顺序表的分类
顺序表一般可以分为:1. 静态顺序表:使用定长数组存储。2. 动态顺序表:使用动态开辟的数组存储。
顺序表的静态存储
使用定长数组来实现顺序表的静态存储。
缺点就是开辟的空间大小是固定的,所开辟空间无法随着数据量的增加而增加。
// 顺序表的静态存储
#define N 100
typedef int SLDataType;
typedef struct SeqList
{
SLDataType array[N]; // 定长数组
size_t size; // 有效数据的个数
}SeqList;
顺序表的动态存储
使用动态开辟的数组来实现顺序表的动态存储。
能够做到随着数据量的增长,顺序表的所开辟的内存空间也随之增长。
先对顺序表初始化,后向内填充数据,当有效数据个数等于容量时,进行扩容。
typedef struct SeqList
{
SQDataType* a;
int size; // 有效数据的个数
int capacity; // 容量
}SL;
用顺序表实现增删查改的接口 (以动态顺序表为例)
初始化顺序表
开辟一块空间,让顺序表指向这块空间。
void SeqListInit(SL* ps)
{
ps->a = (SQDataType*)malloc(Init_size);
if (ps->a == NULL)
{
perror("SeqlistInit");
return;
}
else
{
ps->size = 0;
ps->capacity = 0;
}
}
检查顺序表是否需要扩容
为了增加程序的可维护性,我们重命名一下
typedef int SQDataType;
先判断需不需要扩容,如果容量和有效数据的数量相同,则需要扩容,使用tmp来接受扩容的空间地址,通过判断tmp是不是空指针来判断是否成功扩容。扩容成功则让a指向该空间,同时将容量修改成扩大的容量大小。
void SeqListCheckCapacity(SL* ps)
{
// 满了就要扩容
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SQDataType* tmp = (SQDataType*)realloc(ps->a, newcapacity * sizeof(SQDataType));
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
else
{
ps->a = tmp;
ps->capacity = newcapacity;
}
}
}
顺序表的随机插入
先断言一下,防止要插入的位置在顺序表之外。end开始存放顺序表末端元素的下标,当end大于等于pos时,我们将end所访问的元素向后移动一位,也就是下标为end+1的位置,实现将pos所访问的元素之后的所有元素后移一位,重复到end小于pos,再将我们需要插入的数存放在下标为pos的空间当中,这样便实现了随机插入,头部插入和尾部插入只是pos所访问的位置不同,本质是随机插入。
void SeqListInsert(SL* ps, int pos, SQDataType x)
{
assert(pos <= ps->size);
SeqListCheckCapacity(ps);
int end = ps->size - 1;
while (end >= pos)
{
ps->a[end + 1] = ps->a[end];
--end;
}
ps->a[pos] = x;
ps->size++;
}
顺序表的随机删除
用start变量来存放要删除的元素的后一位下标,也就是pos+1,删除就是将pos所访问的元素之后的所有元素都前移一位。用start和ps->sz的大小来判断start是否需要继续后移。
头部删除和尾部删除只是pos所访问的元素位置不同,实际上还是随机删除。
void SeqListErase(SL* ps, int pos)
{
assert(pos < ps->size);
int start = pos + 1;
while (start < ps->size)
{
ps->a[start-1] = ps->a[start];
++start;
}
ps->size--;
}
顺序表的销毁
释放动态开辟的空间,将指向该空间的指针置空,清零有效数据大小和顺序表容量。
void SeqListDestory(SL* ps)
{
free(ps->a);
ps->a = NULL;
ps->capacity = 0;
ps->size = 0;
}
总结
介绍了线性表的概念、顺序表的概念、静态顺序表和动态顺序表、动态顺序表实现增删查改、随机插入、随机删除、动态顺序表的初始化、动态顺序表的销毁。