目录
概念
在写顺序表之前,我们需要了解什么是顺序表,其实顺序表就是数组,只不过我们在数据结构上习惯上称之为顺序表,所以写出一个顺序表是非常简单的,就是对数组进行操作,只不过封装了。
我们的通讯录就是用顺序表去实现的,所以如果写过通讯录的话,写顺序表也不是什么难事,通讯录代码详见C语言 顺序表实现通讯录【完全版】 含文件版本fwrite、fread和fscanf和fprintf的使用_努力敲代码的小王的博客-CSDN博客
顺序表的功能:
1.顺序表的尾插
2.顺序表的尾删
3.顺序表的头插
4.顺序表的头删
5.顺序表的查找
6.在指定位置插入
7.在指定位置删除
顺序表的定义
typedef int SDataType;
typedef struct SeqList
{
SDataType* arr;
int sz; //记录当前的个数
int capacity; //容量
}SL;
顺序表的初始化
定义好以后我们需要进行初始化,把里面的数据置为空
void Init_SeqList(SL* ps)
{
ps->arr=NULL;
ps->sz=ps->capacity=0;
}
顺序表的尾插
把顺序表想成数组,找到数组中当前的个数,然后把数据插入进去,然后个数+1
void SeqListPushBack(SL* ps,SDataType x)
{
//普通版
assert(ps);
checkcapacity(ps);
ps->arr[ps->sz]=x;
ps->sz++;
//优化版
// SeqListInsert(ps,ps->sz,x);
}
顺序表的增容
不过在插入之前,我们需要检查容量,然后如果顺序表当前的个数等于容量,我们就需要扩容
void checkcapacity(SL* ps)
{
if(ps->sz==ps->capacity)
{
int newcapacity=ps->capacity==0?4:ps->capacity*2;
SDataType* tmp=(SDataType*)realloc(ps->arr,sizeof(SDataType)*newcapacity);
if(tmp==NULL)
{
perror("malloc fail:");
exit(-1);
}
ps->arr=tmp;
ps->capacity=newcapacity;
}
}
顺序表的尾删
实现尾删非常简单,只需要把记录顺序表个数的变量sz-1就可以了
void SeqListPopBack(SL* ps)
{
//普通版
assert(ps->sz>0);
ps->sz--;
//优化版
// SeqListErase(ps,ps->sz);
}
顺序表的头插
想要在头部插入数据,我们就需要把第一个位置空出来,和在数组头部插入数据是一摸一样的
void SeqListPushFront(SL* ps,SDataType x)
{
// 普通版
assert(ps);
checkcapacity(ps);
int i=0;
for(i=ps->sz;i>0;i--)
{
ps->arr[i]=ps->arr[i-1];
}
ps->arr[i]=x;
ps->sz++;
//优化版
// SeqListInsert(ps,0,x);
}
顺序表的头删
想要在头部进行删除,就需要把后面的数据往前挪动,这样就实现了顺序表的头删
void SeqListPopFront(SL* ps)
{
//普通版
assert(ps);
assert(ps->sz>0);
int i=0;
for(i=0;i<ps->sz-1;i++)
{
ps->arr[i]=ps->arr[i+1];
}
ps->sz--;
//优化版
// SeqListErase(ps,0);
}
顺序表的查找
查找数据时,我们只需要从头到尾遍历一遍顺序表,若是找到我们便会返回下标
int SeqListFind(SL* ps,SDataType x)
{
int i=0;
for(i=0;i<ps->sz;i++)
{
if(ps->arr[i]==x)
{
return i;
}
}
return -1;
}
在指定位置插入
首先我们需要把指定位置的数据全部往后移,然后就会把需要插入数据的位置空出来
void SeqListInsert(SL* ps,int pos,SDataType x)
{
assert(ps);
checkcapacity(ps);
int i=0;
for(i=ps->sz;i>pos;i--)
{
ps->arr[i]=ps->arr[i-1];
}
ps->arr[i]=x;
ps->sz++;
}
在指定位置的删除
把指定位置后面的数据全部往前移该功能就完成了
写完指定插入和删除就可以优化我们的头插和尾插了,可以回过头来去看我的优化版本
void SeqListErase(SL* ps ,int pos)
{
int i=0;
assert(ps);
assert(ps->sz>0);
for(i=pos;i<ps->sz-1;i++)
{
ps->arr[i]=ps->arr[i+1];
}
ps->sz--;
}
顺序表的销毁
我们需要把顺序表内的指针置为空就可以了,因为顺序表是一块连续的空间,如果是链表则序表把每一个节点都销毁掉,然后把当前个数和容量也都置为空
void SeqListDestroy(SL* ps)
{
assert(ps);
if(ps->arr)
{
free(ps->arr);
ps->sz=ps->capacity=0;
}
}
顺序表的打印
void SeqListPrint(SL* ps)
{
int i=0;
for(i=0;i<ps->sz;i++)
{
printf("%d ",ps->arr[i]);
}
printf("\n");
}
顺序表的优缺点
优点:(1)尾插尾删效率高 (2)支持随机访问
缺点:(1)头插头删效率低 (2)连续的物理空间,空间不够需要增容(增容有一定程度的消耗,为了避免频繁增容,又可能会导致空间浪费)