顺序表
概念:顺序表是用一段连续物理地址依次存储数据结构元素的线性结构,一般用数组来存储,在数组上进行增删查改。
顺序表分类:
- 静态顺序表:使用定长数组存储
- 动态顺序表:使用动态开辟的数组存储
//静态顺序表
#define N 5
typedef int SLDataType;
typedef struct SeqList
{
SLdataType array[N];// 定长数组
size_t size; //有效数据个数
}SeqList;
//动态顺序表
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* array;//指向动态开辟的数组的指针
size_t size; //有效数据的个数
size_t capacity; //容量空间的大小
}SeqList;
静态顺序表只适用于存储数据量已知的场景。定长数组的N过大导致空间浪费或者N过小导致内存不够,所以静态顺序表在实际中局限性比较大。
所以,动态顺序表动态分配内存的性质,相比静态顺序表更合理更实用一些。
以下的借口实现我们都默认使用动态顺序表
顺序表初始化
//考虑容量为0,容量不为0的情况
void SeqListInit(SeqList* psl, size_t capacity)
{
assert(psl);//当psl为空时终止程序
if(capacity==0)
{
psl->array=NULL;
psl->size=0;
psl->capacity==0;
}
else{
psl->capacity=capacity;
psl->size=0;
psl->array=(SLDataType*)malloc(sizeof(SLDataType)*capacity);//为数组开辟空间
}
}
顺序表销毁
void SeqListDestory(SeqList* psl)
{
assert(psl);
//释放数组空间
free(psl->array);
psl->array=NULL;
//将size和capacity都置为0
psl->size=0;
psl->capacity=0;
}
检查容量
void Checkcapacity(SeqList* psl)
{
assert(psl);
//当size和容量相等时,说明该增容了
if(psl->size == psl->capacity)
{
//定义一个指针变量tmp指向新空间
STDataType* tmp;
if(psl->capacity==0)
{
psl->capacity=2;
}
tmp = realloc(psl->array, psl->capacity*2*sizeof(STDataType));
assert(tmp);
psl->array=tmp;
psl->capacity *=2;
}
}
这里补充一下realloc的用法:
void* realloc(void* ptr, size_t size);
重新分配内存块
更改ptr指向的内存块的大小。
该函数可以将存储块移动到新位置(其地址由该函数返回)。
即使存储块被移动到一个新位置,存储块的内容也会保留到新大小和旧大小中较小的一个。如果新的大小较大,则新分配的部分的值是不确定的。
如果ptr是空指针,该函数的行为就像malloc一样,分配一个新的大小字节块,并返回一个指向其开头的指针。
尾插数据
void SeqListPushBack(SeqList* psl, STDataType x)
{
assert(psl);
Checkcapacity(psl);//检查容量是否足够,防止数组越界
psl->array[psl->size]=x;
psl->size++;
}
尾删数据
void SeqListPopback(SeqList* psl)
{
assert(psl);
if(psl->size>0)//当有效数据个数大于0时,才可以删除数据
{
psl->size--;
}
}
头删数据
void SeqListPopFront(SeqList* psl)
{
assert(psl);
if(psl->size > 0)
{
int start = 0;
while(start < (psl->size-1))//有效数据总数减一
psl->_array[start]=psl->[start+1];//数据依次向前挪动一位
++start;
}
psl->size--;
}
某个位置插入数据
void SeqListInsert(SeqList* psl, size_t pos, STDataType x)
{
int end;
assert(psl && pos<=(psl->size));//添加数据,有可能添加在末尾,所以pos可能等于size
Checkcapacity(psl);
end=psl->size-1;
while( end >= (int)pos)
{
psl->array[end+1]=psl->array[end];//从最后一个位置往前,依次向后挪,空出pos
--end;
}
psl->array[pos]=x;
psl->size++;
}
查找某个元素
int SeqListFind(SeqList* psl, SLDataType x)
{
int i=0;
assert(psl);
for(i=0;i<(psl->size);i++)
{
if(psl->array[i]==x)
{
return i;
}
}
return -1;
}
删除某个值
void SeqListErase(SeqList* psl, size_t pos)
{
int start;
assert(psl &&start < (psl->size));//因为是删除数据,start是下标,不可能等于size
start=pos;
while(start<=(psl->size-1))//与insert原理相似
{
psl->array[start]=psl->array[start+1];
start++;
}
psl->size--;
}
删除某个位置
void SeqListRemove(SeqList* psl, SLDataType x)
{
int pos;
assert(psl);
pos = SeqListFind(psl,x);
if(pos != -1)
{
SeqListErase(psl,pos);
}
}