动态顺序表将顺序表进行动态存储
在这里我们在堆上创建一段空间(堆上的空间便于扩充,因为堆上的空间是我们自己进行动态管理的)
typedef int DataType;
typedef struct SeqListDynamic
{
DataType *arr;//指向堆上那段空间的指针
int capicity;//总容量大小
int size;//有效数据个数
}SeqListD;
动态顺序表中,我们实现了以下基本操作
//动态顺序表的初始化
void SeqListDInit(SeqListD *psld);
//动态顺序表的销毁
void SeqListDDestory(SeqListD *psld);
//动态顺序表的打印
void SeqListDPrint(SeqListD *psld);
//动态顺序表的插入:尾插、头插、插入指定位置
void SeqListDPushBack(SeqListD *psld, DataType data);
void SeqListDPushFront(SeqListD *psld, DataType data);
void SeqListDInsert(SeqListD *psld, int pos, DataType data);
1)初始化
void SeqListDInit(SeqListD *psld)
{
assert(psld != NULL);
//开始我们默认在堆上将申请两个数据那么大的空间
psld->capicity = 2;
//将申请好的空间用arr去指向
psld->arr = (DataType *)malloc(psld->capicity * sizeof(DataType));
//malloc申请空间会有申请失败的时候,因此一定要对申请的空间进行判空
assert(psld->arr);
//初始化时有效数据的个数应该为0
psld->size = 0;
}
2)销毁
void SeqListDDestory(SeqListD *psld)
{
assert(psld != NULL);
psld->size = 0;
psld->capicity = 0;
//堆上的空间使我们向操作系统借的
//一旦我们使用完毕一定要记得归还给操作系统,否则会出现内存泄漏的问题
free(psld->arr);
//free掉这段空间之后arr变成了一个野指针,为此我们最好将该指针指向空
psld->arr = NULL;
}
3)打印
void SeqListDPrint(SeqListD *psld)
{
assert(psld != NULL);
for (int i = 0; i < psld->size; i++)
{
printf("%d->", psld->arr[i]);
}
printf("NULL\n");
}
4)插入
//在此我们写一个函数来应对空间不足时对空间的扩充
void ExpandIfRequired(SeqListD *psld)
{
assert(psld != NULL);
//当有效元素的个数小于当前容量的时候就不需要扩充直接返回
if (psld->size < psld->capicity)
{
return;
}
//我们使用伙伴算法来进行扩充容量
//当空间不足时我们就将空间扩充到原来的2倍
psld->capicity *= 2;
DataType *newArray = (DataType *)malloc(psld->capicity * sizeof(DataType));
assert(newArray != NULL);
//当新的大空间申请成功之后就需要将原来的数据都搬移到新空间中
for (int i = 0; i < psld->size; i++)
{
newArray[i] = psld->arr[i];
}
//此时原来的空间已经没有用了,将该空间归还给操作系统
free(psld->arr);
//把我们整理好的新空间给arr就行啦
psld->arr = newArray;
}
void SeqListDPushBack(SeqListD *psld, DataType data)
{
assert(psld != NULL);
//插入之前得先判断当前是否需要扩充容量
ExpandIfRequired(psld);
//将数据放入空间中
psld->arr[psld->size] = data;
//有效元素个数加1
psld->size++;
}
void SeqListDPushFront(SeqListD *psld, DataType data)
{
assert(psld != NULL);
ExpandIfRequired(psld);
int i = psld->size;
//将当前元素均向后移动一个单位,留下第一个空间进行头插
for (; i > 0; i--)
{
//当然记得从后往前搬移数据,否则会将数据覆盖
psld->arr[i] = psld->arr[i - 1];
}
psld->arr[i] = data;
psld->size++;
}
void SeqListDInsert(SeqListD *psld, int pos, DataType data)
{
assert(psld != NULL);
ExpandIfRequired(psld);
int i = psld->size;
//将指定位置之后的元素均向后搬移一个单位,腾出指定位置的空间进行插入数据
for (; i > pos; i--)
{
psld->arr[i] = psld->arr[i - 1];
}
psld->arr[i] = data;
psld->size++;
}
总结:相对于静态顺序表来说,动态顺序表对空间的管理相对就灵活些