目录
1.顺序表的定义
2.顺序表的初始化
3.顺序表的扩容
4.顺序表的尾插
5.顺序表的头插
6.顺序表的尾删
7.顺序表的头删
8.顺序表的最后处理
9.顺序表指定位置进行插入
10.顺序表指定位置进行删除
定义了一个结构体,用typedef定义int类型,方便以后修改类型
typedef int SLDateTyPe;
typedef struct SeqList
{
SLDateTyPe* a; //指向动态数组的指针
int size; //实际有多少人
int capacity; //容量大小
}SL;
size和capacity直接赋值为0,指针赋为空指针
void SeqListInit(SL*ps) //修改的是结构体里面的值,用指针
{
ps->size = 0;
ps->capacity = 0;
ps->a = NULL; //a是个指针要赋为空
}
这里注意扩容的情况,开始都为0的情况和空间慢了的情况
void SeqListCheck(SL* ps)
{
//检查容量空间,满了扩容
//
//一般有2种情况,一种是开始里面都没有值,都为0,第二种是
//容量空间满了,size往后++就会越界,这时候需要扩容
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
//这里用到三目操作符,如果开始是0,给4个空间,如果不是,扩容
//是之前的二倍,newcapacity是新空间的容量
SLDateTyPe* tmp = (SLDateTyPe*)realloc(ps->a, newcapacity * sizeof(SLDateTyPe));
//realloc函数的使用要熟悉,sizeof后面的是类型的大小,乘以个数,是总字节
if (tmp == NULL)
{
//判断一下是否开辟失败
printf("realloc fail\n");
exit(-1); //结束程序
}
ps->a = tmp; //把扩容开辟的新空间赋给原来的动态数组
ps->capacity = newcapacity;
}
}
把size当作下标看待,这里还要注意扩容的问题
void SeqListPushBack(SL* ps, SLDateTyPe x) //尾插
{
SeqListCheck(ps);
ps->a[ps->size] = x;
//看图容易理解
ps->size++;
}
void SeqListFront(SL* ps, SLDateTyPe x) //头插
{
//检查容量空间满了扩容
SeqListCheck(ps);
int end = ps->size - 1;
//size是最后一个数据的下一个位置下标
while (end >= 0)
{
ps->a[end] = ps->a[end + 1];
end--;
}
ps->a[0] = x;
ps->size++;
}
顺序表尾删简单,直接让size--就可以实现了。我们打印的数据就是size范围内的数据,size减了过后就没有这个数据了。
void SeqListPopBack(SL* ps) //尾删
{
//这里首先保证里面是有数据的,要不然会越界
if (ps->size == 0)
{
printf("SeqListPopBack is empty");
return;
}
//暴力检查
//assert(ps->size>0);
ps->size--;
}
从前往后挪动,先挪动前面的数据再挪动后面的数据
void SeqListPopFront(SL* ps) //头删
{
assert(ps->size > 0);
int begin = 1;
while (begin < ps->size)
{
ps->a[begin-1] = ps->a[begin ];
begin++;
}
ps->size--;
}
把ps(free掉),为空指针,size,capacity为0
void SeqListDestory(SeqList* ps)
{
free(ps->arr);
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
我们想一个问题,如果是在面试中,给了我们很短分钟来实现顺序表,那我们应该怎么做呢
现在有另外2个函数,我们就可以复用这2个函数对顺序表的头插、尾插,就可以直接复用,大大节约了时间。
(插入的话从后往前挪动)
(假如在pos=2的位置插入,3-9依次往后挪动一个,先挪动9,按顺序挪动)
void SeqListInsert(SL* ps, int pos, SLDateTyPe x)
{
assert(ps);
assert(pos>=0 && pos<=ps->size); //pos不能越界
//实现尾插的时候要pos要=size,相当于在尾部直接插入
SeqListCheck(ps);
//检查一下容量的问题,扩容
int end = ps->size - 1;
while (end >= pos)
{
ps->a[end+1] = ps->a[end];
end--;
}
ps->a[pos] = x;
ps->size++;
}
void SeqListErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->size-1);
int begin = pos;
while (begin < ps->size-1)
//删除的时候注意下标,pos的取值范围size-1已经是最大的了,begin+1会造成越界
//这里用ps->size-1代替
{
ps->a[begin] = ps->a[begin + 1];
begin++;
}
ps->size--;
}
void SeqlistErase(Sq* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos size);
int begin = pos+1;
while (begin < ps->size )
{
ps->a[begin-1] = ps->a[begin];
begin++;
}
ps->size--;
}
利用这两个函数可以很快的把前面的东西写出来,很方便。
尾插:尾插其实就是对顺序表最后的位置插入元素
SeqListInsert(ps, ps->size,x);
头插:头插就是对0的位置插入元素
SeqListInsert(ps,0,x);
尾删:尾删也是和尾插一样的,对最后的位置删除
SeqListErase(ps, ps->size-1);
头删:头删是对0的位置开始删除
SeqListErase(ps, 0);
void SeqListPrint(SL* ps)
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
}
int SeqListFind(SL* ps, SLDateTyPe x)
{
assert(ps);
int i = 0;
for (i = 0; i < ps->size; i++)
{
if(ps->a[i] == x);
return i;//返回的是下标
}
return -1;
}
int SeqListModifyt(SL* ps, int pos, SLDateTyPe x)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
ps->a[pos] = x;
}