上一次我们谈到了静态顺序表(https://blog.csdn.net/lsfan0213/article/details/81262124),这次我们来了解另一种顺序表:动态顺序表
在当我们有少量数据的时候,我们可以使用静态顺序表。但是如果我们有大量的数据,这些数据往往会超过数组的大小,这个时候我们需要使用动态顺序表
为了区别静态顺序表和动态顺序表,我们用两张图分别来表示这两中数据结构:
上图是静态顺序表
上图是动态顺序表
静态顺序表和动态顺序表最大的区别就是:动态顺序表可以实现扩容操作
在动态顺序表这张图中,3表示当前有效的数据的个数。10表示容量。在有效数据需要增加的时候,我们可以进行扩容
而静态顺序表是不可以的,它只能规定好不可改变的有效数据的个数。
下面,还是用代码来介绍动态顺序表的一些基本操作
结构体的定义:
typedef int DataType;
struct SeqListDynamic{
DataType *array; //数据块指针
int capacity; //当前的有效数据个数
int size; //容量
};
typedef struct SeqListDynamic SeqListD;
#define CAPACITY (2)
动态顺序表的初始化:
void SeqListDInit(SeqListD *pSLD)
{
assert(pSLD != NULL);
pSLD->capacity = CAPACITY;
pSLD->size = 0;
pSLD->array = (DataType *)malloc(pSLD->capacity * sizeof(DataType)); //在堆上申请空间
assert(pSLD->array != NULL);
}
动态顺序表的销毁:
void SeqListDDestroy(SeqListD *pSLD)
{
assert(pSLD != NULL);
pSLD->size = 0;
free(pSLD->array); //销毁时一定要free掉之前在堆上申请的空间,以免造成内存泄露
pSLD->capacity = 0;
}
判断动态顺序表是否需要扩容:
void ExpandIfRequired(SeqListD *pSLD)
{
if (pSLD->size < pSLD->capacity) {
return;
}
// 到这里肯定不够,需要扩容
// 1.容量变大
// 2.开个新容量的空间
// 3.把老数据迁移到新空间
// 4.把老空间释放
// 5.把新的空间挂过来
//伙伴算法
// 1.
pSLD->capacity *= 2;
// 2.
DataType *newArray = (DataType *)malloc(sizeof(DataType)* pSLD->capacity);
assert(newArray != NULL);
// 3.
int i;
for (i = 0; i < pSLD->size; i++) {
newArray[i] = pSLD->array[i];
}
// 4.
free(pSLD->array);
// 5.
pSLD->array = newArray;
}
尾插:
void SeqListDPushBack(SeqListD *pSLD, DataType data)
{
assert(pSLD != NULL);
//这是静态的处理方式
assert(pSLD->size < pSLD->capacity);
//函数自己去判断,有需要就会扩容
ExpandIfRequired(pSLD);
//到这里的时候,容量就肯定够
pSLD->array[pSLD->size++] = data;
}
头插:
void SeqListDPushFront(SeqListD *pSLD, DataType data)
{
assert(pSLD != NULL);
ExpandIfRequired(pSLD); //有必要就扩容
//剩下的和静态顺序表一样
}
按下标插入:
void SeqListDPushInsert(SeqListD *pSLD, int pos, DataType data)
{
assert(pSLD != NULL);
ExpandIfRequired(pSLD); //有必要就扩容
//剩下的和静态顺序表一样
}
删除等操作都和静态顺序表的是一样的:详细请走这里:
https://blog.csdn.net/lsfan0213/article/details/81262124
到这我们就介绍完了动态顺序表的所有基本操作了