目录
前言:
小伙伴们大家好,今天小编为大家带来的是关于顺序表的内容,因为我们知道顺序表其实在一些方面运用还是比较多的。虽然对于链表等结构来说,顺序表依旧有一定的缺陷,但是缺点是不能够掩饰顺序表的作用的。
一,什么是顺序表
1.1顺序表的两种形式
通俗来讲,顺序表可以有两种形式:
一种是长度固定的,用定长数组存储元素的顺序表,叫做静态顺序表。
另一种是长度不固定的,使用动态内存开辟的顺序表,叫做动态顺序表。
因为静态顺序表的长度是固定的,是不可变的,如果我们真正使用的长度少于固定的长度,那么将会造成空间浪费。所以一般我们不会用静态顺序表,而是使用动态顺序表。
1.2动态顺序表
所谓动态顺序表,就是顺序表的长度是可变的,当原有开辟的空间不够时,会再次新增空间,这样就避免了像静态顺序表一样浪费更多的空间。
接下来,我们通过几个接口来更深层的了解一下顺序表。
二,顺序表增删改查的接口实现
2.1结构体空间表示顺序表
如上图所示,对于动态顺序表来说,我们三个成员,首先是存放元素的数组,其次是表示当前数组元素个数的size,然后是表示数组最大元素个数的capacity。
然后这里将int重命名为 SLDateType ,是因为该结构体内容的size和capacity以后我们可能需要变成其他的数据类型,不仅仅是整型,这里在结构体中是可以用的。
2.2顺序表的初始化
如上图所示,因为暂时来说,顺序表是不需要内容的,只有当之后需要插入新内容时,才会新增空间。
2.2malloc新增空间
//扩容函数
void SeqListCheckCapacity(SL* pc)
{
//判断顺序表是否满
if (pc->size == pc->capacity)
{
//三目操作符:表达式1?表达式2:表达式3
//判断是否为空
int newcapacity = (pc->capacity == 0) ? 3 : pc->capacity * 2;
SLDataType* ps = (SLDataType*)realloc(pc->arr, newcapacity * sizeof(SLDataType));
if (NULL == ps)
{
printf("realloc is failed");
exit(-1);//异常退出,不同于return
}
pc->arr = ps;
pc->capacity = newcapacity;
}
}
如上代码所示,当之后我们需要在顺序表中新增空间时,如果当 size和capaticy 一样大时,说明当前顺序表要么没有一个空间,要么当前的空间已经满了,需要新增空间然后存放数据了。
这里需要注意的有两个方面:
当然,最后一定不能忘记的是,当使用完顺序表之后,一定要将开辟的空间释放哦!!!
2.3增加元素
//头插入
void SeqListFrontPush(SL* pc, SLDataType x)
{
assert(pc);
SeqListCheckCapacity(pc);
//插入
int end = pc->size;
while (end--)
{
pc->arr[end + 1] = pc->arr[end];
}
pc->arr[0] = x;
pc->size++;
}
//尾插入
void SeqListBackPush(SL* pc, SLDataType z)
{
assert(pc);
SeqListCheckCapacity(pc);
pc->arr[pc->size] = z;
pc->size++;
}
那么首先,插入有三种方式,这里我们先了解两种,分别为头插和尾插。也就是说一个在顺序表的头部一次插入,一个是在尾部一次插入元素。
尾插:那么对于尾插是不需要移动元素的,因为尾巴上插入内容不会影响前面元素。 所以我们只需要在最后一个位置上插入即可。
2.4删除元素
//头删除
void SeqListFrontPoP(SL* pc, SLDataType y)
{
assert(pc && pc->size > 0);
if (y > pc->size)
{
printf("删除元素个数错误\n");
SeqListClosePs(pc);
exit(-1);
}
else
{
int i = 0;
for (i = 0; i < pc->size - y; i++)
{
pc->arr[i] = pc->arr[i + y];
}
pc->size -= y;
}
}
//尾删除
void SeqListBackPoP(SL* pc, SLDataType i)
{
//有元素才能删
assert(pc && pc->size > 0);
//应该有一个判断,删除过量?
if (i > pc->size)
{
printf("删除错误\n");
}
else
pc->size -= i;
}
这里我们没有一个一个的删除,而是根据传递的参数 SLDataType 的值来决定删除几个元素,但是大概实现都是一样的。
尾删的话,就更加简单了,因为不需要移动元素,所以只是将现有元素个数减去需要删除的元素个数即可。
2.5查找元素
如上图所示,查找相对来说是比较简单的,这里我们不做过多赘述。
2.6指定位置元素的插入和删除
2.6.1指定位置元素的插入
//在指定pos位置添加指定数字
//假定x值为整型数
void SeqListInsert(SL* pc, int pos, SLDataType x)
{
assert(pc && x < INT_MAX && x >INT_MIN);
SeqListCheckCapacity(pc);
int tmp = pc->size-1;
while (tmp >= pos)
{
pc->arr[tmp+1] = pc->arr[tmp];
tmp--;
}
pc->arr[pos] = x;
pc->size++;
}
那么我们发现,其实任意位置的插入也可以适用于头插和尾插,所以这里的认为位置插入就是我们的第三种万能插入方法。我们只需要对插入的位置进行适当的调整,最后插入即可。
2.6.2指定位置元素的删除
根据上面的插入函数,对于任意位置的删除其实也是很方便的。只是我们需要先检查要删除的元素是不是当前顺序表中存在的元素。然后再将 pos 位置后面的元素依次往前移动一位即可。此 pos 位置元素被覆盖掉,也就完成了我们对于该位置元素的删除。
那么我们也知道,任意位置的删除同样适用于头删和尾删。那么此时就将便利许多。
好的,那么关于顺序表,我们就了解这么多,如有问题,还请小伙伴们指正呀!!!