提到顺序表很多人都会想起数组,但真正的顺序表真的只是一个数组那么简单吗?
再写一个顺序表前,我们需要想三个问题:
1:如何更新数组对的大小
2:数组如何进行扩容
3:顺序表是否是在插入时就已经排好了顺序
对于第三个问题答案是否定的 ,这里的顺序表不是说数组里的数组是按照一定的顺序进行排序的,而是它们在内存中存放的地址是连续的。
考虑到上面的因素我们知道单靠一个数组是不够的,我们需要一个size记录数组的当前大小,一个capicity记录最大容量。所以结构体是最好的选择。
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int SLDateType;
typedef struct SeqList
{
SLDateType* a;
size_t size;
size_t capacity; // unsigned int
}SeqList;
顺序表的初始化,销毁,打印作为基础三大件就不细说了
void SeqListInit(SeqList* ps)
{
ps->a = NULL;
ps->capacity = ps->size = 0;
}
void SeqListDestory(SeqList* ps)
{
free(ps);
ps->a = NULL;
ps->capacity = ps->size = 0;
}
void SeqListPrint(SeqList* ps)
{
for (int i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
}
因为数组的扩容问题,我们在插入元素时可能要经常扩容所以我们可以写一个函数专门用来检查数组是否需要扩容
void checkcapacity(SeqList* ps)
{
if (ps->size == ps->capacity)//如果当前大小等于最大容量那么就需要扩容
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//初始先设置为4
SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SeqList));
if (tmp == NULL)
{
exit(-1);
}
ps->a = tmp;
ps->capacity = newcapacity;
}
}
这里不再写尾插了,我们写一下头插
void SeqListPushFront(SeqList* ps, SLDateType x)
{
checkcapacity(ps);
int end = ps->size - 1;
while (end >= 0)
{
ps->a[end + 1] = ps->a[end];
--end;
}
ps->a[0] = x;
ps->size++;
}
我们从后往前移动元素,最后就可空出一个位置来进行头插。
有了头插的思路我们就可实现在中间插入元素,希望大家可以先自己试一下,周一我会将我写的代码发在评论里。
在数组里面删除一个尾元素只需要把它的size-1就行了,如果在前面的话
void SeqListPopFront(SeqList* ps)
{
for (int i = 0; i < ps->size-1; i++)
{
ps->a[i] = ps->a[i + 1];
}
ps->size--;
}
从前往后移动元素就行了。
这样一个简单的顺序表就建立完成了。