->Gitee源代码点击这里<- 顺序表的本质是一个动态开辟的数组 实现数据表,首先需要创建一个结构体,该结构体的成员记录了该数组的信息 以整形顺序表为例,为了方便以后代码的修改和维护,我们将int重命名
typedef int SLDatatype;
typedef struct SeqList
{
SLDatatype* a;
int size;
int capacity;
}SeqList;
我们创建一个结构体变量
struct SeqList myseq;
此时,变量下的成员都需要随机值,因此我们需要一个初始化成员变量的接口(即函数) 由于成员的值需要发生改变,所以我们需要传地调用函数 初始化时,我们假设需要给定一个初始的数组大小
void SeqListInit(SeqList* pq);
void SeqListInit(SeqList* pq)
{
assert(pq);
pq->a = (SLDatatype*)malloc(sizeof(SLDatatype) * 4);
if (pq->a == NULL)
{
printf("Init Failed\n");
exit(-1);
}
pq->capacity = 4;
pq->size = 0;
}
由于数组的动态开辟的,所以使用完之后需要将空间释放,因此对应的,需要有一个释放动态开辟空间的接口
void SeqListDestroy(SeqList* pq);
void SeqListDestroy(SeqList* pq)
{
assert(pq);
free(pq->a);
pq->a = NULL;
pq->size = pq->capacity = 0;
}
数组的准备工作已经完成,有了数组,就需要完成数据的处理部分,即数据的增删改查 一、插入数据的接口 ①实现任意位置插入 我们需要接口实现能在数组的任意位置 _pos _处插入数据(注意:顺序表的数据必须是连续的,所以任意位置是有限制的,即0<pos<size) 插入数据的原理:从数组的最后一个数据开始,依次往后挪动一个空间,到pos处停止,将pos处原本的数据覆盖成想要插入的数据 而在插入数据之前,我们需要判断数组的容量是否已经满,如果数组满了,再往数组里插入数据显然是不合逻辑的,因此需要对数组进行扩容 所以为了完成插入数据的接口,我们还需要准备一个检查容量判断是否扩容的接口
void CheckCapacity(SeqList* pq);
void CheckCapacity(SeqList* pq)
{
if (pq->size == pq->capacity)
{
SLDatatype newa = (SLDatatype*)realloc(pq->a, sizeof(SLDatatype) * 2 * pq->capacity);
if (newa == NULL)
{
printf("Realloc Failed\n");
exit(-1);
}
pq->a = newa;
pq->capacity *= 2;
}
}
接下来完成数据插入接口,接口的参数需要结构体变量的地址,插入数据的位置以及插入数据的值
void SeqListPush(SeqList* pq, int pos, SLDatatype data);
void SeqListPush(SeqList* pq, int pos, SLDatatype data)
{
assert(pq);
assert(pos >= 0 && pos <= pq->size);
CheckCapacity(pq);
int end = 0;
for (end = pq->size - 1; end >= pos; end--)
{
pq->a[end + 1] = pq->a[end];
}
pq->a[pos] = data;
pq->size++;
}
此时可以对改接口进行测试了(测试过程略),为了方便测试,我们可以增加一个打印数组数据的接口以便于我们观察数组中的值
void SeqPrint(SeqList* pq);
void SeqPrint(SeqList* pq)
{
for (int i = 0; i < pq->size; i++)
{
printf("%d ", pq->a[i]);
}
printf("\n");
}
②有了上面的任意位置插入的接口,我们可以通过该接口的复用来实现更简便的头插数据和尾插数据接口 头插数据:
void SeqListPushFront(SeqList* pq, SLDatatype data);
void SeqListPushFront(SeqList* pq, SLDatatype data)
{
SeqListPush(pq, 0, data);
}
尾插数据:
void SeqListPushBack(SeqList* pq, SLDatatype data);
void SeqListPushBack(SeqList* pq, SLDatatype data)
{
SeqListPush(pq, pq->size, data);
}
二、数据的删除 删除 pos 处数据的原理为:pos 后面的数据整体往前挪动一个空间,以覆盖掉pos处的值 完成删除接口时,我们需要考虑空数组的情况,因此我们需要先添加一个判空接口
bool SeqListIsEmpty(SeqList* pq);
bool SeqListIsEmpty(SeqList* pq)
{
assert(pq);
return pq->size == 0;
}
完成删除接口
void SeqListPop(SeqList* pq, int pos);
void SeqListPop(SeqList* pq, int pos)
{
assert(pq);
assert(!SeqListIsEmpty(pq));
int begin = 0;
for (begin = pos; begin < pq->size-1; begin++)
{
pq->a[begin] = pq->a[begin + 1];
}
pq->size--;
}
和数据插入同理,可通过函数复用实现头删和尾删接口
void SeqListPopFront(SeqList* pq);
void SeqListPopBack(SeqList* pq);
void SeqListPopFront(SeqList* pq)
{
SeqListPop(pq, 0);
}
void SeqListPopBack(SeqList* pq)
{
SeqListPop(pq, pq->size-1);
}
三、数据的修改
void SeqListModify(SeqList* pq,int pos,SLDatatype data);
void SeqListModify(SeqList* pq, int pos, SLDatatype data)
{
assert(pq);
assert(pos >= 0 && pos <= pq->size);
pq->a[pos] = data;
}
四、数据的查找
int SeqListSearch(SeqList* pq, SLDatatype data);
int SeqListSearch(SeqList* pq, SLDatatype data)
{
assert(pq);
for (int i = 0; i < pq->size; i++)
{
if (pq->a[i] == data)
{
return i;
}
}
return -1;
}
至此顺序表的实现已经完成
|