重庆沙坪坝火车站注册公司名称大全免费
2026/4/18 14:28:53 网站建设 项目流程
重庆沙坪坝火车站,注册公司名称大全免费,百度seo关键词排名优化工具,wordpress链接选项不见了引入各位新手小伙伴#xff0c;咱们学完结构体、指针和动态内存管理后#xff0c;是不是总觉得这些知识点 “飘着”#xff0c;不知道怎么落地#xff1f;今天要讲的顺序表#xff0c;就是把这些知识点串起来的 “实战神器”#xff01;你可以把顺序表理解成 “升级版数组…引入各位新手小伙伴咱们学完结构体、指针和动态内存管理后是不是总觉得这些知识点 “飘着”不知道怎么落地今天要讲的顺序表就是把这些知识点串起来的 “实战神器”你可以把顺序表理解成“升级版数组”—— 生活中咱们用的购物清单、待办事项列表本质上都是 “线性” 的一个接一个排顺序表就是用 C 语言把这种 “线性列表” 实现出来的工具学会它你才算真正打通 C 语言 “数据存储” 的任督二脉课前准备新手必看缺一个都容易卡壳1. 必须掌握的基础知识点划重点结构体能定义 “包含多个属性的自定义类型”比如顺序表要存数据 容量 长度指针懂 “地址” 和 “解引用”尤其是动态内存的指针操作malloc/calloc/realloc动态内存管理会申请malloc、扩容realloc、释放free内存知道内存泄漏的坑。✅ 易错点如果连 “结构体怎么定义”“指针怎么指向动态内存” 都模糊先回头补顺序表全程靠这仨知识点撑着基础不牢直接学等于 “空中建楼”。2. 数据结构小概念用大白话讲数据结构简单说就是 “数据怎么存、怎么取” 的规则顺序表是最基础的线性数据结构核心思想“连续存储、随机访问”—— 就像电影院座位按号排找第 5 个座位不用挨个数直接定位。一、顺序表的核心概念先搞懂 “是什么”1.1 线性表顺序表的 “祖宗”线性表是一种“数据排成一条线”的结构特点是除了第一个元素每个元素都有 “前一个”除了最后一个每个元素都有 “后一个”。生活例子排队买奶茶的队伍、一串糖葫芦、咱们的学号列表都是线性表。顺序表是线性表的 “亲儿子”—— 用 “连续的内存空间” 实现的线性表是最容易上手的实现方式。1.2 顺序表和数组的区别新手最易混淆很多新手会问“顺序表不就是数组吗” 大错特错两者核心区别看这张表对比维度普通数组顺序表大小固定不变定义时就定了动态扩容不够用自动加额外信息只存数据存数据 容量 当前长度操作灵活性增删元素要手动挪数据封装增删查改函数更易用✅ 易错点别把 “int arr [10]” 当成顺序表普通数组满了就塞不进去顺序表能 “自动扩容”这是最核心的差异。二、顺序表的分类静态 vs 动态新手优先学动态顺序表分两种静态是 “入门款”动态是 “实战款”咱们先认清楚2.1 静态顺序表了解即可实际开发几乎不用定义用 “固定大小的数组” 实现结构体里直接定死容量。例子// 静态顺序表定义 #define N 100 typedef struct SeqList { int data[N]; // 固定存100个int数据 int size; // 当前存了多少个元素 } SeqList;❌ 缺点容量固定存满了就废比如定义 N100存 101 个数据就会越界新手容易踩 “数组越界” 的坑。✅ 易错点静态顺序表的 size 不能超过 N否则会访问非法内存直接崩2.2 动态顺序表重点工作 / 面试都考这个定义用 “动态内存数组” 实现容量不够时用 realloc 扩容灵活不浪费内存。核心思想“按需分配”—— 就像买行李箱小了就换个大的不用一开始就买最大的。例子先眼熟后面会详解// 动态顺序表定义新手记这个模板 typedef struct SeqList { int* data; // 指向动态申请的内存存数据 int capacity;// 总容量最多能存多少 int size; // 当前已存元素个数size ≤ capacity } SeqList;✅ 易错点初始化时data 要先置 NULL避免野指针capacity 和 size 要分清capacity 是 “总座位数”size 是 “已坐人数”size 永远不能超过 capacity扩容后要检查是否扩容成功realloc 失败会返回 NULL。三、手撕动态顺序表从 0 到 1 实现新手跟着敲咱们的目标实现一个能 “增删查改、动态扩容” 的顺序表先定规则数据类型先存 int新手易上手后面可改成 typedef 通用类型核心操作创建→初始化→增→删→查→销毁一步都不能少。3.1 第一步定义顺序表结构基础中的基础先把 “架子” 搭好用 typedef 给结构体起别名方便后续用// 建议把类型重定义后续改类型只改这里 typedef int SLDateType; // 动态顺序表结构体 typedef struct SeqList { SLDateType* data; // 动态内存指针 int capacity; // 容量最多能存多少元素 int size; // 有效元素个数当前存了多少 } SeqList;✅ 易错点别漏了 typedef直接写 struct SeqList 太麻烦新手容易忘加导致后续写代码重复写 struct。3.2 第二步定义核心操作函数按 “从易到难” 排序3.2.1 初始化顺序表比 “创建” 更重要新手误区以为 “创建” 是单独的函数其实顺序表的 “创建” 就是 “定义变量 初始化”。初始化的目标把 data 置 NULLcapacity 和 size 置 0避免野指针和随机值。// 初始化顺序表 void SeqListInit(SeqList* sl) { // 易错点一定要检查指针是否为空 if (sl NULL) { printf(指针为空初始化失败\n); return; } sl-data NULL; sl-capacity 0; sl-size 0; }✅易错点传参必须传 “顺序表的地址”SeqList*如果传 SeqList值传递函数里改的是副本外面完全没变化3.2.2 扩容函数封装起来增元素时复用顺序表的核心优势是 “动态扩容”把扩容逻辑单独封装避免重复代码// 扩容函数当容量不够时扩容到原来的2倍新手默认规则 void SeqListCheckCapacity(SeqList* sl) { if (sl NULL) return; // 容量为0初始化后或size等于capacity存满了需要扩容 if (sl-size sl-capacity) { // 新容量第一次扩容设为4之后每次翻倍 int newCapacity sl-capacity 0 ? 4 : sl-capacity * 2; // 扩容realloc是在原来的内存基础上扩NULL时等价于malloc SLDateType* newData (SLDateType*)realloc(sl-data, newCapacity * sizeof(SLDateType)); // 易错点检查扩容是否成功realloc失败会返回NULL if (newData NULL) { perror(realloc扩容失败); // 打印错误原因 exit(1); // 直接退出避免后续操作崩 } sl-data newData; // 指向新内存 sl-capacity newCapacity; // 更新容量 } }✅ 易错点扩容后一定要把newData 赋值给 sl-data别直接用 sl-data realloc (...)万一 realloc 失败原来的 data 会丢第一次扩容capacity0要特殊处理否则 newCapacity 会是 0扩了个寂寞。3.2.3 插入元素先学简单的尾插 → 头插 → 指定位置插插入的核心逻辑先扩容 → 挪数据头插 / 指定插需要 → 存数据 → size1。3.2.3.1 尾插最简单新手先练这个尾插直接把元素放到最后一个有效元素的后面不用挪数据// 尾插在顺序表最后加元素 void SeqListPushBack(SeqList* sl, SLDateType x) { if (sl NULL) return; // 先检查容量不够就扩容 SeqListCheckCapacity(sl); // 存数据size的位置就是最后一个位置下标从0开始 sl-data[sl-size] x; // 有效元素个数1 sl-size; }✅ 例子顺序表现有 [1,2,3]size3尾插 4 后变成 [1,2,3,4]size4。✅ 易错点别写成 sl-data [sl-size] x; 新手容易搞混顺序先赋值再 更清晰。3.2.3.2 头插需要挪数据新手易出错头插把所有元素往后挪一位把新元素放到第一个位置下标 0。// 头插在顺序表最前面加元素 void SeqListPushFront(SeqList* sl, SLDateType x) { if (sl NULL) return; // 先扩容 SeqListCheckCapacity(sl); // 核心从最后一个元素开始往后挪一位避免覆盖 // 易错点循环要从size-1开始到0结束 for (int i sl-size; i 0; i--) { sl-data[i] sl-data[i-1]; } // 新元素放到下标0的位置 sl-data[0] x; sl-size; }✅ 例子顺序表现有 [1,2,3]头插 0先把 1→下标 12→下标 23→下标 3再把 0 放到下标 0结果 [0,1,2,3]。❌ 易错点循环从 0 开始挪比如先挪 data [0] 到 data [1]会把 data [1] 的 2 覆盖成 1最后变成 [0,1,1,1]全错3.2.3.3 指定位置前插入头插 / 尾插的 “通用版”新手进阶插入到 “第 pos 个位置” 前面pos 是下标从 0 开始比如 pos2就插在原来下标 2 的元素前面。// 指定位置插入在pos下标前插入xpos范围0 ≤ pos ≤ size void SeqListInsert(SeqList* sl, int pos, SLDateType x) { if (sl NULL) return; // 易错点1检查pos是否合法 if (pos 0 || pos sl-size) { printf(pos位置非法\n); return; } // 扩容 SeqListCheckCapacity(sl); // 核心从最后一个元素开始往后挪到pos1的位置 for (int i sl-size; i pos; i--) { sl-data[i] sl-data[i-1]; } // 插入数据 sl-data[pos] x; sl-size; }✅ 技巧尾插 SeqListInsert (sl, sl-size, x)头插 SeqListInsert (sl, 0, x)学会这个头插尾插可以不用单独写❌ 易错点pos 不能大于 size比如 size3pos 最大是 3尾插pos4 就是非法位置。3.2.4 删除元素先学尾删 → 头删 → 指定位置删删除的核心逻辑检查是否为空 → 挪数据头删 / 指定删需要 → size-1不用真删数据覆盖即可。3.2.4.1 尾删最简单尾删直接把 size-1最后一个元素 “失效”不用挪数据// 尾删删除最后一个元素 void SeqListPopBack(SeqList* sl) { if (sl NULL) return; // 易错点检查顺序表是否为空空表不能删 if (sl-size 0) { printf(顺序表为空无法尾删\n); return; } // 直接size-1最后一个元素就访问不到了 sl-size--; }✅ 例子顺序表 [1,2,3]size3尾删后 size2只剩 [1,2]data [2] 的 3 还在但 size3访问不到。3.2.4.2 头删需要挪数据新手易错头删把所有元素往前挪一位覆盖第一个元素size-1。// 头删删除第一个元素 void SeqListPopFront(SeqList* sl) { if (sl NULL) return; // 空表不能删 if (sl-size 0) { printf(顺序表为空无法头删\n); return; } // 核心从下标1开始往前挪一位 for (int i 0; i sl-size-1; i) { sl-data[i] sl-data[i1]; } sl-size--; }✅ 例子顺序表 [1,2,3]头删后2→下标 03→下标 1size2结果 [2,3]。❌ 易错点循环条件别写成 i sl-size会导致 i1 越界比如 i2i13超过 size-12。3.2.4.3 删除指定位置的数据// 删除pos下标位置的元素pos范围0 ≤ pos size void SeqListErase(SeqList* sl, int pos) { if (sl NULL) return; // 检查pos合法 if (pos 0 || pos sl-size) { printf(pos位置非法\n); return; } // 空表不能删 if (sl-size 0) { printf(顺序表为空无法删除\n); return; } // 核心从pos1开始往前挪一位 for (int i pos; i sl-size-1; i) { sl-data[i] sl-data[i1]; } sl-size--; }✅ 技巧尾删 SeqListErase (sl, sl-size-1)头删 SeqListErase (sl, 0)通用版更实用3.2.5 顺序表的查找实战常用查找指定元素返回其下标没找到返回 - 1。// 查找元素x找到返回下标没找到返回-1 int SeqListFind(SeqList* sl, SLDateType x) { if (sl NULL) return -1; // 遍历顺序表 for (int i 0; i sl-size; i) { if (sl-data[i] x) { return i; // 找到返回下标 } } return -1; // 没找到 }✅ 例子顺序表 [1,2,3]查找 2 返回 1查找 4 返回 - 1。✅ 拓展新手可以试试 “查找所有匹配的元素”“返回第一个 / 最后一个匹配的下标”练手更到位。3.2.6 销毁顺序表重中之重避免内存泄漏动态内存申请了必须释放否则程序结束后内存不会自动还这就是 “内存泄漏”// 销毁顺序表释放动态内存恢复初始状态 void SeqListDestroy(SeqList* sl) { if (sl NULL) return; // 释放data指向的动态内存 free(sl-data); sl-data NULL; // 易错点释放后一定要置NULL避免野指针 sl-capacity 0; sl-size 0; }❌ 易错点只 free 不置 NULLfree 后 data 还是指向原来的内存地址变成野指针后续如果误操作会导致程序崩溃。四、新手实战小技巧避坑 提效写代码时先写 “框架”先定义结构体→初始化→扩容→增删查改→销毁一步一步来调试时打印 “capacity 和 size”比如插入后打印 size删除后打印 size能快速发现 “越界”“没扩容” 的问题别贪多先实现 “尾插、尾删、头插、头删”再搞指定位置操作新手一口吃不成胖子内存泄漏检查Windows 用 VS 的 “内存检测”Linux 用 valgrind写完一定要查结束语恭喜你学完顺序表你已经从 “只会写单个函数” 的新手升级成 “能实现完整数据结构” 的准大佬了顺序表的核心就两点“连续内存” 和 “动态扩容”今天学的 int 类型顺序表只是入门后续你可以把 SLDateType 改成 char、结构体比如存学生信息甚至实现 “通用顺序表”用 void*。记住数据结构的本质是 “解决问题的思路”顺序表虽然简单但它是链表、栈、队列的基础把它吃透后面学更复杂的数据结构会轻松 10 倍现在就动手敲代码吧 —— 先写初始化和尾插再写头插遇到 bug 别慌打印中间结果新手学编程bug 越多进步越快代码SeqList.h#pragma once #includestdio.h #includeassert.h #includestdlib.h typedef int Type; struct SeqList { Type* arr; int size; int capacity; }; typedef struct SeqList SL; void SLInit(SL* ps);//初始化 void SLDestory(SL* ps);//销毁 void SLPrint(SL s);//打印 void SLPushBack(SL* ps, Type x);//尾插 void SLPushFront(SL* ps, Type x);//头插 void SLPopBack(SL* ps);//尾删 void SLPopFront(SL* ps);//头删 void SLInsert(SL* ps, int pos, Type x);//在指定位置之前插入数据 void SLErase(SL* ps, int pos);//删除指定位置数据 int SLFind(SL* ps, int x);//查找SeqList.c#includeSeqList.h void SLInit(SL* ps) { ps-arr NULL; ps-size ps-capacity 0; } void SLDestory(SL* ps) { if (ps NULL) { return; } if (ps-arr!NULL) { free(ps-arr); ps-arr NULL; } ps-size ps-capacity 0; } void SLPushBack(SL* ps, Type x) { assert(ps); if (ps-capacity 0) { int newcapacity ps-capacity 0 ? 4 : 2 * ps-capacity; Type* temp(Type*)realloc(ps-arr, newcapacity * sizeof(Type)); if (temp ! NULL) { ps-arr temp; ps-capacity newcapacity; } else { perror(realloc fail); exit(1); } } ps-arr[ps-size] x; ps-size; } void SLPushFront(SL* ps, Type x) { assert(ps); if (ps-capacity 0) { int newcapacity ps-capacity 0 ? 4 : 2 * ps-capacity; Type* temp (Type*)realloc(ps-arr, newcapacity * sizeof(Type)); if (temp ! NULL) { ps-arr temp; ps-capacity newcapacity; } else { perror(realloc fail); exit(1); } } for (int i 0; ips-size; i) { ps-arr[ps-size - i] ps-arr[ps-size - i - 1]; } ps-arr[0] x; ps-size; } void SLPrint(SL s) { for (int i 0; i s.size; i) { printf(%d , s.arr[i]); } printf(\n); } void SLPopBack(SL* ps) { assert(ps); assert(ps-size); ps-size--; } void SLPopFront(SL* ps) { assert(ps); assert(ps-size); for (int i 0; ips-size-1; i) { ps-arr[i] ps-arr[i 1]; } ps-size--; } void SLInsert(SL* ps, int pos, Type x) { assert(ps); assert(posps-sizepos0); if (ps-capacity 0) { int newcapacity ps-capacity 0 ? 4 : 2 * ps-capacity; Type* temp (Type*)realloc(ps-arr, newcapacity * sizeof(Type)); if (temp ! NULL) { ps-arr temp; ps-capacity newcapacity; } else { perror(realloc fail); exit(1); } } for (int i ps-size; i pos; i--) { ps-arr[i] ps-arr[i - 1]; } ps-arr[pos] x; ps-size; } void SLErase(SL* ps, int pos) { assert(ps); assert(pos ps-size pos 0); for (int i pos; ips-size-1; i) { ps-arr[i] ps-arr[i 1]; } ps-size--; } int SLFind(SL* ps, int x) { assert(ps); for (int i 0; i ps-size; i) { if (ps-arr[i] x) { return i; } } return -1; }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询