一、顺序表的结构
顺序表是线性表的一种实现形式,其底层基于数组结构,因此在物理存储和逻辑结构上均保持线性特征。
二、顺序表的类型
顺序表可分为静态顺序表和动态顺序表两种类型。
- 静态顺序表
静态顺序表在定义时即固定其容量,无法在程序运行过程中调整大小。 - 动态顺序表
动态顺序表具备在运行时根据需要调整容量的能力,从而更灵活地管理内存。
通过对比可以看出,动态顺序表在实际应用中通常优于静态顺序表。静态顺序表若预设空间过大易造成资源浪费,而空间不足又无法适应数据增长。因此,实际开发中更常使用动态顺序表。
三、动态顺序表的实现
我们通过以下步骤实现一个动态顺序表:
首先,创建头文件 Seqlist.h,定义顺序表结构及相关函数声明:
c
typedef int SLDataType; // 便于后续替换数据类型
typedef struct SeqList {
SLDataType* arr; // 指向动态数组的指针
int size; // 当前有效数据个数
int capacity; // 当前分配的存储容量
} SL;
// 函数声明
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
void SLPrint(const SL* ps);
- 顺序表的初始化与销毁
初始化时,将数组指针设为 NULL,size 与 capacity 均设为 0。也可选择初始时分配一定空间。
c
void SLInit(SL* ps) {
ps->arr = NULL;
ps->size = 0;
ps->capacity = 0;
}
销毁顺序表时,需释放动态申请的内存,避免内存泄漏:
c
void SLDestroy(SL* ps) {
if (ps->arr) {
free(ps->arr);
ps->arr = NULL;
}
ps->size = ps->capacity = 0;
}
- 数据插入操作
在插入数据前,需检查当前容量是否足够。我们封装一个检查并扩容的函数:
c
void SLCheckCapacity(SL* ps) {
if (ps->size == ps->capacity) {
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
if (tmp == NULL) {
perror("Realloc failed");
exit(1);
}
ps->arr = tmp;
ps->capacity = newCapacity;
}
}
- 尾插:在顺序表末尾插入元素
c
void SLPushBack(SL* ps, SLDataType x) {
SLCheckCapacity(ps);
ps->arr[ps->size] = x;
ps->size++;
}
- 头插:在顺序表头部插入元素,需将现有元素依次后移
c
void SLPushFront(SL* ps, SLDataType x) {
SLCheckCapacity(ps);
for (int i = ps->size; i > 0; i--) {
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[0] = x;
ps->size++;
}
使用打印函数验证插入操作:
c
void SLPrint(const SL* ps) {
for (int i = 0; i < ps->size; i++) {
printf("%d ", ps->arr[i]);
}
printf("\n");
}
- 数据删除操作
- 尾删:仅需将
size减一
c
void SLPopBack(SL* ps) {
if (ps->size > 0) {
ps->size--;
}
}
- 头删:将后续元素前移一位,并调整
size
c
void SLPopFront(SL* ps) {
if (ps->size > 0) {
for (int i = 0; i < ps->size - 1; i++) {
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
}
- 指定位置插入与删除
- 指定位置插入:将目标位置及之后的元素后移,再插入新值
c
void SLInsert(SL* ps, int pos, SLDataType x) {
assert(pos >= 0 && pos <= ps->size);
SLCheckCapacity(ps);
for (int i = ps->size; i > pos; i--) {
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[pos] = x;
ps->size++;
}
- 指定位置删除:将目标位置之后的元素前移,覆盖目标值
c
void SLErase(SL* ps, int pos) {
assert(pos >= 0 && pos < ps->size);
for (int i = pos; i < ps->size - 1; i++) {
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
以上即为动态顺序表的基本实现,涵盖了初始化、销毁、插入、删除等核心操作,具备良好的可扩展性与实用性。