欢迎光临
我们一直在努力

数据结构入门:顺序表(C语言实现)

一、什么是顺序表?

顺序表是线性表的顺序存储结构,底层用 一段连续的内存空间(数组) 存放数据,逻辑相邻的元素在物理内存上也相邻。

可以把它理解成:自带长度管理、支持自动扩容的增强版数组。

顺序表分类

  • 静态顺序表:固定大小数组,容量写死,不够用就溢出,不实用。
  • 动态顺序表:用 malloc/realloc 动态申请空间,容量不够自动扩容,最常用。

二、顺序表结构体设计

我们用结构体封装三个核心信息:

  • 数据指针:指向动态数组
  • size:当前有效元素个数
  • capacity:当前最大容量

// 顺序表存储的数据类型(可改为char/double/结构体)
typedef int SLDataType;

// 动态顺序表结构体
typedef struct SeqList
{
SLDataType* a; // 指向动态数组
int size; // 有效数据个数
int capacity; // 容量(最多能存多少)
} SL;

三、基础操作函数声明

// 初始化
void SLInit(SL* ps);

// 销毁
void SLDestroy(SL* ps);

// 打印
void SLPrint(SL* ps);

// 扩容检查
void SLCheckCapacity(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);

// 查找
int SLFind(SL* ps, SLDataType x);

四、函数实现

1,初始化

void SLInit(SL* ps)
{
assert(ps);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}

2.销毁

void SLDestroy(SL* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->size = ps->capacity = 0;
}

3.打印

void SLPrint(SL* ps)
{
assert(ps);
for (int i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
printf("\\n");
}

4.扩容检查

容量满了自动扩容,一般扩为原来 2 倍(有其数学依据):

void SLCheckCapacity(SL* ps)
{
assert(ps);

if (ps->size == ps->capacity)
{
// 初始容量给4,否则*2
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapacity * sizeof(SLDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
ps->a = tmp;
ps->capacity = newCapacity;
}
}

5. 尾插 / 尾删

// 尾插
void SLPushBack(SL* ps, SLDataType x)
{
assert(ps);
SLCheckCapacity(ps);
ps->a[ps->size++] = x;
}

// 尾删
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size > 0);
ps->size–;
}

6.头插/头删

// 头插
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps);
SLCheckCapacity(ps);

// 数据往后挪一位
for (int i = ps->size; i > 0; i–)
{
ps->a[i] = ps->a[i – 1];
}
ps->a[0] = x;
ps->size++;
}

// 头删
void SLPopFront(SL* ps)
{
assert(ps);
assert(ps->size > 0);

for (int i = 0; i < ps->size – 1; i++)
{
ps->a[i] = ps->a[i + 1];
}
ps->size–;
}

7.指定位置插入/删除

// pos下标处插入x
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos <= ps->size);
SLCheckCapacity(ps);

for (int i = ps->size; i > pos; i–)
{
ps->a[i] = ps->a[i – 1];
}
ps->a[pos] = x;
ps->size++;
}

// 删除pos下标元素
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);

for (int i = pos; i < ps->size – 1; i++)
{
ps->a[i] = ps->a[i + 1];
}
ps->size–;
}

8.查找

// 找到返回下标,没找到返回-1
int SLFind(SL* ps, SLDataType x)
{
assert(ps);
for (int i = 0; i < ps->size; i++)
{
if (ps->a[i] == x)
return i;
}
return -1;
}

五、时间复杂度总结

操作时间复杂度
随机访问 O(1)
尾插 / 尾删 O(1)
头插 / 头删 O(n)
指定位置插入 / 删除 O(n)
查找 O(n)

六、顺序表优缺点

优点

  • 下标随机访问,查找极快
  • 内存连续,CPU 缓存命中率高
  • 实现简单,适合大量查询、少量插入删除的场景

缺点

  • 头部 / 中间插入删除要挪动数据,效率低
  • 扩容有开销,可能存在空间浪费
  • 必须连续内存,大片空间不足时容易失败

七、总结

顺序表是数据结构入门第一站,在以后会用到:

  • 内存连续存储
  • 动态内存管理
  • 增删改查的基本思想
  • 为后续链表、栈、队列打下基础
赞(0)
未经允许不得转载:171主机测评 » 数据结构入门:顺序表(C语言实现)
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址