跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C算法

数据结构初阶:顺序表的概念与动态实现

介绍数据结构基础概念及顺序表的实现。涵盖顺序表定义、分类(静态/动态),重点讲解动态顺序表在 C 语言中的核心操作,包括初始化、销毁、尾插、头插、尾删、头删及空间检查函数的具体代码实现与逻辑分析。

云朵棉花糖发布于 2026/3/30更新于 2026/5/2321 浏览
数据结构初阶:顺序表的概念与动态实现

数据结构初阶:顺序表专题

图片

1. 数据结构相关概念

1. 什么是数据结构

数据结构由'数据'和'结构'组合而来。

什么是数据? 常见的数值(1、2、3...)、教务系统里保存的用户信息(姓名、性别、年龄等)、网页里肉眼可见的信息(文字、图片、视频等),这些都是数据。

什么是结构? 当我们想要使用大量同一类型的数据时,通过手动定义大量的独立变量对于程序来说可读性非常差。我们可以借助数组这样的数据结构将大量的数据组织在一起。结构也可以理解为组织数据的方式。

想要找到草原上名叫'咩咩'的羊很难,但是从羊圈里找到 1 号羊就很简单,羊圈这样的结构有效将羊群组织起来。

概念: 数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。数据结构反映数据的内部构成,即数据由那部分构成,以什么方式构成,以及数据元素之间呈现的结构。

图片

图片

总结:

  1. 能够存储数据(如顺序表、链表等结构)
  2. 存储的数据能够方便查找

2. 为什么需要数据结构?

图片

如图所示,不借助排队的方式来管理客户,会导致客户就餐感受差、等餐时间长、餐厅营业混乱等情况。同理,程序中如果不对数据进行管理,可能会导致数据丢失、操作数据困难、野指针等情况。通过数据结构,能够有效将数据组织和管理在一起。按照我们的方式任意对数据进行增删改查等操作。

最基础的数据结构:数组。

图片

【思考】 有了数组,为什么还要学习其他的数据结构?

假定数组有 10 个空间,已经使用了 5 个,向数组中插入数据步骤:求数组的长度,求数组的有效数据个数,向下标为数据有效个数的位置插入数据(注意:这里是否要判断数组是否满了,满了还能继续插入吗)…

假设数据量非常庞大,频繁的获取数组有效数据个数会影响程序执行效率。

结论: 最基础的数据结构能够提供的操作已经不能完全满足复杂算法实现。

2. 顺序表

1. 顺序表的概念及结构

顺序表是线性表的一种

线性表有物理结构和逻辑结构。 线性表的物理结构不一定连续,但逻辑结构一定连续。

那什么是线性表呢? 线性表(linear list)是 n 个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

案例:蔬菜分为绿叶类、瓜类、菌菇类。 线性表指的是具有部分相同特性的一类数据结构的集合。

顺序表的物理结构跟逻辑结构都是连续的

2. 顺序表分类

  • 顺序表和数组的区别
    • 顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口
  • 顺序表分类
    • 静态顺序表 图片
    • 动态顺序表 图片

3. 动态顺序表的实现

图片

先创建一个头文件用来声明函数,两个 .c 文件,SeqList.c 顺序表的实现,test.c 用来测试。

1. 定义一个动态顺序表
typedef struct SeqList // sequence 顺序的
{
    SLDataType* arr;
    int size;      // 有效数据个数
    int capacity;  // 空间大小
} SL; // SeqList 太长 我们把他换成 SL

因为我们不知道以后使用时要用什么类型的数据,所以我们最好给数据类型起一个别名。

typedef int SLDataType;
2. 顺序表的初始化
void SLInit(SL *s)
{
    s->arr = NULL;
    s->size = s->capacity = 0;
}

注意: 这里函数传参一定要用地址传参。

3. 顺序表的销毁
void SLDestroy(SL* ps)
{
    if (ps->arr)
    {
        free(ps->arr);
    }
    ps->arr = NULL;
    ps->size = ps->capacity = 0;
}
4. 顺序表的尾插
void SLPushBack(SL* ps, SLDataType x)
{
    assert(ps); // 表达式为真,继续执行;表达式假,程序报错
    
    // 插入之前先看空间够不够
    if (ps->size == ps->capacity)
    {
        // 申请空间
        // 只有 realloc 可以增容
        // 增容通常是成倍数的增加,一般是 2 倍或 3 倍,不能频繁增容,会造成性能降低
        int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
        SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));
        
        // 用临时变量来接收,防止内存开辟失败数据丢失
        if (tmp == NULL)
        {
            perror("realloc fail");
            exit(1); // 直接退出程序,不再执行
        }
        
        // 空间申请成功
        ps->arr = tmp;
        ps->capacity = newcapacity;
    }
    ps->arr[ps->size++] = x;
}

图片

5. 顺序表的头插
void SLPushFront(SL* ps, SLDataType x)
{
    assert(ps);
    SLCheckCapacity(ps); // 先让顺序表中数据整体后移一位
    
    for (int i = ps->size; i > 0; i--)
    {
        ps->arr[i] = ps->arr[i - 1]; // arr[1]=arr[0]
    }
    ps->arr[0] = x;
    ps->size++; // 加了一个数据
}

图片

6. 空间大小检查函数

我们注意到在头插跟尾插中都检查了空间的大小,所以我们可以把它封装成函数。

void SLCheckCapacity(SL* ps)
{
    if (ps->size == ps->capacity)
    {
        // 申请空间
        // 只有 realloc 可以增容
        // 增容通常是成倍数的增加,一般是 2 倍或 3 倍,不能频繁增容,会造成性能降低
        int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
        SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));
        
        if (tmp == NULL)
        {
            perror("realloc fail");
            exit(1); // 直接退出程序,不再执行
        }
        
        // 空间申请成功
        ps->arr = tmp;
        ps->capacity = newcapacity;
    }
}
7. 顺序表的尾删
void SLPopBack(SL* ps)
{
    assert(ps);
    assert(ps->size); // 判断顺序表是否为空
    // ps->arr[ps->size - 1] = -1;
    ps->size--;
}
8. 顺序表的头删
void SLPopFront(SL* ps)
{
    assert(ps);
    assert(ps->size);
    
    for (int i = 0; i < ps->size - 1; i++)
    {
        ps->arr[i] = ps->arr[i + 1]; // 逐个向前替换,最后一个是 arr[size-2]=arr[size-1]
    }
    ps->size--; // 这个不能忘
}
9. 测试示例
#include "SeqList.h"

// 打印函数原型
void SLPrintf(SL s);

void SLTest01()
{
    SL sl;
    SLInit(&sl); // 这里要传地址,传值(值拷贝)这都没有初始化,没有值
    
    SLPushBack(&sl, 1); // 尾插
    SLPushBack(&sl, 2);
    SLPushBack(&sl, 3);
    SLPushBack(&sl, 4);
    SLPrintf(sl); // 打印函数
    
    // 头插
    SLPushFront(&sl, 5);
    SLPushFront(&sl, 6);
    SLPrintf(sl);
    
    // 尾删
    SLPopBack(&sl);
    SLPrintf(sl);
    
    // 头删
    SLPopFront(&sl);
    SLPopFront(&sl);
    SLPopFront(&sl);
    SLPrintf(sl);
    
    SLDestroy(&sl); // 销毁
}

int main()
{
    SLTest01();
    return 0;
}

图片

void SLPrintf(SL s) // 上文中的打印函数,这里不是对底层的修改,所以传值即可
{
    for (int i = 0; i < s.size; i++)
    {
        printf("%d ", s.arr[i]);
    }
    printf("\n");
}

目录

  1. 数据结构初阶:顺序表专题
  2. 1. 数据结构相关概念
  3. 1. 什么是数据结构
  4. 2. 为什么需要数据结构?
  5. 2. 顺序表
  6. 1. 顺序表的概念及结构
  7. 2. 顺序表分类
  8. 3. 动态顺序表的实现
  9. 1. 定义一个动态顺序表
  10. 2. 顺序表的初始化
  11. 3. 顺序表的销毁
  12. 4. 顺序表的尾插
  13. 5. 顺序表的头插
  14. 6. 空间大小检查函数
  15. 7. 顺序表的尾删
  16. 8. 顺序表的头删
  17. 9. 测试示例
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 自然语言处理在社交媒体分析领域的应用与实战
  • 深度强化学习基础架构与核心算法实现
  • 基于机器学习的生态组合塘强化城市污水处理厂脱氮优化
  • Flutter 技术优势显著但市场普及度为何滞后?
  • AI 辅助生成前端原型:从需求文档到交互界面自动化流程
  • 基于 Stable Diffusion 与 YOLOv5 的智能安防原型搭建实战
  • OpenWebUI 联网搜索实战:用 SearXNG 让本地大模型获取实时信息
  • 从建筑工地转行 Python 开发的经历与感悟
  • Trae 配置 Java 环境并运行 SpringBoot 项目
  • Jenkins 核心概念、Pipeline 脚本与运维实战指南
  • 构建并微调大型语言模型实现文本分类任务
  • 银行智能营销助手架构:知识图谱与大模型融合应用
  • Claude Code的完美平替:OpenCode + GitHub Copilot
  • FreeCAD Python API 入门与实战指南
  • 二叉树算法实战:美国血统重建与深度宽度计算
  • 金仓 KingbaseES 融合架构实践:告别多库并存,实现一库多能
  • PyTorch 文本引导图像生成与 Stable Diffusion 实践
  • MaaS 模型选型指南:利用 AI Ping 进行性能评测与供应商筛选
  • 反爬虫:机器人点选验证原理及网站设计
  • Ubuntu 24.04 安装 ROS 2 Jazzy 版本实战指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online