顺序存储线性表详解:从内存布局到扩容策略的工程实践

1. 从“数组”说起:为什么顺序存储的线性表值得单独拎出来讲

很多人第一次接触数据结构,都是从“线性表”这三个字开始的。而线性表最基础、最直观的一种实现方式,就是顺序存储。说白了,它就是用一段地址连续的内存空间,把数据一个挨着一个地放进去。你在C语言里见到的数组,在Java里见到的ArrayList底层,在Python里见到的list的某些实现思路,本质上都跟顺序存储的线性表脱不开关系。

我见过不少初学者,学链表的时候头头是道,指针指来指去画得满纸都是箭头,但一回到顺序存储,反而觉得“这不就是数组吗,有什么好讲的”。结果一到实际写代码,插入删除的时候下标越界、元素搬移搬错方向、扩容时机判断失误,各种问题全冒出来了。顺序存储的线性表看似简单,但它是理解随机访问、空间连续性、时间复杂度权衡这些核心概念的起点。你如果连它的边界条件都没吃透,后面学树、图、哈希表,遇到类似的空间管理问题照样会栽跟头。

这篇文章我打算从零开始,把顺序存储的线性表彻底拆一遍。从它的内存布局、核心操作的实现细节,到实际编码中容易踩的坑,再到它和链式存储到底该怎么选,都会结合我自己的经验展开聊。不管你是正在准备考试的学生,还是刚入行想补基础的开发者,或者是想重新梳理知识体系的从业者,这篇内容都能让你对“顺序存储”这四个字有更扎实的理解。

2. 顺序存储的底层逻辑:一块连续内存引发的连锁反应

2.1 连续内存到底意味着什么

顺序存储的线性表,核心特征就一个词:连续。它向系统申请一块连续的内存区域,然后把线性表中的第1个元素放在起始位置,第2个元素紧挨着放,以此类推。假设每个元素占用c个字节,起始地址是LOC(a1),那么第i个元素的地址就是:

LOC(ai) = LOC(a1) + (i - 1) * c

这个公式看起来平平无奇,但它带来的能力是巨大的:只要知道起始地址和下标,就能在常数时间内算出任意元素的地址。这就是所谓的随机访问——注意,是“随机访问”,不是“随机存储”。你可以直接跳到第100个元素,不需要从头遍历。这一点是链表做不到的,链表想找第100个元素,必须从头结点一个一个往后走。

但连续内存也是一把双刃剑。因为内存必须连续,所以当你需要在中间插入或删除元素时,后面的元素就得整体搬家。这就像一排人坐在长椅上,你要在中间塞一个人进去,右边所有人都得往右挪一格。如果长椅不够长,还得换一条更长的长椅,把所有人重新安排一遍。这个“搬家”的过程,就是顺序存储最主要的性能开销来源。

2.2 容量与长度:两个必须分清楚的概念

在实现顺序存储的线性表时,有两个概念极其容易混淆:容量和长度。

  • 容量:这块连续内存总共能装多少个元素,是申请时就确定的上限。
  • 长度:当前实际存了多少个元素,是动态变化的。

我见过不少人在写代码时,直接用“长度”去判断数组是否越界,结果容量是10,长度是10,他还以为可以继续插入,一运行就崩了。正确的判断逻辑应该是:插入之前先检查length < capacity,如果长度已经等于容量,要么报错,要么触发扩容。

用生活化的例子来说,容量就像你家的衣柜总空间,长度就像你目前挂进去的衣服数量。衣柜满了不代表衣服数量等于衣柜的格子数,但你要再挂一件,就必须先腾地方或者换更大的衣柜。这个区分在写插入操作时尤其关键,因为插入的前提就是“还有空位”。

2.3 随机访问的代价与收益

随机访问的收益很直观:按位查找的时间复杂度是O(1)。你访问第1个元素和第1000个元素,耗时几乎一样。这个特性在很多场景下非常关键,比如你需要频繁根据下标读取数据、做二分查找、实现矩阵运算等。

但代价也藏在细节里。因为内存连续,操作系统在分配这块空间时,必须找到足够大的连续空闲区域。如果内存碎片化严重,可能明明总空闲内存够,但就是找不到一块连续的区域来分配。这在嵌入式系统或者内存受限的环境里尤其明显。相比之下,链式存储的结点可以散落在内存各处,只要用指针串起来就行,对连续性的要求低得多。

所以,选择顺序存储,本质上是在用“插入删除的搬移成本”换取“随机访问的极速体验”。这个权衡贯穿整个数据结构的学习过程,你越早想明白,后面做技术选型时就越有底气。

3. 插入与删除:顺序存储最核心的两个操作

3.1 插入操作的完整逻辑与边界条件

插入是顺序存储里最典型的操作,也是最能体现“搬移成本”的地方。假设我们要在第i个位置插入一个新元素e,步骤应该是这样的:

  1. 判断插入位置是否合法:合法的插入位置是1 <= i <= length + 1。注意,这里允许插入到最后一个元素的后面,所以是length + 1,不是length。
  2. 判断容量是否已满:如果length == capacity,要么抛出异常,要么执行扩容。
  3. 搬移元素:从最后一个元素开始,依次向后移动一位,直到第i个位置空出来。
  4. 放入新元素:把e放到第i个位置。
  5. 更新长度:length加 1。

这里最容易出错的是第3步的搬移方向。必须从后往前搬。如果你从前往后搬,第i个位置的元素会被第i+1个位置的元素覆盖,数据就丢了。这个细节我在早期写代码时踩过不止一次,尤其是用循环写的时候,循环变量的起始值和终止值稍微一马虎,方向就反了。

用代码表达大概是这样的:

// 假设 elem 是存储元素的数组,length 是当前长度,capacity 是容量 int insert(int *elem, int *length, int capacity, int i, int e) { if (i < 1 || i > *length + 1) { return 0; // 插入位置不合法 } if (*length >= capacity) { return 0; // 容量已满,实际项目中这里应该触发扩容 } for (int j = *length; j >= i; j--) { elem[j] = elem[j - 1]; // 从后往前搬 } elem[i - 1] = e; (*length)++; return 1; }

注意数组下标是从0开始的,所以第i个位置对应的是elem[i-1]。这个转换关系在写代码时一定要在脑子里过清楚,否则很容易出现“差一错误”。

3.2 删除操作的搬移方向为什么相反

删除操作和插入操作在搬移方向上正好相反。假设我们要删除第i个元素,步骤是:

  1. 判断删除位置是否合法:合法的删除位置是1 <= i <= length。注意这里没有length + 1,因为你不能删除一个不存在的位置。
  2. 保存被删除的元素(如果需要返回的话)。
  3. 搬移元素:从第i+1个元素开始,依次向前移动一位,覆盖掉被删除的元素。
  4. 更新长度:length减 1。

搬移方向是从前往后,因为你要用后面的元素去覆盖前面的空位。如果从后往前搬,后面的元素会先被覆盖,同样会丢数据。

int delete(int *elem, int *length, int i, int *e) { if (i < 1 || i > *length) { return 0; // 删除位置不合法 } *e = elem[i - 1]; // 保存被删除的元素 for (int j = i; j < *length; j++) { elem[j - 1] = elem[j]; // 从前往后搬 } (*length)--; return 1; }

插入和删除的搬移方向,本质上是由“空位出现在哪里”决定的。插入时空位在目标位置,需要把后面的元素往后推;删除时空位在目标位置,需要把后面的元素往前拉。想清楚这个物理过程,就不用死记硬背方向了。

3.3 时间复杂度:最好、最坏与平均

插入和删除的时间复杂度,取决于元素搬移的次数。

对于插入操作:

  • 最好情况:插入到表尾,不需要搬移任何元素,时间复杂度O(1)。
  • 最坏情况:插入到表头,需要搬移全部n个元素,时间复杂度O(n)。
  • 平均情况:假设插入到每个位置的概率相等,平均搬移次数是n/2,时间复杂度仍然是O(n)。

对于删除操作:

  • 最好情况:删除表尾元素,不需要搬移,O(1)。
  • 最坏情况:删除表头元素,需要搬移n-1个元素,O(n)。
  • 平均情况:平均搬移次数是(n-1)/2,时间复杂度O(n)。

这个分析告诉我们一个很重要的实践结论:如果你的应用场景中插入和删除非常频繁,尤其是频繁在表头或中间位置操作,顺序存储可能不是最佳选择。反过来,如果你的操作主要是按位查找和尾部追加,顺序存储的效率会非常高。

4. 扩容策略:顺序存储绕不开的工程问题

4.1 固定容量带来的尴尬

教科书上的顺序存储线性表,通常用一个固定大小的数组来实现。但实际项目中,你很难提前知道到底要存多少个元素。定小了不够用,定大了浪费内存。这个矛盾在嵌入式开发、游戏引擎、服务端缓存等场景里都很常见。

我早期写过一个日志缓冲模块,当时拍脑袋定了个1000的容量,觉得肯定够用。结果上线没多久就遇到批量导入的场景,日志条数直接冲到几万条,程序直接抛异常。后来改成动态扩容,才算是解决了问题。这个经历让我明白,固定容量的顺序存储只适合数据量可预测的场景,一旦数据量有波动,就必须考虑扩容机制。

4.2 扩容的常见策略与代价分析

扩容的基本思路是:当容量不足时,申请一块更大的连续内存,把原有数据复制过去,然后释放旧内存。关键在于“更大”是多少。常见的策略有两种:

  • 固定增量扩容:每次扩容增加固定大小,比如每次增加100个元素的空间。
  • 倍数扩容:每次扩容把容量翻倍,比如从100变成200,再变成400。

固定增量的优点是内存增长平滑,不容易浪费;缺点是扩容操作会变得非常频繁,每次扩容都要复制全部数据,累计的时间开销很大。倍数扩容的优点是扩容次数少,均摊到每次插入操作上的成本更低;缺点是可能会浪费一部分内存空间,尤其是最后一次扩容后可能只用了一小部分。

从均摊分析的角度看,倍数扩容的均摊时间复杂度是 O(1)。假设每次翻倍,从容量1开始插入n个元素,总复制次数大约是1 + 2 + 4 + ... + n/2 < n,所以平均每次插入的复制成本是常数级别。这也是为什么大多数动态数组实现(比如C++的vector、Java的ArrayList)都采用倍数扩容。

但倍数扩容也不是没有代价。每次扩容都需要一块更大的连续内存,如果内存碎片化严重,可能会分配失败。而且复制过程中,程序会出现短暂的卡顿,对于实时性要求高的系统,这个卡顿可能是不可接受的。所以在实际工程中,有时候会采用“预分配+分段”的策略,或者干脆换用链式存储。

4.3 缩容:什么时候该把内存还回去

有扩容就有缩容。如果线性表中的元素大量减少,占着很大的内存空间不用,也是一种浪费。缩容的策略通常是:当元素数量降到容量的某个比例(比如1/4)以下时,把容量缩减到当前元素数量的一半或某个合理值。

但缩容比扩容更危险,因为频繁的缩容和扩容会导致“抖动”——刚缩容完又插入元素,又得扩容,来回折腾。所以缩容的触发条件通常比扩容更保守,比如容量是元素数量的4倍以上才缩容,缩容后容量是元素数量的2倍。这样留出足够的缓冲空间,避免频繁抖动。

注意:缩容操作在大多数标准库的动态数组实现中并不常见,因为内存分配器本身会管理空闲内存。但在内存极度受限的环境中,手动缩容是有意义的。

5. 顺序存储 vs 链式存储:选型时到底该看什么

5.1 从访问方式看差异

顺序存储支持随机访问,按位查找是 O(1);链式存储只支持顺序访问,按位查找是 O(n)。这个差异决定了两者的适用场景。

如果你的应用需要频繁地“读取第k个元素”,比如实现一个排行榜、一个矩阵、一个需要二分查找的有序表,顺序存储几乎是唯一的选择。链式存储在这种场景下会非常低效,因为每次查找都要从头遍历。

反过来,如果你的应用主要是“在某个位置插入或删除”,而且这个位置不固定,链式存储的优势就体现出来了。链式存储插入和删除只需要修改指针,不需要搬移元素,时间复杂度是 O(1)(前提是已经找到了位置)。顺序存储则需要 O(n) 的搬移成本。

5.2 从内存利用看差异

顺序存储的内存利用率通常更高,因为它不需要额外的指针域来存储元素之间的关系。每个元素就是纯粹的数据,没有额外开销。但顺序存储要求连续内存,如果内存碎片化严重,可能会分配失败。

链式存储的每个结点都需要额外的指针域,内存开销更大。但链式存储对内存的连续性没有要求,结点可以散落在各处,内存分配的灵活性更高。在内存碎片化严重的环境中,链式存储可能比顺序存储更容易分配成功。

5.3 从缓存友好性看差异

这一点在教科书里经常被忽略,但在实际性能优化中非常重要。顺序存储的元素在内存中是连续的,CPU的缓存预取机制可以很好地工作。当你访问第1个元素时,CPU会把后面几个元素一起加载到缓存里,后续访问就直接命中缓存,速度极快。

链式存储的结点在内存中是分散的,访问一个结点后,下一个结点可能在完全不同的内存页上,缓存命中率低,每次访问都可能触发缓存未命中,导致性能下降。在现代CPU架构下,这个差异可能比时间复杂度分析更显著。我做过一个简单的测试,同样是遍历100万个元素,顺序存储的耗时只有链式存储的几分之一,差距主要就来自缓存。

所以,如果你的应用是“读多写少”,顺序存储通常是更好的选择,不仅因为随机访问快,还因为缓存友好。如果是“写多读少”,而且写入位置不固定,链式存储可能更合适。

6. 实际编码中容易踩的坑与排查思路

6.1 下标越界:最常见的崩溃来源

下标越界是顺序存储最常遇到的问题。C语言不会自动检查数组越界,一旦越界,可能读到垃圾数据,也可能直接段错误。Java和Python虽然会抛异常,但异常本身也意味着程序中断。

排查下标越界,我的经验是:在每次访问数组之前,先把下标的合法范围写出来,然后检查当前下标是否在范围内。比如插入操作中,合法的插入位置是1 <= i <= length + 1,删除操作中是1 <= i <= length。把这些边界条件写在注释里,写代码时对照检查,能避免大部分越界问题。

另外,数组下标从0开始,而线性表的位置从1开始,这个转换关系也是越界的高发区。我习惯在函数入口处就把位置转换成下标,后续统一用下标操作,减少混淆。

6.2 搬移方向写反:数据丢失的隐形杀手

搬移方向写反,程序不会崩溃,但数据会悄悄丢失。这种问题最难排查,因为程序看起来运行正常,只是结果不对。

我的排查方法是:在搬移循环前后打印数组内容。比如插入操作,搬移前打印一次,搬移后打印一次,对比一下就能看出方向对不对。如果搬移后目标位置的数据被覆盖了,说明方向反了。

还有一个更根本的方法:想清楚物理过程再写代码。插入时,你要在目标位置腾出一个空位,所以后面的元素必须往后挪;删除时,你要把目标位置的空缺填上,所以后面的元素必须往前挪。把这个过程在脑子里过一遍,方向就不会错。

6.3 扩容时机判断错误:容量和长度混淆

扩容时机判断错误,通常是因为把容量和长度搞混了。正确的判断是length == capacity时才需要扩容,而不是length == capacity - 1或者别的什么条件。

我见过有人在插入前判断length + 1 == capacity,这其实也是对的,因为插入后长度会变成length + 1,如果插入后等于容量,说明插入前容量还够,不需要扩容。但更直观的写法是:先判断length == capacity,如果满了就扩容,然后再执行插入。这样逻辑更清晰,不容易出错。

6.4 扩容后忘记更新容量变量

扩容后,容量变量必须更新为新的容量值。如果忘了更新,下次判断容量时还会用旧值,导致明明已经扩容了却还认为容量不足,反复触发扩容,性能急剧下降。

这个问题的排查方法是:在扩容函数返回后,立即检查容量变量是否已经更新。可以在扩容函数里加日志,打印扩容前后的容量值,确认更新逻辑正确。

7. 顺序存储的典型应用场景与实战建议

7.1 什么时候优先选顺序存储

根据我的经验,以下场景优先考虑顺序存储:

  • 数据量可预测或变化不大:比如配置项、固定大小的缓冲区、矩阵运算。
  • 读多写少:比如缓存、索引表、静态数据集。
  • 需要频繁随机访问:比如二分查找、排行榜、按位读取。
  • 对缓存友好性要求高:比如高性能计算、游戏引擎中的实体列表。

7.2 什么时候该果断放弃顺序存储

以下场景建议考虑链式存储或其他结构:

  • 频繁在表头或中间插入删除:比如消息队列、任务调度列表。
  • 数据量波动极大且难以预测:比如实时日志收集、动态增长的集合。
  • 内存碎片化严重:比如长时间运行的服务,内存分配器已经产生大量碎片。
  • 需要频繁合并或拆分:比如多项式运算、大整数运算。

7.3 一个实用的性能优化技巧

如果你的顺序存储需要频繁扩容,可以考虑预分配策略:在初始化时申请一块比预期稍大的内存,减少扩容次数。比如你预计最多存1000个元素,可以初始分配1200个元素的空间,留出20%的余量。这样既能减少扩容次数,又不会浪费太多内存。

另一个技巧是批量插入时先扩容再插入:如果你知道要连续插入多个元素,可以先计算需要的总容量,一次性扩容到位,然后逐个插入,避免多次扩容。这个技巧在批量导入数据的场景下非常有效。

8. 从顺序存储延伸出去的知识脉络

顺序存储的线性表虽然基础,但它串联起了很多后续的知识点。比如:

  • 栈和队列:都可以用顺序存储实现,栈的顺序存储就是“后进先出”的数组,队列的顺序存储需要处理“假溢出”问题,引出循环队列的设计。
  • 字符串:字符串本质上就是字符的顺序存储,很多字符串算法(如KMP)都依赖于顺序存储的随机访问特性。
  • 动态数组:C++的vector、Java的ArrayList、Python的list,都是顺序存储线性表的工程化实现,理解它们的扩容策略和迭代器失效问题,对实际开发很有帮助。
  • 内存管理:顺序存储的扩容和缩容,本质上就是内存的分配和释放,理解这些操作有助于深入理解操作系统的内存管理机制。

我个人的体会是,顺序存储的线性表就像数据结构世界的“地基”。你在这个地基上盖的楼越高,越需要回头检查地基是否牢固。很多高级数据结构的问题,追根溯源都能在顺序存储这里找到影子。所以,别急着跳过它去学更炫酷的结构,把顺序存储的每个细节都吃透,后面的路会好走很多。

最后分享一个我常用的学习方法:手写实现一遍顺序存储的线性表,包括插入、删除、查找、扩容、缩容,然后写测试用例覆盖所有边界条件。这个过程可能只需要一两个小时,但它能帮你把所有的坑都踩一遍,比看十遍书都管用。写完之后,再去对比标准库的实现,看看别人是怎么处理边界条件和性能优化的,收获会更大。

相关新闻

iText实现Markdown转PDF完整流程:HTML桥接与字体排版实战

iText实现Markdown转PDF完整流程:HTML桥接与字体排版实战

收到&#xff0c;我会严格按照要求&#xff0c;基于“ITextpdf将Markdown转换成PDF详细流程&#xff08;HTML转PDF&#xff09;”这一标题&#xff0c;撰写一篇结构独立、内容详实、可直接复现的实战型博文。以下为纯净的Markdown正文内容。1. 为什么绕这么大一圈&#xff1a;M…

2026/10/20 21:04:02 阅读更多 →
多Agent协作实战:用虚拟AI团队搞定理论研究与工程实现

多Agent协作实战:用虚拟AI团队搞定理论研究与工程实现

半年前&#xff0c;我给自己定了个规矩&#xff1a;把同时涉及理论分析和工程实现的任务&#xff0c;统一交给一支多Agent协作的虚拟AI研究团队来跑。这个决定不是突发奇想&#xff0c;而是被一个具体的序列预测项目&#xff08;暂称项目X&#xff09;逼出来的——项目一边要求…

2026/10/20 21:04:02 阅读更多 →
构建知识工作自动化流水线:基于Markdown的插件体系实践

构建知识工作自动化流水线:基于Markdown的插件体系实践

knowledge-work-plugins 这个项目&#xff0c;最初就是为了解决我自己一个特别具体的死结&#xff1a;每天涌进来的信息越来越多&#xff0c;真正能沉淀下来、在写方案时用得上的却少得可怜。那时候我的阅读材料散落在临时文件、聊天记录、邮箱附件和几个不同的网盘里&#xff…

2026/10/20 21:02:58 阅读更多 →

最新新闻

MPU6050+OLED姿态角显示:从原始数据到稳定角度的完整闭环

MPU6050+OLED姿态角显示:从原始数据到稳定角度的完整闭环

简介&#xff1a;这是一份基于STM32的MPU6050姿态解算与OLED实时显示完整工程&#xff0c;适合物联网、机器人及无人机方向开发者动手实践。资源包共213个文件&#xff0c;约5.58MB&#xff0c;以C源码、H头文件、编译中间文件&#xff08;o、d、crf&#xff09;及Keil工程配置…

2026/10/20 21:43:04 阅读更多 →
Nmap到Metasploit:靶场完整攻击链路实战详解

Nmap到Metasploit:靶场完整攻击链路实战详解

我一直觉得&#xff0c;网络安全这行如果只是会装个工具、跑个脚本&#xff0c;那遇到真实场景基本抓瞎。真正让人长进的动作&#xff0c;是在一个完全可控的靶场环境里&#xff0c;把“信息收集→端口扫描→漏洞研判→攻击利用→权限获取”这条闭环完整走一遍。今天这篇就是一…

2026/10/20 21:43:04 阅读更多 →
AI Agent从Demo到生产:上下文、工具调用与状态治理的底层壁垒

AI Agent从Demo到生产:上下文、工具调用与状态治理的底层壁垒

最近总有朋友拿着自己做的AI Agent来给我看&#xff0c;演示的时候一切“乖巧”&#xff0c;任务拆解清晰、工具调用流畅、回答有逻辑&#xff0c;看起来比不少商业产品还像样。但问一句“上线了吗”&#xff0c;气氛就会突然安静下来。这大概是当下做Agent最普遍的一种状态&am…

2026/10/20 21:43:04 阅读更多 →
自适应哈夫曼编码FGK算法:C++实现与压缩避坑实战

自适应哈夫曼编码FGK算法:C++实现与压缩避坑实战

简介&#xff1a;自适应哈夫曼编码通过随字符频率变化实时更新哈夫曼树&#xff0c;解决了静态哈夫曼编码难以应对字符频次动态变化的问题。配套C实现面向数据压缩算法学习者与开发者&#xff0c;代码覆盖哈夫曼树构建、最小堆维护、编码解码与文本文件I/O的完整逻辑。资源包共…

2026/10/20 21:43:04 阅读更多 →
从技能清单到能力系统:拆解、补齐与组合skills的实操指南

从技能清单到能力系统:拆解、补齐与组合skills的实操指南

1. 从“skills”这个词说起&#xff1a;为什么它突然成了高频词“skills”这个词最近被反复提起&#xff0c;不是没有原因的。我在几个技术社区和职场社群里潜水观察了大半年&#xff0c;发现一个很明显的趋势&#xff1a;大家讨论的不再是“你会用什么工具”&#xff0c;而是“…

2026/10/20 21:43:04 阅读更多 →
context-mode上下文模式:从参数爆炸到可维护系统的工程实践

context-mode上下文模式:从参数爆炸到可维护系统的工程实践

1. 从“上下文模式”说起&#xff1a;一个被低估的工程概念第一次看到“context-mode”这个词&#xff0c;很多人会以为是某个新出的框架或者库。其实不是。它更像是一种设计思路&#xff0c;一种在系统开发中处理“上下文”这件事的工程模式。我在几个中型项目里反复踩过上下文…

2026/10/20 21:41:49 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →