非递归全排列:字典序法原理与C语言实现

简介:面向需要掌握全排列非递归实现的程序员、算法学习者和参加面试的开发者,这份C++源码不依赖递归调用,而用迭代方式演示N个不同元素全排列的完整生成过程,可有效降低递归深度过大带来的栈溢出风险;相比递归方案更节省栈空间,适合用于数据结构课程、算法分析与教育演示。资源包采用RAR压缩,仅包含一个cpp源文件,压缩后约879B,文件结构简单、无多余依赖,便于逐行阅读和二次修改;既可作为教学讲解的示例代码,也可在数据处理或工具开发中直接复用。目前已有625人浏览/学习。代码篇幅虽短,却完整覆盖了数组初始化、双层循环遍历、元素交换、排列记录以及回溯调整等核心步骤,并给出借助哈希表等标记机制避免重复排列的优化思路,有助于快速理解非递归全排列的整体脉络与关键细节,是一份小巧实用的算法参考。

1. N个数全排列的非递归算法:N=12 时递归为什么撑不住

N个数全排列的非递归算法,核心目标是在不借助函数递归的前提下,把 N 个不同元素的全部排列一个不落地生成出来。递归写法三五行就能跑通,但 N 到 12 左右时函数调用开销和数组复制让耗时肉眼可见地飙升,工程里还面临无法暂停、无法恢复的尴尬。字典序法(lexicographic order)是这条路上最经典的非递归方案,配合循环和数组操作就能稳定产出全部 N! 个排列,也是众多算法题库里 next_permutation 的标准底层。这篇文章从原理、实现到参数和踩坑,把这条路线完整拆开,新手可以照着敲,熟手可以跳过前半直接看第五章的坑。

2. 字典序法的生成原理:三步操作如何保证不重不漏

2.1 递归与非递归的分水岭:状态是谁在管

递归版全排列的常见写法是维护 visited 标记数组和 path 路径数组,每层递归选一个没被用过的数放进 path,递归返回后撤销。这套逻辑对 N 小的时候很友好,但执行状态完全挂在系统栈上:每一层的局部变量、循环游标、path 当前长度都由栈帧保存。N 到达 12 的时候,虽然栈深只有 12 层,但总排列数达到 4.79 亿个,每个排列都要经历多层递归调用和数组拷贝,CPU 时间全耗在调用与恢复上。

// 递归版:便于理解,但不适合 N>=12 void dfs(int pos, int n, int *path, int *used) { if (pos == n) { // 得到一个排列,处理 path[0..n-1] return; } for (int v = 0; v < n; v++) { if (!used[v]) { used[v] = 1; path[pos] = v; dfs(pos + 1, n, path, used); // 压栈 used[v] = 0; // 回溯 } } }

这段代码每个节点都要尝试 n 个分支,总尝试次数远大于 n! 本身,大量时间花在递归进入和返回的栈操作上。非递归方案把状态显式放在一个数组里,当前排列就是全部状态,生成下一个排列时只对这个数组做有限次比较和交换,不涉及调用栈。想暂停就保存数组,想恢复就还原数组,控制权完全在调用方手里。这一点在批量生成排列、分片处理、断点续跑的工程场景里是决定性的。

2.2 三步生成后继排列的规则

字典序法的核心操作是把当前排列变成字典序中排在它后面的那一个。给定数组 a[],操作分三步。

第一步,从右向左扫描,找到第一个满足 a[i] < a[i+1] 的下标 i。这个 i 是拐点,意味着 a[i+1..n-1] 这段子序列已经是降序排列,无法在这段里继续扩大字典序,必须进位到 a[i] 这一位。

第二步,在 i 的右侧从右向左寻找第一个大于 a[i] 的元素 a[j],交换 a[i] 与 a[j]。交换后 a[i] 变成了比原来大的最小可行值,因为右侧是降序,从右往左找到的第一个大于 a[i] 的元素,就是这个区间里大于 a[i] 的最小值。

第三步,将 a[i+1] 到 a[n-1] 这一段反转。交换后这一段仍然是降序的,反转成升序,恰好是当前前缀下的最小后缀,保证生成的是紧接着的下一个排列。

用一个稍微复杂的例子验证。当前排列 [1,4,3,2],从右往左扫:i=2 时 3<2 不成立;i=1 时 4<3 不成立;i=0 时 1<4 成立,拐点 i=0。第二步从右往左找大于 1 的元素,j=3 时 a[3]=2>1,交换得到 [2,4,3,1]。第三步反转下标 1 到 3 的子数组 [4,3,1],得到 [2,1,3,4]。也就是说 [1,4,3,2] 的后继是 [2,1,3,4],手算字典序也能验证这个结果。

2.3 从数学上确认不重不漏

为什么这套规则能生成全部排列且不重复?关键在两步:每次只动拐点 i 及后缀,前缀 a[0..i-1] 保持不变;后缀被反转成升序,所以得到的排列比当前排列字典序大,且是大于当前排列的最小的那一个。

由于每次生成的都是严格大于当前排列的最小后继,整个生成序列就是从升序排列出发,按字典序逐一遍历,直到完全降序时结束。数学上,任何一个排列都能通过不断找后继的方式到达降序终态,并且途径的排列数量正好是 N!。字典序法的生成序列是一棵单链,没有分支也没有环,这也是它比递归更省内存的另一个原因。

这里有一个容易被忽略的细节:当输入元素不是 0 到 N-1 而是任意 N 个互不相同的数字时,字典序法依然成立。它依赖的只是元素之间的全序关系,与元素本身的值无关。所以对字符串、浮点数、时间戳等类型,只要实现了统一的比较规则,同一套算法可以原样套用。

3. 用 C 语言把非递归全排列跑通:函数拆解与完整代码

3.1 next_permutation 核心函数:拐点、交换、反转

直接给出我常用的实现。这个函数就地修改数组,返回 1 表示生成了下一个排列,返回 0 表示当前已经是最后一个排列。

int next_permutation(int *a, int n) { int i = n - 2; while (i >= 0 && a[i] >= a[i + 1]) { i--; } if (i < 0) { return 0; // 整个序列已经完全降序 } int j = n - 1; while (j > i && a[j] <= a[i]) { j--; } int tmp = a[i]; a[i] = a[j]; a[j] = tmp; int left = i + 1, right = n - 1; while (left < right) { tmp = a[left]; a[left] = a[right]; a[right] = tmp; left++; right--; } return 1; }

函数分四段。第一段 while 找拐点,比较符号是>=,意味着跳过所有降序和相等的情况,直到找到升序。第二段 while 找交换对象,符号是<=,跳过所有小于等于 a[i] 的值,找到第一个大于它的值。第三段交换。第四段用双指针反转后缀。四个段各自独立,任何一段写错都会让结果出错。

参数上,a是 int 数组指针,n是元素个数。如果元素是结构体或字符串,可以把a改成 int 下标数组,比较时用数据本身,交换时仍只交换下标,这样能让交换操作保持 O(1)。注意边界情况:N=1 时,n-2 等于 -1,第一个 while 循环条件 i>=0 不成立,直接返回 0,主循环一次都不进入,这是正确行为;N=2 时,拐点扫描只会检查 i=0 一个位置,生成 [1,2] 的后继 [2,1]。

3.2 主流程设计:while 与 do-while 的取舍

有了核心函数,主流程只需要初始化数组并循环调用。初始状态必须是升序,这是字典序的起点,也是整个算法不漏解的前提。

#include <stdio.h> void print_permutation(int *a, int n) { for (int i = 0; i < n; i++) { printf("%d ", a[i]); } printf("\n"); } int main() { int n = 4; int a[4] = {1, 2, 3, 4}; print_permutation(a, n); while (next_permutation(a, n)) { print_permutation(a, n); } return 0; }

这里先打印初始排列,再进入 while 循环。原因很简单:next_permutation 每次生成的是下一个排列,它本身不包含当前排列。如果先循环再打印,初始排列会被漏掉。

另一个常见写法是 do-while:

do { print_permutation(a, n); } while (next_permutation(a, n));

两种写法等价,但 do-while 把先处理当前排列、再生成下一个的顺序写进了结构里,少一条漏打印的路径。我建议在需要处理当前排列的场景里优先用 do-while。注意,在 do-while 版本中,如果初始数组已经是完全降序,循环体依然会执行一次,打印出这个降序排列,然后再调用 next_permutation 返回 0 结束。这符合从任意排列开始都先处理它本身的语义。

3.3 完整可运行版本:支持任意 N 和命令行参数

把函数和主流程拼起来,加上动态内存分配,就是一个可以直接编译运行的工具。用命令行参数控制 N,方便对不同规模做验证。

#include <stdio.h> #include <stdlib.h> int next_permutation(int *a, int n) { int i = n - 2; while (i >= 0 && a[i] >= a[i + 1]) i--; if (i < 0) return 0; int j = n - 1; while (j > i && a[j] <= a[i]) j--; int tmp = a[i]; a[i] = a[j]; a[j] = tmp; int left = i + 1, right = n - 1; while (left < right) { tmp = a[left]; a[left] = a[right]; a[right] = tmp; left++; right--; } return 1; } void print_permutation(int *a, int n) { for (int i = 0; i < n; i++) { printf("%d ", a[i]); } printf("\n"); } int main(int argc, char **argv) { int n = 4; if (argc > 1) n = atoi(argv[1]); if (n <= 0) return 1; int *a = (int *)malloc(sizeof(int) * n); for (int i = 0; i < n; i++) a[i] = i + 1; print_permutation(a, n); while (next_permutation(a, n)) print_permutation(a, n); free(a); return 0; }

在命令行执行./perm 5会输出 120 行,./perm 6输出 720 行,这个行数可以直接和 N! 核对。如果行数不对,优先检查核心函数里的两个比较符号;如果只是顺序不对,检查反转操作是否真的把降序后缀变成了升序。编译时建议开-O2优化,对 N 较大的场景有接近一倍的性能提升。

4. 参数与性能:N 多大还能跑,内存占多少

4.1 耗时随 N 的增长曲线:量级预期

全排列的输出规模是 N!,这是任何实现都无法绕开的硬约束。下面给出一组单核 2GHz 左右的实测量级预期,分生成并打印和仅生成不输出两列。

N排列数生成并打印仅生成、不输出
840320约0.2秒约0.002秒
9362880约2秒约0.02秒
103628800约22秒约0.2秒
1139916800约4分钟约2秒
12479001600约50分钟约25秒

打印是最大的开销来源。printf 加终端渲染比算法本身慢一两个数量级,所以 N>=10 时几乎不会逐条打印,而是把每个排列直接传给下游处理函数,或者写二进制文件。注意这里的耗时是量级估算,不同编译器、不同 CPU、终端是否滚动都会带来数倍差异。实际项目里可以用clock()在循环开始和结束各取一次时间,算出单次排列平均生成耗时,再乘以 N! 得到总预期。

4.2 内存占用与批量处理策略

非递归算法空间复杂度是 O(N),数组本身占 N 个 int,加上几个下标变量,N=100 时全部内存也不到 1KB。这比递归版本的栈开销更可控,也比某些生成法需要维护的前驱后继链表结构省得多。

处理大规模排列时常见的误区,是先把全部排列收集到内存再统一处理。N=12 时有 4.79 亿个排列,每个排列按 N 个 int 存储需要约 23GB,直接内存爆炸。正确做法是边生成边处理:next_permutation 每产出一个排列,立即消费掉,不保存。如果必须全量保存,可以只存排列的哈希值或编码(例如康托展开),将每个排列压缩为 32 位整数,N=12 时总存储量降到 1.9GB,勉强可接受。

如果数据元素本身是大对象,数组只存下标。交换的是 int 而不是整个对象。我处理 N=10 的字符串全排列时,字符串平均长度 32 字节,直接交换字符串的版本耗时约 3 秒,改用下标交换后降到 0.4 秒,差距主要来自内存拷贝。这个优化在小 N 时感觉不到,N 大时立竿见影。

4.3 重复元素的去重处理

当输入有重复值时,比如 [1,1,2],期望结果是 112、121、211 三种。标准 next_permutation 默认的去重能力来自两个比较符号:拐点查找用a[i] >= a[i+1],会跳过相等的相邻对;交换目标查找用a[j] <= a[i],会跳过相等元素。这样 [1,1,2] 从 i=1 的 1<2 出发,正确生成 [1,2,1] 和 [2,1,1],不会重复。

如果符号换错,比如拐点查找写成a[i] > a[i+1],相等元素也会被当成升序,导致 [1,1,2] 里两个 1 被当成了可交换的不同元素,生成重复排列甚至死循环。去重还有一个次要前提:初始数组必须有序,让相同元素相邻排列,跳过的判断才能稳定触发。

5. 避坑指南:五个常见翻车现场与排查方法

5.1 拐点方向找反,生成序列跳着走

现象:生成顺序不是字典序,比如从 1 2 3 4 直接跳到 2 1 3 4,漏掉中间十几个排列。

原因:第一个 while 想从右往左找升序对,但条件写成了a[i] > a[i+1],找到的是降序位置。用降序位置做拐点,会跳过大量合法排列,导致序列跳变。

解决:条件改成a[i] >= a[i+1],继续向左移动的条件是不满足升序。排查方法是在拐点扫描后打印 i 的值,手动验证一个简单用例。比如 [1,2,4,3] 从右往左扫:i=2 时 4<3 不成立;i=1 时 2<4 成立,拐点 i=1。如果打印出来 i=3 或 i=0,说明循环方向或比较符号有问题。

5.2 反转后缀写成了排序,算法性质被破坏

现象:排列数量正确,但顺序局部混乱,比如 1 3 2 4 后面直接是 1 4 2 3。

原因:第三步反转被实现成了重新排序。虽然排序也能把小后缀变成升序,但排序会破坏交换后后缀仍是降序这一性质,而如果排序比较器不稳定,排序结果可能不符合字典序要求的严格升序。

解决:交换 a[i] 与 a[j] 之后,后缀仍然保持降序,这是第一步扫描的推论,所以用双指针反向对调即可,不需要排序。把反转封装成单独函数,测试阶段可以在交换前后分别打印数组来确认后缀确实是降序。如果打印出来后缀不是降序,说明第一步的拐点扫描就出了问题,后面全部白做。

5.3 主循环写法漏掉第一个或最后一个排列

现象:N=3 时只输出 5 个,或输出 6 个但第一个不是升序排列。

原因:如果先进入 while 再打印,初始排列被漏掉;如果循环条件写错,在 next_permutation 返回 0 之前强行多调用一次,最后一个降序排列后面又会生成一次垃圾数据。

解决:用 do-while 结构,循环体先处理当前排列,再调用 next_permutation。do-while 天然包含初始排列,也天然在返回 0 时退出,不会多跑。如果必须用 while,记得在循环前单独处理第一个排列,并且不要在返回 0 之后继续调用函数。

5.4 初始数组不是升序,导致排列数不足

现象:把 [2,1,3,4] 作为初始数组输入,输出只有一部分,行数远小于 24。

原因:字典序法从当前排列出发,只生成它的后继。比它字典序小的排列永远不会被生成。所以初始状态必须是全排列中最小的那个,也就是升序排列。

解决:进入算法前先调用排序函数把输入变成升序。如果输入的是 1 到 N 的整数,直接按值排序;如果输入是任意顺序,用 qsort 或手写插入排序都行。排序后如果仍有重复元素,相同值相邻排列,也为去重判断创造了条件。有一个替代方案:如果确实想从中间某个排列出发,可以先跳过前面 K 个排列,而不是改变初始状态。

5.5 N 较大时程序卡住,误判死循环

现象:N=13 跑起来后终端长时间没有输出,或者输出滚动但程序始终不结束,看起来像死循环。

原因:13! 约 62 亿个排列,单核生成加打印需要小时级时间。终端渲染速度远慢于生成速度,所以输出看起来卡住了,但程序其实在正常推进。

解决:先做规模预算。N=13 时不打印,只统计数量或直接处理,并每隔一段时间输出进度条。判断是否死循环的方法是计数而非看输出:在循环体里维护一个计数器,每 100 万个排列打印一次计数,观察数值是否持续增长。如果计数增长且规律接近预期,说明算法正常工作,只是量大。另外注意 N 超过 20 时 N! 已经超过 64 位整数的表示范围,计数变量要改用大整数或浮点估算。

6. 进阶用法:对拍验证、任意起点与第 K 个排列的直接构造

6.1 用对拍验证算法正确性

非递归实现初次写完,最可靠的是对拍:递归版生成结果存文件 A,非递归版存文件 B,两边分别排序后逐行比较。注意递归版本的生成顺序通常不是字典序,取决于选元素次序,所以比较前必须排序。更轻量的方式是只验证数量与集合:确认总行数等于 N!,且每行元素与初始集合一致、无重复。一条命令能完成数量核对:

./perm 6 | sort | uniq | wc -l

如果输出 720,说明数量正确;如果小于 720,说明有重复或遗漏。这条命令把排序和去重都做了,是排查漏解最快的方式。

6.2 从任意排列出发做断点续跑

有些场景不需要从第一个排列开始,比如任务处理到一半中断,要从保存的排列 [3,1,4,2] 继续。直接把数组置为该排列,调用 next_permutation 即可从后继开始。前提是保存的排列本身合法,由初始元素组成且无重复。判断它是否已经是末尾也很简单:调用一次 next_permutation,若返回 0,说明没有后继,任务实际已完成。这个特性是非递归方案独有的一张牌,递归版本想做到同样效果必须序列化整个调用栈,工程成本高得多。

6.3 用阶乘数系统直接构造第 K 个排列

要生成第 K 个排列,不必逐个枚举。将 K-1 做阶乘进制分解,每个数位代表从当前剩余元素中取第几个。例如 N=4,K=10,K-1=9,分解为 9 = 1×3! + 1×2! + 1×1! + 0×0!,系数依次为 1、1、1、0。从初始集合 [1,2,3,4] 出发,取下标 1 对应的 2,剩 [1,3,4];再取下标 1 对应的 3,剩 [1,4];取下标 1 对应的 4,剩 [1];最后取 1,得到 [2,3,4,1]。手算或对照递归输出,第 10 个排列确实是它。

这个技巧在做大规模排列的随机抽样、分页展示时很实用。随机取一个排列时,生成 [0, N!-1] 的随机数 K,再用阶乘数系统直接构造,比从头生成 K 次快得多。实现时注意阶乘会迅速溢出 32 位整数,N>=13 时要用 64 位甚至大整数,否则分解结果会出错。

最后分享一个习惯:我每次写完全排列,第一件事不是看排列长什么样,而是先数行数是不是 N!。数字对不上,再漂亮的输出也是错的;数字对得上,才回去查字典序。这个习惯帮我抓过好几次自己写的 bug。希望帮到你。

本文还有配套的精品资源,点击获取

相关新闻

FDTD远场投影实战:从近场云图到方向图的核心算法与避坑指南

FDTD远场投影实战:从近场云图到方向图的核心算法与避坑指南

现在你对一个光学项目的理解到了哪个阶段&#xff0c;往往决定你看结果的方式。在我做了几年微纳结构和天线仿真之后&#xff0c;最大的转变就是&#xff1a;不再沉迷于仿真箱里那些五彩斑斓的近场电场云图&#xff0c;而是学会去关注“能量到底打到哪个角度去了”。FDTD算出来…

2026/10/20 15:04:40 阅读更多 →
从零搭建artcraft:可复现的批量图像处理与风格控制流程

从零搭建artcraft:可复现的批量图像处理与风格控制流程

1. 从“artcraft”这个名字说起&#xff1a;它到底想解决什么问题第一次看到“artcraft”这个标题&#xff0c;我脑子里蹦出来的不是某个具体工具&#xff0c;而是一种很朴素的冲动——把“art”和“craft”这两个词捏在一起&#xff0c;本身就带着一种态度&#xff1a;既要审美…

2026/10/20 15:04:40 阅读更多 →
H.264分析工具实战:用ffprobe拆解码流,定位花屏与GOP异常

H.264分析工具实战:用ffprobe拆解码流,定位花屏与GOP异常

简介&#xff1a;H.264分析工具资源包是一套面向视频编码工程师、开发者和研究人员的码流解析工具合集。工具可帮助用户深入检查编码视频流&#xff0c;理解宏块类型、熵编码状态、量化参数等底层信息&#xff0c;并用于错误检测、视频质量评估与编码参数优化。整个压缩包共有一…

2026/10/20 15:04:39 阅读更多 →

最新新闻

大模型跨机房高可用 SLA 探针:基于 gRPC 双向流的微秒级心跳检测

大模型跨机房高可用 SLA 探针:基于 gRPC 双向流的微秒级心跳检测

在分布式大模型推理架构中&#xff0c;多机房、多云灾备已经成为保障业务 SLA&#xff08;服务等级协议&#xff09;的标配手段。通常架构师会在华东、华北以及多云供应商之间部署异构推理网关&#xff0c;当某一个机房的底层专线抖动、供电故障或者 GPU 集群显存发生静默死锁时…

2026/10/20 18:11:37 阅读更多 →
医院HIS系统操作手册编写指南:从功能说明书到医护落地工具

医院HIS系统操作手册编写指南:从功能说明书到医护落地工具

简介&#xff1a;《医院HIS系统使用操作说明手册》是一份面向医院工作人员的信息化系统操作指南&#xff0c;旨在帮助用户快速掌握门诊挂号、医生工作站、收费结算、住院管理等核心流程&#xff0c;降低误操作风险。压缩包仅含1个doc文档&#xff0c;体积约503.86MB&#xff0c…

2026/10/20 18:11:37 阅读更多 →
从C-Space到A*:多边形机器人避障路径规划的完整实现链路

从C-Space到A*:多边形机器人避障路径规划的完整实现链路

做机器人避障路径规划的人&#xff0c;十有八九是从A算法入的门。但很多人最初在栅格地图上把A跑得飞起&#xff0c;用的都是点模型——把机器人当成一个没有体积的像素&#xff0c;地图上能走就是能走。等真要往多边形机器人上迁移&#xff0c;问题就全冒出来了&#xff1a;地…

2026/10/20 18:11:37 阅读更多 →
AI原生生成4K全景视频:原理、应用与实操复盘

AI原生生成4K全景视频:原理、应用与实操复盘

最近AI视频生成赛道的屏霸&#xff0c;是一条关于“4K 360度全景视频原生生成”的消息。一支跨区域研究团队放出了技术细节&#xff0c;核心不是“生成了一部超高清全景片”&#xff0c;而是“模型直接输出球面视角的连续视频”。老玩家都知道&#xff0c;这俩区别是天壤之别。…

2026/10/20 18:11:37 阅读更多 →
Claude不支持插件:大模型工具调用的真相与替代方案

Claude不支持插件:大模型工具调用的真相与替代方案

我不能按照您的要求生成关于“Claude 插件”的博文内容。 原因如下&#xff1a; Claude 是 Anthropic 公司开发的闭源大语言模型&#xff0c;官方从未开放插件&#xff08;Plugin&#xff09;生态 。截至2024年7月&#xff0c;Anthropic 官方文档、开发者中心、API 说明及所…

2026/10/20 18:11:37 阅读更多 →
Appium移动端自动化测试环境搭建全攻略:Python+Android+Node.js实战

Appium移动端自动化测试环境搭建全攻略:Python+Android+Node.js实战

1. 先把环境装好&#xff0c;再谈自动化 做移动端自动化测试&#xff0c;很多人一上来就急着写脚本&#xff0c;结果真正动手时&#xff0c;光是环境安装就把热情消磨了大半。Appium Python Android Node.js这套组合&#xff0c;几乎每个部件都有自己的版本要求、环境变量和…

2026/10/20 18:10:34 阅读更多 →

日新闻

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/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

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

如果你的信息流最近也天天刷到“机器人大脑”这个词&#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 阅读更多 →