1、顺序表的定义
使用结构体来构造顺序表的结构。
typedef struct SeqList
{
SLDataType* arr;//顺序表的数据元素存储空间
int size;//顺序表的当前数据个数
int capacity;//顺序表的最大容量
}SL;
2、顺序表初始化
使用动态分配构造一个空的顺序表,即顺序表最开始的模样。
void SLInit(SL* p)//初始化
{
p->arr = (SLDataType*)malloc(sizeof(SLDataType) * Init_CAPACITY);//动态开辟一块空间给arr
if (p == NULL)
{
perror("malloc fail");
return;
}
p->size = 0;
p->capacity = Init_CAPACITY;
}
3、顺序表的扩容
当我们的顺序表容量不够用时,这时我们需要扩容,扩容可以使顺序表变得更灵活。
void SLCheckCapacity(SL* p)
{
assert(p);//assert是断言操作,我们要确保指针p不为NULL。如p==NULL,assert就会将其报错,并且不在往后操作。
if (p->capacity == p->size )//扩容条件:数据元素个数==最大容量
{
SLDataType* tmp = (SLDataType*)realloc(p->arr, sizeof(SLDataType) * p->capacity * 2);//再次动态开辟新的空间
//realloc(需改变内存大小的指针名,新大小)
if (tmp == NULL)
{
perror("realloc fail");
return;
}
p->capacity *= 2;//容量2倍增长
p->arr = tmp;
}
}
4、顺序表的插入
4.1、头插
注意点:
1、确保指针不为NULL。
2、插入前检查容量是否满了,即还有没有位置插入数据。
3、插入前,我们需要先对原有的数据进行往后移。
4、插入完成后,数据元素个数增加了,所以需要对 size+1。
void SLPushFront(SL* p,SLDataType x)
{
assert(p);//断言p是否为NULL
SLCheckCapacity(p);//插入数据前检查容量是否满了
int end = p->size - 1;
while (end >= 0)
{
p->arr[end + 1] = p->arr[end];//把数据往后移。
end--;
}
p->arr[0] = x;
p->size++;
}
4.2、尾插
相较于头插,尾插就比较简单了。
注意点:
1、确保指针不为NULL。
2、插入数据前检查容量是否满了。
void SLPushBack(SL* p,SLDataType x)
{
assert(p);
SLCheckCapacity(p);
p->arr[p->size++] = x;//这里是后置++,
//相当于先p->arr[p->size]=x
//再p->size++
}
4.3、按位插入
注意点:
1、确保指针不为NULL,确保pos(下标)不能小于0和超过顺序表。
2、插入前检查容量是否满了。
3、插入前要把pos及后面的位置后移。
void SLInsert(SL* p,SLDataType pos,SLDataType x)//在pos位置插入数据
{
assert(p);
assert(pos >= 0 && pos <= p->size);//注意pos不能超过表长和小于0
//这里可以pos = p->size是我们接下来会扩容检查,所以不怕越界行为。
SLCheckCapacity(p);
for (int i = p->size-1; i >= pos; i--)
{
p->arr[i + 1] = p->arr[i];//pos及后面的数据后移
}
p->arr[pos] = x;
p->size++;
}
5、顺序表的删除
5.1、头删
注意点:
1、确保指针不为NULL。
2、删除前要确保还有数据可以删,如果没有数据了,就不能在删。
3、不需要先把数据置成什么,可以直接把后面的数据往前移即可,即从后往前覆盖,这样就可以实现删除操作。
void SLPopFront(SL* p)//头删
{
assert(p);
assert(p->size > 0);