发布时间:2026/7/14 7:02:19
数据结构-线性表第一篇
前言最近二刷了数据结构顺序表的视频课程第一遍学的时候C语言结构体、动态内存分配、指针这些基础掌握得并不扎实只是跟着敲了一遍代码似懂非懂。这次特意从头重学课件作为核心思路参考所有代码全程自己手写、调试、改错、优化把动态顺序表从基础实现到一步步排错再到封装通用打印函数的完整过程走了一遍。这是我的数据结构学习系列第一篇先从最基础的头尾增删开始后续会陆续更新指定位置插入/删除、按值查找、按位置修改等进阶操作最终会基于顺序表实现完整的通讯录项目把学到的知识真正落地。另外我的C语言基础专栏也快要更新收尾了打好C语言地基再循序渐进啃数据结构才是最稳妥的学习节奏。一、学习心得为什么要二刷顺序表顺序表是数据结构第一个线性结构底层完全依赖C语言基础如果结构体、指针、动态内存没学牢根本学不透第一遍只追求“跑起来就行”忽略了代码规范、边界校验、内存泄漏、函数封装这些细节这次重学坚持自己手写每一行代码出Bug自己排查真正理解每一步扩容、插入、删除的逻辑刻意做了代码优化把打印函数改成通用可适配类型后续改顺序表存储类型不用改打印逻辑。二、动态顺序表核心原理结合代码讲解2.1 什么是顺序表顺序表是线性表的一种它的特点是逻辑上连续物理存储上也连续底层本质就是一个数组。我们对数组进行了一层封装加上了“有效数据个数”和“容量”的管理就变成了顺序表。和原生数组相比顺序表的优势是自动管理容量满了自动扩容统一的增删改查接口不用自己手动计算下标自带边界校验减少非法访问2.2 动态顺序表结构体定义这是我自己定义的动态顺序表结构体核心三个成员分工明确// 顺序表存储类型后续改类型只改这里 typedef int SLType; // 动态顺序表结构体 typedef struct SeqList { SLType* a; // 指向动态数组的指针真正存储数据 int size; // 当前有效数据个数 int capacity; // 当前数组总容量满了就自动扩容 }SL;SLType* a用指针指向堆上开辟的动态数组这样才能实现按需扩容int size永远记录当前顺序表里有多少个有效数据所有增删操作都要更新它int capacity记录当前数组最多能存多少个数据当size capacity时触发扩容2.3 核心操作总览本篇先实现顺序表最基础的7个核心操作对应7个函数函数名功能时间复杂度SLInit初始化空顺序表O(1)Destroy销毁顺序表释放内存O(1)SLExp检测并自动扩容O (n)扩容时需要拷贝数据PushBack尾部插入O (1)均摊PushFront头部插入O(n)SLDeleteBack头部删除O(n)SLDeleteBehind尾部删除O(1)Print遍历打印顺序表O(n)后续更新预告下一篇会补充实现SLInsert指定位置插入、SLErase指定位置删除、SLFind按值查找、SLModify按位置修改4个进阶接口让顺序表功能更完整。三、我的代码迭代 排错优化过程全程手写踩坑记录这部分是我这次学习收获最大的地方每一个错误都是自己实际写代码时踩过的坑不是凭空想象的。3.1 初期手写遇到的5个硬性BugBug1头删函数数组越界崩溃错误代码// 错误写法 void SLDeleteBack(SL* ps) { assert(ps); assert(ps-size); // 错误循环条件写成了 i ps-size for (int i 0; i ps-size; i) { ps-a[i] ps-a[i 1]; } ps-size--; }错误原因当i ps-size - 1时i 1 ps-size访问了数组下标为size的元素这是非法内存直接导致程序崩溃。正确代码// 正确写法 void SLDeleteBack(SL* ps) { assert(ps); assert(ps-size); // 正确循环到 size-2 即可最后一个元素不用移动 for (int i 0; i ps-size - 1; i) { ps-a[i] ps-a[i 1]; } ps-size--; }Bug2删除函数多余参数错误代码// 错误写法多了无用参数x void SLDeleteBack(SL* ps, SLType x) void SLDeleteBehind(SL* ps, SLType x)错误原因删除操作只需要知道要删除哪个位置的元素不需要传入数据值。这个多余的参数会导致调用时必须传一个没用的数否则编译报错。正确代码// 正确写法删掉参数x void SLDeleteBack(SL* ps) void SLDeleteBehind(SL* ps)Bug3缺少指针防护断言错误代码// 错误写法没有加 assert(ps) void SLInit(SL* ps) { ps-a NULL; ps-capacity 0; ps-size 0; }错误原因如果不小心传入了NULL指针会直接野指针访问程序崩溃。正确代码// 正确写法第一行加断言校验 void SLInit(SL* ps) { assert(ps); ps-a NULL; ps-capacity 0; ps-size 0; }Bug4扩容逻辑写错错误代码// 错误写法用 size 计算新容量 int Newspace ps-capacity 0 ? 4 : 2 * ps-size;错误原因size是当前有效数据个数capacity才是数组的总容量。虽然在满容时size capacity数值上巧合相等但逻辑上必须用capacity计算。正确代码// 正确写法用 capacity 计算新容量 int Newspace ps-capacity 0 ? 4 : 2 * ps-capacity;Bug5打印函数初始版本漏洞错误代码// 错误写法 void Print(SL* ps) { assert(ps); assert(ps-size); // 错误1空表不能打印 // 错误2少打印最后一个元素 for (int i 0; i ps-size - 1; i) { printf(%d , ps-a[i]); // 错误3格式符写死 } }错误原因空表也应该能打印直接输出空行即可不能断言崩溃循环条件i ps-size - 1会少打印最后一个元素格式符写死为%d改SLType类型就要改打印代码3.2 关键优化通用打印函数实现为了解决“改SLType类型就要改printf格式符”的问题我用宏定义做了一层封装实现了真正通用的打印函数。第一步头文件添加打印格式宏// 通用打印格式宏切换类型只改这里 #define SLTYPE_PRINT_FMT %d // 顺序表存储类型 typedef int SLType;第二步通用打印函数// 通用打印函数适配任意SLType类型 void Print(SL* ps) { assert(ps); for (int i 0; i ps-size; i) { // 直接引用宏自动匹配对应格式 printf(SLTYPE_PRINT_FMT , ps-a[i]); } printf(\n); }切换类型示例如果想改成存储float类型只需要改头文件两行#define SLTYPE_PRINT_FMT %f typedef float SLType;其他所有代码包括打印函数完全不用动直接编译运行即可。3.3 工程化优化多文件拆分我严格按照C语言工程规范把代码拆分成了三个独立文件SeqList.h头文件存放结构体定义、类型别名、宏定义、函数声明SeqList.c源文件存放所有功能函数的具体实现test.c测试文件单独存放主函数专门用来测试所有接口这样拆分的好处是代码结构清晰便于维护接口和实现分离后续修改实现不影响接口测试代码和业务代码解耦不会互相干扰四、完整最终代码本人手写版4.1 SeqList.h 头文件#pragma once #includestdio.h #includestdlib.h #includeassert.h // 通用打印格式宏切换类型只改这里 #define SLTYPE_PRINT_FMT %d // 顺序表存储类型 typedef int SLType; // 动态顺序表结构体 typedef struct SeqList { SLType* a; int size; // 有效数据个数 int capacity; // 储存空间总容量 }SL; // 初始化和销毁 void SLInit(SL* ps); void Destroy(SL* ps); void Print(SL* ps); // 扩容检测 void SLExp(SL* ps); // 头部操作 void PushFront(SL* ps, SLType x); // 头部插入 void SLDeleteBack(SL* ps); // 头部删除 // 尾部操作 void PushBack(SL* ps, SLType x); // 尾部插入 void SLDeleteBehind(SL* ps); // 尾部删除4.2 SeqList.c 功能实现文件#includeSeqList.h // 初始化顺序表 void SLInit(SL* ps) { assert(ps); ps-a NULL; ps-capacity 0; ps-size 0; } // 销毁顺序表释放动态内存 void Destroy(SL* ps) { assert(ps); if (ps-a) { free(ps-a); ps-a NULL; ps-capacity 0; ps-size 0; } } // 检测并自动扩容 void SLExp(SL* ps) { assert(ps); if (ps-capacity ps-size) { int Newspace ps-capacity 0 ? 4 : 2 * ps-capacity; SLType* Newps (SLType*)realloc(ps-a, Newspace * sizeof(SLType)); if (Newps NULL) { perror(Failed to apply for space); exit(1); } ps-a Newps; ps-capacity Newspace; } } // 尾部插入 void PushBack(SL* ps, SLType x) { assert(ps); SLExp(ps); ps-a[ps-size] x; } // 头部插入 void PushFront(SL* ps, SLType x) { assert(ps); SLExp(ps); // 元素后移从最后一个元素开始往前移 for (int i ps-size; i 0; i--) { ps-a[i] ps-a[i - 1]; } ps-a[0] x; ps-size; } // 头部删除 void SLDeleteBack(SL* ps) { assert(ps); assert(ps-size); // 元素前移覆盖第一个元素 for (int i 0; i ps-size - 1; i) { ps-a[i] ps-a[i 1]; } ps-size--; } // 尾部删除 void SLDeleteBehind(SL* ps) { assert(ps); assert(ps-size); // 逻辑删除只需要把有效数据个数减1 ps-size--; } // 通用打印函数适配任意SLType类型 void Print(SL* ps) { assert(ps); for (int i 0; i ps-size; i) { printf(SLTYPE_PRINT_FMT , ps-a[i]); } printf(\n); }4.3 test.c独立测试文件#include SeqList.h int main() { // 定义顺序表变量 SL sl; // 初始化 SLInit(sl); printf( 顺序表初始化完成 \n\n); // 测试尾插 printf(----- 测试尾插 -----\n); PushBack(sl, 10); PushBack(sl, 20); PushBack(sl, 30); PushBack(sl, 40); printf(尾插 10 20 30 40 后); Print(sl); printf(\n); // 测试头插 printf(----- 测试头插 -----\n); PushFront(sl, 5); PushFront(sl, 1); printf(头插 5 1 后); Print(sl); printf(\n); // 测试尾删 printf(----- 测试尾删 -----\n); SLDeleteBehind(sl); SLDeleteBehind(sl); printf(尾删2次后); Print(sl); printf(\n); // 测试头删 printf(----- 测试头删 -----\n); SLDeleteBack(sl); printf(头删1次后); Print(sl); printf(\n); // 释放内存 printf( 顺序表销毁完成 \n); Destroy(sl); return 0; }五、编译运行输出结果5.1编译命令gcc test.c SeqList.c -o SeqList5.2运行输出 顺序表初始化完成 ----- 测试尾插 ----- 尾插 10 20 30 40 后10 20 30 40 ----- 测试头插 ----- 头插 5 1 后1 5 10 20 30 40 ----- 测试尾删 ----- 尾删2次后1 5 10 20 ----- 测试头删 ----- 头删1次后5 10 20 顺序表销毁完成 六、学习总结与后续更新计划基础是重中之重顺序表卡壳本质是C语言结构体、指针、动态内存没学牢。二刷补完短板后写代码顺畅很多也能理解为什么要这么写。拒绝复制粘贴课件只看思路代码自己手写、自己排错印象远比抄代码深刻。每一个 Bug都是一次宝贵的学习机会。注重代码质量不只是实现功能还要考虑健壮性assert断言、可扩展性通用打印宏、工程规范多文件拆分。后续更新计划下一篇实现顺序表进阶接口——SLInsert指定位置插入、SLErase指定位置删除、SLFind按值查找、SLModify按位置修改再下一篇基于完整的顺序表接口实现一个可增删改查的通讯录项目长期规划继续学习链表、栈、队列、二叉树等数据结构坚持每一个知识点都手写实现踩坑记录的形式沉淀扎实的基础初学数据结构不要追求进度慢一点、写一遍、改一遍、优化一遍远比快速刷完视频有用得多。

相关新闻

Actus F8一键神器:鼠标连点与键盘自动化全攻略
2026/7/14 6:02:19

Actus F8一键神器:鼠标连点与键盘自动化全攻略

# Actus F8一键神器:鼠标连点与键盘自动化全攻略在重复性任务泛滥的数字化时代,无论是游戏挂机、办公数据录入,还是软件测试中的高频点击,自动化工具已成为提升效率的利器。今天,我们将深入剖析一款免费且轻量级的自动…

阅读更多
实体商家AI实战:批量打造爆款内容,零基础搭建可盈利个人IP账号
2026/7/14 6:02:19

实体商家AI实战:批量打造爆款内容,零基础搭建可盈利个人IP账号

# 实体商家AI实战:批量打造爆款内容,零基础搭建可盈利个人IP账号## 引言在流量红利见顶、获客成本飙升的2025年,实体商家面临前所未有的挑战:线下客流锐减,线上推广又苦于不懂内容、不会剪辑、没时间运营。但与此同时&…

阅读更多
macOS上ROS 2与Webots协同仿真的双环境架构实践
2026/7/14 6:02:19

macOS上ROS 2与Webots协同仿真的双环境架构实践

1. 项目概述:为什么 macOS 上的 ROS 2 Webots 要走“主机虚拟机”双环境路线?你正在看的,是一份面向 macOS 用户、专为运行webots_ros2仿真系统而设计的实操指南。关键词里那个“L5 | Tutorials > Advanced > Simulators > Webots …

阅读更多
如何快速上手Mistral-7B-Instruct-v0.2_rai_1.7.1_hybrid?Ryzen AI本地部署完整指南
2026/7/14 9:02:19

如何快速上手Mistral-7B-Instruct-v0.2_rai_1.7.1_hybrid?Ryzen AI本地部署完整指南

如何快速上手Mistral-7B-Instruct-v0.2_rai_1.7.1_hybrid?Ryzen AI本地部署完整指南 【免费下载链接】Mistral-7B-Instruct-v0.2_rai_1.7.1_hybrid 项目地址: https://ai.gitcode.com/hf_mirrors/amd/Mistral-7B-Instruct-v0.2_rai_1.7.1_hybrid Mistral-7B…

阅读更多
TB67H480FNG与MKV42F128VLH16电机控制方案解析
2026/7/14 9:02:19

TB67H480FNG与MKV42F128VLH16电机控制方案解析

1. TB67H480FNG与MKV42F128VLH16的黄金组合解析 在电机控制与嵌入式系统开发领域,选择合适的驱动芯片和微控制器往往决定着项目的成败。TB67H480FNG作为东芝(Toshiba)推出的双通道有刷直流电机驱动IC,搭配NXP的MKV42F128VLH16微控制器,形成了…

阅读更多
ICM-45605 IMU与PIC18F86K22的嵌入式姿态感知系统设计
2026/7/14 9:02:19

ICM-45605 IMU与PIC18F86K22的嵌入式姿态感知系统设计

1. 项目背景与核心器件选型在AR/VR、无人机和机器人等需要精准姿态感知的应用场景中,惯性测量单元(IMU)的性能直接决定了运动追踪的准确性和稳定性。ICM-45605作为TDK InvenSense最新推出的6轴IMU传感器,凭借其3mm3mm0.81mm的超小封装尺寸和低至0.81mm的…

阅读更多
如何快速部署SmolLM2-135M-Instruct_rai_1.7.1_hybrid模型?基于Ryzen AI的完整指南
2026/7/14 9:02:19

如何快速部署SmolLM2-135M-Instruct_rai_1.7.1_hybrid模型?基于Ryzen AI的完整指南

如何快速部署SmolLM2-135M-Instruct_rai_1.7.1_hybrid模型?基于Ryzen AI的完整指南 【免费下载链接】SmolLM2-135M-Instruct_rai_1.7.1_hybrid 项目地址: https://ai.gitcode.com/hf_mirrors/amd/SmolLM2-135M-Instruct_rai_1.7.1_hybrid 想要在AMD Ryzen A…

阅读更多
如何快速集成PullToBounce:iOS开发者的完整指南
2026/7/14 9:02:19

如何快速集成PullToBounce:iOS开发者的完整指南

如何快速集成PullToBounce:iOS开发者的完整指南 【免费下载链接】PullToBounce Animated "Pull To Refresh" Library for UIScrollView. Inspired by https://dribbble.com/shots/1797373-Pull-Down-To-Refresh 项目地址: https://gitcode.com/gh_mirro…

阅读更多
JDspyder京东抢购脚本:3分钟轻松部署,告别手动抢购的烦恼
2026/7/14 8:02:19

JDspyder京东抢购脚本:3分钟轻松部署,告别手动抢购的烦恼

JDspyder京东抢购脚本:3分钟轻松部署,告别手动抢购的烦恼 【免费下载链接】JDspyder 京东预约&抢购脚本,可以自定义商品链接 项目地址: https://gitcode.com/gh_mirrors/jd/JDspyder 还在为京东秒杀抢不到心仪商品而烦恼吗&#x…

阅读更多
智慧树刷课插件:5分钟实现自动化学习的智能助手
2026/7/14 6:43:28

智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 智慧树刷课插件是一款专为智慧树在线教育平台设计的Chrome浏…

阅读更多
Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案
2026/7/12 0:01:57

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在GOG或Epic Games Store购买了心仪的游戏…

阅读更多
办公自动化实战:5个免费工具构建合同处理流水线
2026/7/13 17:34:38

办公自动化实战:5个免费工具构建合同处理流水线

1. 这不是“又一个工具包”,而是一套经过237次真实场景验证的效率组合拳“2026.04.28实用教程工具分享”这个标题乍看平平无奇,像极了你邮箱里被自动归入“促销/订阅”文件夹的那类通知——但如果你真把它当普通更新忽略,接下来半年里&#x…

阅读更多
DeepSeek提示词效果暴跌预警:当LLM置信度低于0.62时,必须启用的4层动态重写机制
2026/7/14 0:02:17

DeepSeek提示词效果暴跌预警:当LLM置信度低于0.62时,必须启用的4层动态重写机制

更多请点击: https://codechina.net 第一章:DeepSeek提示词效果暴跌预警:当LLM置信度低于0.62时,必须启用的4层动态重写机制 当DeepSeek-R1或DeepSeek-V3模型返回的token级置信度(logits softmax归一化后最大概率值&a…

阅读更多
Perplexity vs ChatGPT vs Claude:实测127组复杂查询任务,谁才是真正可靠的“事实型AI助手”?
2026/7/14 0:02:17

Perplexity vs ChatGPT vs Claude:实测127组复杂查询任务,谁才是真正可靠的“事实型AI助手”?

更多请点击: https://codechina.net 第一章:Perplexity 怎么用 Perplexity 是衡量语言模型预测能力的核心指标,数值越低表示模型对文本序列的不确定性越小、预测越精准。它本质上是交叉熵损失的指数形式,计算公式为:…

阅读更多
AD74412R与STM32F407ZG在工业信号采集中的高效应用
2026/7/14 0:02:17

AD74412R与STM32F407ZG在工业信号采集中的高效应用

1. 为什么选择AD74412R与STM32F407ZG组合?在工业控制和嵌入式系统设计中,信号采集与处理的实时性、精度和稳定性往往是核心挑战。AD74412R作为ADI公司推出的四通道软件可配置I/O解决方案,与STMicroelectronics的STM32F407ZG高性能微控制器组合…

阅读更多
基于Dify与DeepSeek构建私有知识库问答系统实战指南
2026/7/13 21:11:56

基于Dify与DeepSeek构建私有知识库问答系统实战指南

在业务中快速构建一个能理解私有文档、准确回答专业问题的智能助手,是很多开发团队面临的共同挑战。传统方案往往需要从零开始搭建复杂的 RAG(检索增强生成)系统,涉及文档解析、向量化、检索、大模型调用等多个环节,整…

阅读更多
FAE放射组学分析工具:医学影像特征探索的完整解决方案
2026/7/13 1:50:37

FAE放射组学分析工具:医学影像特征探索的完整解决方案

FAE放射组学分析工具:医学影像特征探索的完整解决方案 【免费下载链接】FAE FeAture Explorer 项目地址: https://gitcode.com/gh_mirrors/fae/FAE 你是否曾经面对海量医学影像数据感到无从下手?想要从CT、MRI等影像中提取有价值的定量特征&#…

阅读更多
DesktopNaotu:你的终极离线思维导图解决方案,告别网络依赖!
2026/7/13 13:09:00

DesktopNaotu:你的终极离线思维导图解决方案,告别网络依赖!

DesktopNaotu:你的终极离线思维导图解决方案,告别网络依赖! 【免费下载链接】DesktopNaotu 桌面版脑图 (百度脑图离线版,思维导图) 跨平台支持 Windows/Linux/Mac OS. (A cross-platform multilingual Mind Map Tool) 项目地址:…

阅读更多