33_顺序表(待完善)

核心摘要: 本文使用C语言从零实现动态顺序表,重点讲解内存分配策略、增删改查的核心算法以及边界条件处理,解决"数组越界"和"扩容无效"两大常见问题。


一、顺序表的基本概念与结构设计

1. 逻辑结构与物理结构对比

   (1) 逻辑结构:线性表(元素之间具有一对一的前后关系)。

   (2) 物理结构:连续的内存地址(与数组一致,但支持动态扩展)。

2. 静态数组 vs 动态顺序表

   (1) 静态数组的致命缺陷:容量固定,编译时确定,易溢出。

   (2) 动态顺序表的优势:运行时扩容,内存利用率高。

3. 结构体定义(C语言描述)

   采用 SeqList 结构体封装三个必要属性:

c 复制代码
typedef int SLDataType;  // 方便后续修改数据类型(如改为char或double)

typedef struct SeqList
{
    SLDataType* a;      // 指向动态开辟数组的指针
    int size;           // 有效数据个数(当前长度)
    int capacity;       // 当前最大容量(总空间大小)
} SeqList;

    a. 为什么需要 capacity ------ 区分"已用空间"和"总空间",是扩容判断的依据。

    b. 为什么用 typedef 定义数据类型? ------ 提高代码复用性,一行修改即可适配int/float/struct。


二、核心操作的实现(增删改查)

1. 初始化与销毁(内存管理)

   (1) 初始化 :将指针置 NULLsizecapacity 置 0。

c 复制代码
void SLInit(SeqList* psl);

   (2) 销毁 :释放 psl->a,重新调用初始化(防止野指针)。

c 复制代码
void SLDestroy(SeqList* psl);

2. 扩容机制(核心难点)

   (1) 触发条件size == capacity

   (2) 扩容策略

    a. 小容量场景:capacity 为 0 时,开辟 4 个元素大小。

    b. 大容量场景:新容量 = 原容量 × 2(指数增长,减少 realloc 次数)。

   (3) 扩容函数实现

c 复制代码
void SLCheckCapacity(SeqList* psl)
{
   if (psl->size == psl->capacity)
   {
       int newCapacity = (psl->capacity == 0 ? 4 : psl->capacity * 2);
       SLDataType* tmp = (SLDataType*)realloc(psl->a, newCapacity * sizeof(SLDataType));
       if (tmp == NULL)
       {
           perror("realloc fail");
           return;
       }
       psl->a = tmp;
       psl->capacity = newCapacity;
   }

3. 增(头插 / 尾插 / 任意位置插入)

   (1) 尾插 :先检查容量,再在 psl->a[psl->size] 处赋值,最后 size++。时间复杂度 O(1)。

   (2) 头插 :从后往前移动元素(for 循环从 size1),腾出 [0] 位置。时间复杂度 O(n)。

   (3) 任意位置插入 :将 [pos, size-1] 全部后移一位,再插入。必须判断 pos 合法性(0 ≤ pos ≤ size)。

4. 删(头删 / 尾删 / 任意位置删除)

   (1) 尾删 :直接 size--(注意:不需要真正清除内存,下次插入会覆盖)。

   (2) 头删 :从前往后移动元素(for 循环从 1size-1),最后 size--

   (3) 任意位置删除 :将 [pos+1, size-1] 前移覆盖 pos 位置。

    ⚠️ 删除操作的三重检查:

    ⓵ 断言 psl 不为空。

    ⓶ 断言 psl->size > 0(空表不能删)。

    ⓷ 检查 pos 范围:0 ≤ pos < size。

5. 查与改

   (1) 按值查找:遍历数组,返回第一个匹配的下标(找不到返回 -1)。

   (2) 按位置修改 :直接赋值 psl->a[pos] = x前提是 pos < size

   (3) 按值修改:先查找位置,再修改(查找逻辑复用)。


三、打印与调试辅助函数

1. 打印顺序表

   遍历 size 次,输出 psl->a[i],格式统一为 [1, 2, 3, 4]

2. 菜单交互示例(用于控制台测试)

   提供 0-7 的数字菜单:

   ⓵ 尾插   ⓶ 头插   ⓷ 尾删   ⓸ 头删

   ⓹ 任意插入   ⓺ 任意删除   ⓻ 查找   ⓼ 打印   ⓿ 退出


四、常见错误与避坑指南(实用性重点)

1. 扩容时的野指针问题

   (1) 错误写法 :直接用 realloc(psl->a, newSize) 且不判断返回值。

   (2) 正确写法 :用临时指针 tmp 接收 realloc 返回值,成功后再赋值给 psl->a

    原因realloc 失败返回 NULL,直接赋值会丢失原有内存地址,导致内存泄漏且无法恢复。

2. 删除/插入时的越界访问

   (1) 头插移动元素时,必须从后往前移动for (i = size; i > pos; i--))。

   (2) 头删移动元素时,必须从前往后移动for (i = pos; i < size-1; i++))。

    口诀:插入向后挪,删除向前盖;反向操作必越界。

3. 结构体传值 vs 传址

   (1) 错误 :函数参数写 void func(SeqList sl),修改的是临时副本。

   (2) 正确 :一律传指针 void func(SeqList* psl),用 -> 访问成员。

4. 缩容的误区

   不建议在删除元素时立即缩容(频繁缩容会导致性能抖动)。业界通用做法:只扩不缩 ,或仅在剩余空间占比极低时(如 size < capacity/4)考虑缩容。


五、完整代码文件结构(项目组织)

1. 分文件编写(工业级规范)

   (1) SeqList.h ------ 头文件:结构体定义、函数声明、宏定义。

   (2) SeqList.c ------ 源文件:所有函数的具体实现。

   (3) test.c ------ 测试文件:main 函数和菜单交互。

2. 头文件中的防重复包含

c 复制代码
#ifndef _SEQLIST_H_
#define _SEQLIST_H_

// 所有声明放在这里

#endif

3. 编译命令示例(gcc)

bash 复制代码
gcc -o test SeqList.c test.c -std=c99 -Wall

六、顺序表的性能总结与适用场景

1. 时间复杂度汇总

操作 时间复杂度 备注
尾插 / 尾删 O(1) 平均情况(考虑扩容均摊后仍为 O(1))
头插 / 头删 / 任意位置插入删除 O(n) 需要移动大量元素
按位置访问 O(1) 随机访问是顺序表的最大优势
按值查找 O(n) 无序情况下必须遍历

2. 适用场景(什么时候用顺序表)

   ⓵ 需要频繁随机访问(如通过下标取第 i 个元素)。

   ⓶ 插入/删除操作只在尾部进行(栈结构)。

   ⓷ 元素个数可预估,或对内存连续有硬性要求(如 DMA 传输)。

3. 不适用场景(什么时候该换链表)

   ⓵ 频繁在头部或中间插入/删除。

   ⓶ 元素个数极其不稳定,且单个元素体积很大(扩容拷贝成本高)。

相关推荐
Kuakewei8883 小时前
平芯微42V热拔插OVP过压保护芯片:PW1600
嵌入式硬件
rannn_1113 小时前
【力扣hot100】链表专题下|138、148、23、146
java·算法·leetcode·链表·开发
wengqidaifeng3 小时前
1.从“会敲命令”到理解 Linux:15 个基础指令、文件树与命令执行的本质
linux·运维·服务器·ubuntu
ly76893 小时前
分布式一致性算法详解:从 2PC、3PC 到 Paxos、Raft、ZAB
分布式·算法
ACP广源盛139246256733 小时前
WAIC2026 国产超节点算力浪潮下@ACP#IX9104 在算力矩阵中的定位与落地场景
大数据·数据库·人工智能·嵌入式硬件·线性代数·矩阵
tedcloud1233 小时前
book-to-skill 怎么部署?把技术书和文档转换成可复用的 AI Skill
运维·服务器·人工智能·开源·ai编程
z20348315204 小时前
STM32单片机控制无源蜂鸣器播放《晴天》
stm32·单片机·嵌入式硬件
(initial)4 小时前
C-05. Kernel Fusion 代价边界:少写回 vs 寄存器压力与 occupancy
c语言·开发语言·cuda
阿维的博客日记4 小时前
保姆级教程-BBPE分词算法
算法·bbpe
那年窗外下的雪.4 小时前
AIDC 学习日志 Day 3:OSPF Underlay 实验、故障排查与深入解析
服务器·网络·php