概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。
顺序表一般分为:
1、静态顺序表:使用定长数组存储元素。
2、动态顺序表:使用动态开辟的数组储存元素。
接口实现
静态顺序表只适用于已知数据个数的场景。静态顺序表使初始空间开辟后就无法更改,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态分配空间大小,所以下面我们实现动态顺序表。
定义动态顺序表
//C语言实现,所用头文件
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//定义顺序表自定义类型
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* data; //储存动态数组首元素地址
int size; //有效数据个数
int capacity; //空间容量
}SL;
顺序表初始化
void SLInit(SL* ps)
{
assert(ps); //断言
ps->data = (SLDataType*)malloc(sizeof(SLDataType) * 4);
if (ps->data == NULL) //申请动态内存都要判断是否申请成功
{
perror("SLInit malloc fail");
return;
}
ps->size = 0;
ps->capacity = 4;
}
顺序表销毁
void SLDestroy(SL* ps)
{
assert(ps);
free(ps->data);
ps->data = NULL;
ps->size = ps->capacity = 0;
}
尾插 – O(N)
void SLPushBcak(SL* ps, SLDataType x)
{
//空间满,则扩容
if (ps->size == ps->capacity)
{
SLDataType* tmp = (SLDataType*)realloc(ps->data, sizeof(SLDataType) * ps->capacity * 2);
if (tmp == NULL)
{
perror("SLPushBack realloc fail");
return;
}
ps->data = tmp;
ps->capacity *= 2;
}
ps->data[ps->size++] = x; //插入数据
}
尾删 – O(N)
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size > 0);
ps->size--; //不考虑缩容,直接减小有效数据个数
}
头插 – O(N^2)
void SLPushFront(SL* ps, SLDataType x)
{
//空间满,则扩容
if (ps->size == ps->capacity)
{
SLDataType* tmp = (SLDataType*)realloc(ps->data, sizeof(SLDataType) * ps->capacity * 2);
if (tmp == NULL)
{
perror("SLPushBack realloc fail");
return;
}
ps->data = tmp;
ps->capacity *= 2;
}
int end = ps->size - 1;
while (end >= 0)
{
ps->data[end + 1] = ps->data[end];
--end;
}
ps->data[0] = x;
ps->size++;
}
头删 – O(N^2)
void SLPopFront(SL* ps)
{
assert(ps);
assert(ps->size > 0);
int begin = 1;
while (begin < ps->size)
{
ps->data[begin - 1] = ps->data[begin];
++begin;
}
ps->size--;
}
查找指定数据
int SLFind(SL* ps, SLDataType x)
{
assert(ps);
for (int i = 0; i < ps->size; ++i)
{
if (ps->data[i] == x)
return i; //找到,返回下标
}
return -1; //未找到
}
指定位置插入
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos <= ps->size);
//空间满,则扩容
if (ps->size == ps->capacity)
{
SLDataType* tmp = (SLDataType*)realloc(ps->data, sizeof(SLDataType) * ps->capacity * 2);
if (tmp == NULL)
{
perror("SLPushBack realloc fail");
return;
}
ps->data = tmp;
ps->capacity *= 2;
}
int end = ps->size - 1;
while (end >= pos)
{
ps->data[end + 1] = ps->data[end];
--end;
}
ps->data[pos] = x;
ps->size++;
}
//复用SLInsert可直接得道头插和尾插
指定位置删除
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
int begin = pos + 1;
while (begin < ps->size)
{
ps->data[begin - 1] = ps->data[begin];
++begin;
}
ps->size--;
}
//复用SLErase可直接得道头删和尾删