什么是顺序表
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组来存储。那么数组和顺序表的区别主要是顺序表是对数组的封装,虽然顺序表的底层是数组,但是提供了很多现成的方法如数据的增删查改等功能。顺序表是线性表的一种,顺序表的物理结构(指的是数据在内存上的存储方式)不一定是连续的,逻辑结构一定连续。
链表与顺序表的区别
链表:链表是一种基于指针的数据结构,它将数据存储在一系列不连续的内存块中。在链表中,每个元素包含一个指向下一个元素的指针,因此可以通过遍历指针来访问元素。在插入或删除元素时,只需要修改指针的指向,不需要移动其他元素的位置,这使得链表在插入或删除元素时具有更好的性能。
顺序表:顺序表是一种基于数组的数据结构,它将数据存储在一段连续的内存空间中。可以通过下标快速访问。
为什么不用静态存储
我们知道顺序表分为动态表和静态表,那么为什么不用静态存储是因为我们未知所需内存的大小所以使用动态存储可以对顺序表进行扩容。
顺序表的初始化
顺序表初始化的时候需要把指向的数组制空,然后此时长度和容量都应该为空
void SLIint(SL* ps)
{
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
检查是否需要开辟空间所封装的函数
在动态开辟空间插入的时候,首先要考虑所要插入的空间大不大,是否需要扩容,扩容的时候一般都是二倍或者三倍的形式进行扩充,因为可以节省效率,如果一次扩大一倍操作系统就会一直循环这个不够扩不够扩的循环,这样导致效率较低。注意一点这里扩容是字节的大小所以一点过要*上数据的类型
void checkSpace(SL* ps)
{
//如果内存不够还需要扩容,这时候还要考虑如何扩容,扩多大的内存
// 一般是成倍数的增加,一般是2倍或者3倍
//如果容量大则不需进行扩容
if (ps->capacity == ps->size)
{
//申请空间2*SLDataType类型所占字节的大小
int NEWcapacity = ps->capacity == 0 ? 4 : 2 *ps->capacity;
SLDataType* temp = (SLDataType*)realloc(ps->arr, NEWcapacity * sizeof(SLDataType));
//申请失败
if (temp == NULL)
{
perror("realloc fail!!!");
exit(1);
}
//申请成功
ps->arr = temp;
ps->capacity = NEWcapacity;
}
}
顺序表的头插
头部插入只需要考虑的问题是插入的空间是否够,因此需要检查一下即可,此外不用考虑是否指向一个空数组,因为这不影响插入的元素。就是从后向前移动即可。
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps);
checkSpace(ps);
int i = 0;
for (i = ps->size; i>0; i--)
{
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[0] = x;
ps->size++;
}
顺序表的尾插
尾插的具体方法和细节我已经在代码中注释了
void SLPushBack(SL* ps, SLDataType x)
{
assert(ps);
//判断是否为空指针,空直接跳出
/*if (ps == NULL)
{
return;
}*/
/*方法二assert(ps);*/
checkSpace( ps);
//申请成功
ps->arr[ps->size++] = x;
}
顺序表的头删
头删就要注意指向是否为空指针这个问题,为空就直接跳出就行,不为空就是后面元素盖掉前面就可以了。
void SLPopFront(SL* ps)
{
assert(ps);
assert(ps->size);
int i = 0;
for (i = 0; i <ps->size-1; i++)
{
ps->arr[i] = ps ->arr[i+1];
}
ps->size--;
}
顺序表的尾删
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size);//进行判断顺序表为空不能进行删除操作
/*ps->arr[ps->size - 1] = -1;*/
--ps->size;
}
顺序表的释放
空间开辟结束后一定要记得释放,并置为空指针,不然会造成野指针。
void SLDestroy(SL* ps)
{
if (ps->arr!=NULL )
{
free(ps->arr);//释放
}
ps->arr = NULL;//指向空指针
ps->size = ps->capacity = 0;
}
指定位置插入
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos <= (ps->size));
//检查是需要扩容
checkSpace(ps);
for (int i = ps->size; i > pos; i--)
{
ps->arr[i] = ps->arr[i-1];
}
ps->arr[pos] = x;
ps->size++;
}
指定位置删除
void SLErase(SL* ps, int pos)
{
assert(ps);
for (int i = pos; i < ps->size; i++)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
查找指定元素
int SLFind(SL* ps, SLDataType x)
{
assert(ps);
assert(ps->size > 0);
int sign = 0;
for (int i = 0; i < ps->size; i++)
{
if (ps->arr[i] == x)
{
return 1;
sign = 1;
break;
}
}
if(sign==0)
return 0;
}
![](https://i-blog.csdnimg.cn/direct/3c2435dd110744418d1fc20927e0d505.png)
总结
数据结构和C语言的结构体,内存的动态存储,指针的练习较为密切。数据结构的算法理解问题不大但是当上手练习时难度还是不小,所以想练好数据结构还是要多敲多练。由于代码较多所以此处不进行展示了。