一、定义
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存
储。在数组上完成数据的增删查改
二、分类
静态顺序表
动态顺序表
- 静态顺序表
一般都不使用,因为它的缺点太大,内存不能按照需求自动申请,需要人为的改变源代码
![](https://i-blog.csdnimg.cn/blog_migrate/039959bc5d3f52e795a361df5c3a1de5.png)
代码解释
1.N是这个顺序表的总长度
2.size需要根据存进去的数据的多少而发生变化
由于静态顺序表的缺点,诞生出了动态顺序表(由于不常用,就不展开说了)
2.动态顺序表
![](https://i-blog.csdnimg.cn/blog_migrate/7624e5def66a36528539d6fe404384c4.png)
- 定义解释
1.a用(int *),一会就可以用数组进行表示。
2.size的大小就是存进去的数据的多少。
3.capacity的大小就相当于静态顺序表中的"N",但是这个capacity的大小是可以自动进行变化的(下面有扩容的代码)。
- 常见操作
![](https://i-blog.csdnimg.cn/blog_migrate/ad02d2fae552860a45de9be464ead11a.png)
首先,我想在这边啰嗦几句,讲讲几个编程好习惯。
不要在main函数里面测试你写的函数接口是否正确,而是将要测试的几个函数放到一个函数里面,分组进行测试比如可以起名为 void Text_SL1();
void Text_SL1()
{
SL sl;
SLInit(&sl);
SL_Push_Back(&sl,5);
PrintSL(&sl);
SL_Pop_Back(&sl);
SLDestroy(&sl);
}
void Text_SL2()
{
SL sl;
SLInit(&sl);
SL_Push_Back(&sl,3);
PrintSL(&sl);
SL_Pop_Back(&sl);
PrintSL(&sl);
}
int main()
{
Text_SL2();
return 0;
}
像这样,你就可以只在main函数里面改变Text_SL的后缀就可以测试不同组合类型的函数(我这组就是测试了一下初始化+尾插法+打印函数+尾删法几个功能的组合效果如何),极大的提高了测试效率
操作一:初始化顺序表
void SLInit(SL* psl)
{
assert(psl);
psl->a =NULL;
psl->capacity = psl->size = 0;
}
传递过来的是SeqList sl的地址,可以对sl结构体的数据进行改变(assert的用法可以戳这里)。
操作二:尾插法插入数据
void SL_Push_Back(SL* psl,SLDateType x)
{
assert(psl);
//检查容量,不够就扩容,下面可以封装成一个函数
if (psl->size >= psl->capacity)
{
int newCapcity = psl->capacity == 0 ? 4 : psl->capacity * 2;
psl->a= (SLDateType*)realloc(psl->a, newCapcity * sizeof(SLDateType));
if (psl->a== NULL)
{
perror("realloc fail");
return;
}
psl->capacity = newCapcity;
}
psl->a[psl->size]=x;
psl->size++;
}
第五-第七行的解释:如果size和capacity相同,就意味着应该进行扩容了,如果原本的容量是0,那么我们就让newCapacity和capacity的值为4(能装四个元素),这是针对于经过SLInit函数初始化后的那种情况。如果经过初始化之后,又遇到了size和capacity相同的情况,就将容量扩大二倍(此时最合适,你也可以根据你的喜好扩大相应的备注,无非是数据多了需要多次扩容,数据少了扩容空间浪费的问题)
操作三:头插法插入数据
void SL_Push_Front(SL* psl, SLDateType x)
{
assert(psl);
CheckCapacity(psl);//此处的CheckCapacity()函数就是操作二里面的检查容量,封装成函数了
int end = psl->size-1;
while(end >=0)
{
psl->a[end +1] =psl->a[end];
end--;
}
psl->a[0] = x;
psl->size++;
}
操作四:尾删法
void SL_Pop_Back(SL* psl)
{
if (psl->size < 0)
return;
psl->size--;
}
最后一个元素不用释放,因为数组空间是连续的,并且你的psl->size也在变小,也不会用到这个值
操作五:头删法
void SL_Pop_Front(SL* psl)
{
if (psl->size ==0)return;
int begin =0;
while (begin <= psl->size-2)
{
psl->a[begin]=psl->a[begin + 1];
++begin;
}
psl->size--;
}
从后向前进行覆盖即可
操作五:查找元素并返回其下标
int Get_Elem_byNum(SL* psl,int x)
{
assert(psl);
for (int i = 0; i< psl->size; i++)
{
if (psl->a[i] == x)
return i;
}
return -1;
}
很简单,就是遍历一遍数组,如果找到,就返回其下标,如果找不到,就返回-1(也可以是其它数组里面没有的值);
操作六:指定位置插入
void Insert(SL* psl, size_t pos, int x)
{
assert(psl);
assert(pos<=psl->size);
int end=psl->size;
CheckCapacity(psl);
while (end>pos)
{
psl->a[end]=psl->a[end-1];
end--;
}
psl->a[end]=x;
psl->size++;
}
![](https://i-blog.csdnimg.cn/blog_migrate/27322a352ab8228086d8f536aa1415a0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d78e96d1ba6d8a12823964685b348834.png)
操作七:删除指定位置的元素
void Delect(SL* psl, int pos)
{
assert(psl);
assert(pos<=psl->size);
while (pos<psl->size)
{
psl->a[pos-1]=psl->a[pos];
pos++;
}
psl->size--;
}
![](https://i-blog.csdnimg.cn/blog_migrate/d1509793f2924a1757baff33fdbf2624.png)
操作八:修改指定位置的数据
void SLModify(SL* psl, int pos, SLDateType x)
{
pos = pos - 1;
assert(psl);
assert(pos<psl->size);
psl->a[pos]=x;
}
1.pos=pos-1是为了让与数组下标相照应
2.修改的位置必须在数组内,所以(assert(pos<psl->size);)
3.直接修改即可