前言
在计算机内存中,顺序表是以数组的形式保存的线性表。也就是一组地址连续的存储单元依次存储数据元素的线性结构。
在数组中,我们会先申请一段连续的内存空间,然后把数组以此存入内存当中,中间没有一点空隙。这就是一种顺序表存储数据的方式。对于顺序表的基本操作有:增(add),删(remove),改(set),查(find),插(insert)。
1.顺序表删除元素
从顺序表中删除指定的元素,其实实现起来是非常简单的,只需要找到目标元素,并将其后续的所有元素整体前移1个位置即可。比如
上面我们发现,顺序表删除元素,其实是在间接删除目标元素。就是将后续元素整体向前移动一个位置。
时间复杂度分析:从顺序表中删除元素,最好的情况是删除的元素刚好是最后一个元素,这时候不需要移动元素,只需要把表的size-1即可。最坏的时间复杂度刚好是第一个元素,这个时候需要后面全部的元素向前移动一位,同时size - 1,时间复杂度是O(N)。我们分析时间复杂度的原则是分析最快情况,这样才有意义。因此删除操作的时间复杂度为O(N)。
2.顺序表插入元素
向已有的顺序表中插入元素,根据插入的位置不同,可以分为3种情况。
1.插入到顺序表的表头
2.在表中间位置插入
3.尾随顺序表中已有的元素,作为最后一个元素插入
虽然数据元素插入顺序表中的位置有所不同,但是都是使用的是同一个方法去解决的。就是通过遍历,找到数据元素要插入的位置。然后要做到如下两步工作。将要插入的位置元素以及后续的元素整体向后移动一个位置将元素放到腾出来的位置上。例如,在{1,2,4,5,6,7}的第三个位置插入3实现过程如下:
从时间复杂度来看,同删除元素是一样的,均为O(N)。
3.优势
因为数据在数组中按顺序存储,可以通过数组下标直接访问,因此顺序表的查找定位元素很快
4.劣势
插入和删除元素都需要大量的操作。
因为数组在声明的时候需要确定长度,因此顺序表的长度是确定的。若需要扩大顺序表长度,有需要大量的操作,不够灵活。(要将该数组中的元素全部copy到另外⼀个数组)
由于数据大小的不可测性,有时会浪费掉大量的空间。
5.应用场景
顺序表适用于那些不需要对于数据进行大量改动的结构
6.代码展示
#include<stdio.h>
#include<stdlib.h>
//实现一个存放int类型数据的顺序表
typedef struct ArrayList{
int *date;//指针模拟开数组
int length;//理论最大容量
int size;//实际容量
}MyArray;
//初始化顺序表,将顺序表的 理论最大容量定为n
MyArray initAarry(int n)
{
MyArray ar;
ar.date=(int *)malloc(sizeof(int)*n);
if(ar.date==NULL)
{
printf("空间分配失败\n");
}
ar.length=n;
ar.size=0;
return ar;
}
//在顺序表a中增加一个元素k
void add(MyArray *a,int k)
{
if(a->size<a->length)
{
a->date[a->size]=k;
a->size++;
}
else{
printf("空间已满,不能插入\n");
}
}
//在顺序表a的i下标位置,插入一个元素k
void insert(MyArray *a,int i,int k)
{
if(a->size<a->length)
{
//移动位置
for(int j=a->size-1;j>=i;j--)
{
a->date[j+1]=a->date[j];
}
a->date[i]=k;
a->size++;
}
else{
printf("空间已满,不能插入\n");
}
}
//在顺序表a中查找元素k
int find(MyArray *a,int k)
{
for(int i=0;i<a->size;i++)
{
if(a->date[i]==k)
{
return i;
}
}
return -1;
}
//在顺序表a中删除元素k
void del(MyArray *a,int k)
{
int i=find(a,k);//i是被删除数据k的下标
if(i==-1)
{
printf("被删除的数据不存在\n");
}
else
{
for(int j=i+1;j<a->size;j++)
{
a->date[j-1]=a->date[j];
}
a->size--;
}
}
//输出顺序表a中的元素
void show(MyArray a)
{
for(int i=0;i<a.size;i++)
{
printf("%d ",a.date[i]);
}
printf("\n");
}
int main()
{
MyArray a;
int n;//理论容量
printf("请给出顺序表的理论最大容量:\n");
scanf("%d",&n);
a=initAarry(n);
add(&a,0);
add(&a,1);
add(&a,2);
add(&a,3);
add(&a,4);
show(a);
insert(&a,2,7);
show(a);
del(&a,7);//删除数据7
show(a);
return 0;
}
main函数中的操作可以随意更改 。
总结
综上所述,可以得出。顺序表对于插入、删除一个元素的时间复杂度是O(n)。
因为顺序表支持随机访问,顺序表读取一个元素的时间复杂度为O(1)。因为我们是通过下标访问的,所以时间复杂度是固定的,和问题的规模无关。
最大的优点是空间利用率高。最大的缺点是大小固定。