目录
一、顺序表的概念
顺序表是一段物理地址连续的村塾单元依次存储数据元素的线性结构,一般情况下使用数组存储,在数组上完成数据的增删改查。
二、顺序表的分类
1.静态顺序表
使用定长数组存储元素
#define N 7
typedef int SLDataType;
typedef struct SeqList{
SLDataType array[N]; //定长数组
size_t size ; //有效数据的个数
}SeqList;
静态顺序表只适用于确定需要多少数据的情况,N大了空间浪费,N小了不够用,所以一般用动态顺序表,按需分配空间。
2.动态顺序表
使用动态开辟的数组存储
//顺序表的动态存储
typedef struct SeqList
{
SLDataType * array; //指向动态开辟的数组
size_t size; //有效的数据个数
sieze_t capacity; //容量空间的大小
}SeqList;
3.顺序表的增删改查
- 顺序表的初始化
顺序表为一个结构体,里面有3个参数:指向数组的指针,顺序表中的有效数字个数,顺序表的大小,初始化的时候全部置空
//顺序表的初始化
void SLInit(SL * ps)
{
assert(ps);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
- 尾插
首先,在尾部插入数据,先判断顺序表中的大小是否能插入,如果不能,需要扩容,如果可以插入,则要找到尾的位置,然后把数据放入,放入的时候根据size找下标,放入a中。ps->a[ps->size];此时size++
void SLCheckCapacity(SL * ps)
{
assert(ps);
//如果容量满了
if(ps->size == ps->capacity)
{
//如果是第一次开辟空间 给4个字节
// 后面开辟,扩容到二倍
int newCapacity = ps->capacity == 0 ?4: ps->capacity * 2;
//扩容的地址 realloc 形参为第一次开辟的地址和要扩容的大小
//要扩容的单位 字节 字节个数=扩容几个 * 类型
SLDataType * tmp = (SLDataType * ) realloc(ps->a, newCapcity * sizeof(SLDataType));
//如果开失败
if(tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
//开成功 地址给a (realloc可能为原地也可能为异地) 相当于一次原地扩容
ps->a = tmp;
// 容量大小改变
ps->capacity = newCapacity;
}
void SLPushBack(SL * ps,SLDataType x)
{
assert(ps);
//检查容量
SLCheckCapacity(ps);
ps->a[ps->size] = x; //x要放入a数组中,根据现在的数据个数(即数组的最后一个)找下标赋值插入
ps->size++;
}
- 尾删
先判断顺序表是否删空了,如果空了返回。如果不空,a数组中的尾部位置数置0,size--.
void SLPopBack(SL * ps)
{
assert(ps);
assert(ps->size >0);
ps->a[ps->size-1] = 0; //注意下标的位置,size是有效数据个数,size-1是最后一个数的位置
ps->size--;
}
- 头插
插入之前需要先判断能否插入,使用checkCapacity检查,如果可以插入,头插,需要把后面的数字往后挪,往后挪有两种方式:从前往后,从后往前,此时需要从后往前,否则会覆盖掉后一个数字,挪动结束后,第一个位置插入,插入之后size++
//头插
void SLPushFront(SL * ps,SLDataType)
{
assert(ps);
SLCheckCapacity(ps);
//挪动数据
int end = ps->size-1;
while(end>=0)
{
ps->a[end+1]= ps->a[end];
end--;
}
ps->a[0] = x;
ps->size++;
}
- 头删
先判断是否为空的顺序表,然后删除第一个,后面的数据往前挪动,挪动的时候从前往后挪,不会覆盖,删除结束之后size--
//头删
void SLPopFront(SL * ps)
{
assert(ps->size >0)
int begin = 1; //注意这里begin设置为1
while(begin<ps->size)
{
ps->a[begin-1] = ps->a[begin]; //覆盖前一个
begin++;
}
ps->size--;
}
- 查找
遍历顺序表, 根据数据查找位置,找到了就返回数据的下标
int Find(SL * ps, SLDataType x)
{
assert(ps);
for(int i = 0;i<ps->size;i++)
{
if(ps->a[size] == x)
{
return i;
}
}
//没找到
return -1;
}
- 在pos位置插入x
先判断pos位置的合法性,是否在这个顺序表的范围里,然后判断是否能插入,如果不可以,需要扩容;如果可以插入,pos位置之后的先往后挪动,end>=pos,然后pos位置插入数据
void SLInsert(SL * ps,SLDataType x)
{
assert(ps);
//判断pos的合法性 在这个顺序表中
assert(pos>=0);
assert(pos<=ps->size);
//判断是否要扩容
SLCheckCapacity(ps);
int end = ps->size - 1;
//pos位置之后的挪动 往后挪
while(end>=pos)
{
ps->a[end+1] = ps->a[end];
end--;
}
ps->a[pos] = x;
ps->size++;
}
- 在pos位置删除x
先判断pos的合法性,判断顺序表是否为空,如果可以删除,pos位置之后的往前挪动,size--
void SLErase(SL * ps,int pos)
{
assert(ps);
assert(pos>=0);
assert(pos<=ps->size);
assert(ps->size >0);
//挪动数据覆盖
int begin = pos+1;
while(begin<ps->size)
{
ps->a[begin-1] = ps->a[begin];
begin++;
}
ps->size--;
- 顺序表的打印
遍历打印即可,打印数组中的内容
void SLPrint(SL * ps)
{
assert(ps);
for(int i = 0;i<ps->size;i++)
{
printf("%d",ps->a[i];);
}
}
- 顺序表的销毁
将顺序表中的数组内容置空,size和capacity均置空
void SLDestroy(SL * ps)
{
assert(ps);
if(ps->a)
{
free(ps->a);
ps->a = NULL;
ps->size = ps->capacity = 0;
}
}
总结
本文主要介绍了顺序表的结构,以及对顺序表的操作:增删改查等。如有错误请指正。