顺序队列、链式队列与约瑟夫环的C++实现与避坑指南

队列这个结构,刚学数据结构那会儿我觉得它比栈简单——不就是先进先出嘛,能有多难。结果第一次用数组手写循环队列,被取模运算绕得头晕;第一次用链表实现队列,指针操作写反了导致内存泄漏;第一次做约瑟夫环,用数组模拟报数,边界条件调了整整一个下午。这三个东西单独拎出来都不算复杂,但放在一起恰好覆盖了线性结构里最核心的几类问题:连续存储与离散存储的取舍、循环利用空间的技巧、以及用数据结构解决经典数学问题的建模思路。下面我就按自己踩坑的顺序,把顺序队列、链式队列和约瑟夫环的C++实现从头到尾捋一遍,代码全部实测可跑,关键位置我会解释为什么这么写而不是那么写。

1. 为什么队列值得单独花时间啃

很多人学数据结构有个误区:觉得队列太简单,看一眼就跳过去,把精力全砸在树和图上面。我当初也这么想,直到后来做项目时遇到一个消息缓冲的需求,才发现自己对队列的理解全是漏洞。

队列的本质是受限的线性表——只允许在一端插入,另一端删除。这个限制看起来是"阉割"了线性表的能力,但实际上它带来的语义非常明确:先来的先被处理。这个语义在操作系统调度、网络数据包缓冲、打印任务排队、广度优先搜索等场景里反复出现。你如果只是背下来"先进先出"四个字,遇到具体问题照样写不对。

顺序队列和链式队列解决的是同一个问题,但底层存储方式完全不同。顺序队列用一段连续内存,靠两个下标(front和rear)标记队头和队尾;链式队列用离散节点,靠指针串联。两者各有各的坑:顺序队列如果不做循环处理,会出现"假溢出"——明明数组前面有空位,但因为rear已经到头了,新元素就是插不进去;链式队列则要小心指针操作顺序,写反一步就是内存泄漏或者段错误。

约瑟夫环则是队列的一个经典应用场景。问题描述很简单:n个人围成一圈,从第一个人开始报数,报到m的人出列,然后从下一个人继续报数,直到所有人出列。用队列来模拟这个过程非常自然——每次把队头元素移到队尾,相当于"跳过"一个人;报到m时直接出队,相当于"淘汰"一个人。但真正写起来,边界条件、报数起点、剩余人数的处理,每一个都可能让你调试半天。

我下面会先讲顺序队列的循环实现,再讲链式队列的指针操作,最后用队列思路解约瑟夫环。每一部分都会给出完整代码、关键逻辑解释,以及我在实际调试中总结的注意事项。

2. 顺序队列的循环数组实现与假溢出陷阱

2.1 顺序队列的基本结构设计

顺序队列最直觉的做法是:开一个固定大小的数组,用front记录队头位置,用rear记录队尾位置。入队时把元素放到rear位置,然后rear加一;出队时取走front位置的元素,然后front加一。空队列的条件是front等于rear。

这个设计在元素只进不出的情况下没问题,但一旦有出队操作,front就会往后移动,前面空出来的位置就永远浪费了。比如数组大小是5,你入队5个元素,rear到了5(越界),此时出队2个元素,front变成2,数组下标0和1的位置空着,但rear已经不能再加了。这就是假溢出——不是真的没空间,而是空间没有被循环利用。

解决办法是把数组在逻辑上弯成一个环。当rear到达数组末尾时,如果前面还有空位,就让它绕回到下标0继续存放。实现上就是每次移动下标时做一次取模运算:rear = (rear + 1) % capacity。这样数组的物理存储还是线性的,但逻辑上变成了循环的。

这里有一个关键细节:如何区分队空和队满。如果不做特殊处理,队空时front等于rear,队满时front也等于rear(因为rear绕了一圈追上了front),两者条件冲突。常见的解决方案有三种:

  • 牺牲一个存储单元:队满的条件变成(rear + 1) % capacity == front,也就是说当rear的下一个位置是front时就算满,实际可用容量是capacity减一。
  • 增加一个size变量记录当前元素个数:队空时size为0,队满时size等于capacity,判断简单直接。
  • 增加一个tag标记:记录最后一次操作是入队还是出队,配合front和rear判断。

我个人最推荐第二种——加一个size变量。原因很简单:代码可读性最好,不需要在脑子里绕取模逻辑,而且实际项目中队列的容量通常不会卡到极限,多一个int变量的开销完全可以忽略。下面给出的实现就用这种方式。

2.2 循环队列的完整C++实现

#include <iostream> using namespace std; template<typename T> class CircularQueue { private: T* data; // 动态数组 int capacity; // 容量 int front; // 队头下标 int rear; // 队尾下标(下一个入队位置) int count; // 当前元素个数 public: CircularQueue(int cap = 10) { capacity = cap; data = new T[capacity]; front = 0; rear = 0; count = 0; } ~CircularQueue() { delete[] data; } bool isEmpty() const { return count == 0; } bool isFull() const { return count == capacity; } int size() const { return count; } bool enqueue(const T& value) { if (isFull()) { return false; // 队列已满,入队失败 } data[rear] = value; rear = (rear + 1) % capacity; count++; return true; } bool dequeue(T& value) { if (isEmpty()) { return false; // 队列为空,出队失败 } value = data[front]; front = (front + 1) % capacity; count--; return true; } bool getFront(T& value) const { if (isEmpty()) { return false; } value = data[front]; return true; } void print() const { if (isEmpty()) { cout << "队列为空" << endl; return; } cout << "队列元素: "; int idx = front; for (int i = 0; i < count; i++) { cout << data[idx] << " "; idx = (idx + 1) % capacity; } cout << endl; } };

这段代码有几个地方值得展开说。

为什么用模板:队列里存什么类型的数据是不确定的,可能是int、string,也可能是自定义的结构体。用模板可以让同一份代码适配所有类型,避免为每种类型重复写一遍。如果你暂时不熟悉模板,把template<typename T>去掉,把所有T换成int,逻辑完全一样。

为什么用动态数组而不是固定大小数组:固定大小数组在编译期就确定了容量,不够灵活。用new T[capacity]在堆上分配内存,容量可以在构造时指定,用完之后在析构函数里delete[]释放。这里要注意,如果是存自定义类型,T需要有无参构造函数或者你需要在分配时做额外处理,不过对于基础类型和标准库类型都没问题。

入队和出队的返回值设计:我让enqueue和dequeue返回bool,表示操作是否成功。这样做的好处是调用方可以明确知道操作结果,而不是默默失败。有些教材的实现直接返回void,队列满时什么都不做,调用方根本不知道数据有没有进去。实际项目中这种沉默失败是灾难性的。

取模运算的位置:rear = (rear + 1) % capacity这行代码是循环队列的核心。当rear等于capacity减一时,加一变成capacity,取模后变成0,正好绕回数组开头。front的移动同理。你可以手动模拟一下:capacity为5,rear从0开始,依次变成1、2、3、4、0、1……永远不会越界。

2.3 实测中容易踩的三个坑

第一个坑:取模运算的优先级。C++中%的优先级和*、/同级,高于+和-。所以rear + 1 % capacity会被解析成rear + (1 % capacity),结果完全错误。必须写成(rear + 1) % capacity。我当初就是因为少写了一对括号,调试了半个小时才发现问题。

第二个坑:遍历队列时的下标处理。因为队列是循环的,不能简单地从front循环到rear,因为rear可能小于front。正确的做法是用count控制循环次数,每次下标加一后取模。上面print函数就是这么写的。如果你用for (int i = front; i != rear; i = (i + 1) % capacity)也可以,但要注意队列满时front等于rear,这个循环一次都不会执行,需要额外处理。

第三个坑:拷贝构造和赋值运算符。上面的类用了动态内存分配,如果直接拷贝对象,两个对象会共享同一块内存,析构时就会double free。正确的做法是实现拷贝构造函数和赋值运算符(深拷贝),或者用std::vector代替裸指针。为了代码简洁,我这里没有展开,但你在实际使用中一定要注意。如果只是局部使用、不涉及对象拷贝,问题不大;一旦要把队列作为参数传递或者放入容器,就必须处理这个问题。

提示:如果你用的是C++11及以上标准,可以用std::unique_ptr<T[]>来管理数组内存,这样连析构函数都不用写了,而且自动禁止拷贝,避免误用。

3. 链式队列的指针操作与边界处理

3.1 链式队列的节点设计与头尾指针

顺序队列的容量是固定的,一旦满了就没法再入队。链式队列没有这个问题——每个元素是一个独立的节点,用指针串联起来,理论上只要内存够就可以一直入队。链式队列需要维护两个指针:front指向队头节点,rear指向队尾节点。入队在rear后面接一个新节点,出队删除front指向的节点。

这里有一个设计选择:要不要带头节点。带头节点的意思是,front指向一个不存数据的哑节点,真正的队头元素是front->next。带头的好处是入队和出队的代码可以统一处理,不需要单独判断队列是否为空。不带头的代码更直观,但空队列时插入第一个元素需要特殊处理。

我两种都写过,个人更倾向于不带头节点,因为代码更短,逻辑更直接。但如果你追求代码的对称性和统一性,带头节点也是很好的选择。下面给出的实现不带头节点。

#include <iostream> using namespace std; template<typename T> struct Node { T data; Node* next; Node(const T& d) : data(d), next(nullptr) {} }; template<typename T> class LinkedQueue { private: Node<T>* front; // 队头指针 Node<T>* rear; // 队尾指针 int count; // 元素个数 public: LinkedQueue() : front(nullptr), rear(nullptr), count(0) {} ~LinkedQueue() { while (front != nullptr) { Node<T>* temp = front; front = front->next; delete temp; } } bool isEmpty() const { return front == nullptr; } int size() const { return count; } void enqueue(const T& value) { Node<T>* newNode = new Node<T>(value); if (isEmpty()) { front = rear = newNode; } else { rear->next = newNode; rear = newNode; } count++; } bool dequeue(T& value) { if (isEmpty()) { return false; } value = front->data; Node<T>* temp = front; front = front->next; if (front == nullptr) { rear = nullptr; // 队列变空,rear也要置空 } delete temp; count--; return true; } bool getFront(T& value) const { if (isEmpty()) { return false; } value = front->data; return true; } void print() const { if (isEmpty()) { cout << "队列为空" << endl; return; } cout << "队列元素: "; Node<T>* cur = front; while (cur != nullptr) { cout << cur->data << " "; cur = cur->next; } cout << endl; } };

3.2 入队和出队的指针变化过程

链式队列的入队操作分两种情况。如果队列为空,新节点既是队头也是队尾,所以front = rear = newNode。如果队列不为空,把新节点接到rear的后面,然后更新rear指向新节点。注意这里不能先更新rear再连接,否则就找不到原来的队尾了。顺序必须是:先rear->next = newNode,再rear = newNode。

出队操作也分两种情况。如果出队后队列变空(front变成了nullptr),必须把rear也置为nullptr。这一步非常容易漏掉。如果你漏了,rear会指向一个已经被delete的节点,下次入队时rear->next = newNode就会访问已释放的内存,程序可能崩溃或者产生不可预期的行为。我当初就是因为漏了这一行,程序在小数据量下运行正常,一旦数据量大了就随机崩溃,排查了很久才定位到。

内存释放的顺序:出队时先用temp保存front,然后front后移,最后delete temp。顺序不能反——如果先delete front,再访问front->next就是访问已释放内存。这个错误在初学者代码里非常常见。

析构函数的实现:析构时需要遍历整个链表,逐个delete节点。注意在delete当前节点之前,要先把front移到下一个节点,否则就找不到后续节点了。上面的析构函数就是这么写的。

3.3 链式队列相比顺序队列的取舍

链式队列和顺序队列没有绝对的优劣,关键看使用场景。我整理了一个对比表格:

对比维度顺序队列(循环数组)链式队列
内存分配一次性分配连续内存每次入队动态分配节点
容量限制固定,满了无法入队理论上无限制,受内存约束
缓存友好度高,连续内存访问快低,节点分散在堆上
入队时间复杂度O(1)O(1),但有new操作开销
出队时间复杂度O(1)O(1),但有delete操作开销
内存开销仅数组本身每个节点多一个指针域
适用场景容量可预估、追求性能容量不确定、频繁增删

如果你的队列容量可以预估,比如做嵌入式开发时缓冲区大小固定,顺序队列更合适——没有动态内存分配,不会产生内存碎片,访问速度也更快。如果容量完全不可预测,比如处理网络请求,链式队列更灵活。

还有一个实际因素:动态内存分配的开销。每次入队都new一个节点,每次出队都delete一个节点,在高频场景下这个开销不可忽视。有些高性能场景会用内存池来优化,预先分配一批节点循环使用,避免频繁的系统调用。不过这属于进阶优化,初学阶段先把基础实现搞扎实。

注意:链式队列的enqueue操作如果new失败(内存耗尽),会抛出std::bad_alloc异常。在资源受限的环境下,你可能需要捕获这个异常并做降级处理,而不是让程序直接崩溃。

4. 约瑟夫环的队列建模与模拟实现

4.1 约瑟夫环问题的本质拆解

约瑟夫环的描述有很多版本,核心逻辑是一样的:n个人围成一圈,从某个人开始报数,每报到m的人出列,然后从出列者的下一个人重新开始报数,直到所有人出列。要求输出出列的顺序。

这个问题的数学模型其实是一个递推问题,有O(n)的数学解法。但用队列来模拟是最直观的,也是理解队列应用的绝佳案例。用队列模拟的思路是:

  1. 把n个人依次入队。
  2. 从队头开始,每次把队头元素取出并重新入队到队尾,相当于"这个人报数不是m,跳过"。
  3. 当报数到m时,队头元素直接出队,不再入队,这个人被淘汰。
  4. 重复上述过程,直到队列为空。

这里的关键是报数计数器的维护。你可以用一个变量从1开始计数,每处理一个人就加一,当计数器等于m时执行淘汰并重置计数器为1。也可以每轮固定移动m减一次,然后淘汰队头。两种写法等价,但后者代码更简洁。

4.2 用链式队列模拟约瑟夫环

#include <iostream> using namespace std; // 复用上面的LinkedQueue,这里简化为int类型 void josephus(int n, int m) { LinkedQueue<int> q; for (int i = 1; i <= n; i++) { q.enqueue(i); } cout << "出列顺序: "; int count = 0; // 已出列人数 while (!q.isEmpty()) { int cur; q.dequeue(cur); count++; if (count % m == 0) { // 报到m,出列 cout << cur << " "; } else { // 未报到m,重新入队 q.enqueue(cur); } } cout << endl; } int main() { int n = 7, m = 3; cout << "n = " << n << ", m = " << m << endl; josephus(n, m); return 0; }

运行结果:出列顺序: 3 6 2 7 5 1 4。

这个实现非常简洁,但有几个细节值得注意。

为什么用count % m而不是维护一个独立的报数变量:count记录的是当前处理到第几个人(包括已经出列和重新入队的),每处理一个人count加一。当count能被m整除时,说明当前这个人正好是第m个报数的,应该出列。这种写法避免了在出列后重置计数器的操作,逻辑更统一。

出列后为什么不需要特殊处理:因为出列的人直接从队列中移除了,队列的front自动指向下一个人,下一轮循环自然从下一个人开始报数。这正是队列"先进先出"特性带来的便利——你不需要手动维护"下一个人是谁"。

时间复杂度分析:每处理一个人,要么出列(O(1)),要么重新入队(O(1))。总共处理的人次数是n乘以m(因为每淘汰一个人需要跳过m减一个人),所以时间复杂度是O(n*m)。当n和m都很大时,这个模拟会非常慢。比如n等于一百万、m等于一百万,运算量是万亿级别,肯定超时。这时候就需要用数学递推法,把时间复杂度降到O(n)。

4.3 数学递推法的思路与对比

数学递推法的核心是找到出列编号的递推关系。假设f(n, m)表示n个人报数m时,最后剩下的人(或者第一个出列的人)的编号。经过推导,可以得到递推公式:f(n, m) = (f(n-1, m) + m) % n,其中f(1, m)等于0(假设编号从0开始)。

这个公式的含义是:n个人问题的解,等于n减一个人问题的解加上m,再对n取模。你可以这样理解:淘汰一个人之后,剩下n减一个人重新围成一圈,但起点变了,需要做一个偏移映射。

用递推法求第一个出列的人:

int josephusMath(int n, int m) { int result = 0; // f(1, m) = 0 for (int i = 2; i <= n; i++) { result = (result + m) % i; } return result + 1; // 转换回1-based编号 }

这个算法的时间复杂度是O(n),空间复杂度是O(1),比队列模拟快得多。但它只能求出最后剩下的人,如果要输出完整的出列顺序,还是得用模拟法或者更复杂的数学方法。

两种方法的适用场景:如果只需要知道最后谁留下,用数学递推法;如果需要完整的出列顺序,用队列模拟法。在实际面试中,面试官可能会先让你用模拟法写,然后问你有没有更优的解法,这时候数学递推法就是加分项。

提示:约瑟夫环的数学解法有多种变体,有的求最后剩下的人,有的求第k个出列的人。递推公式的初始条件和边界处理略有不同,使用前一定要确认清楚问题的具体定义。

5. 三个实现串起来看:存储方式如何决定代码形态

把顺序队列、链式队列和约瑟夫环放在一起看,会发现一个有意思的规律:底层存储方式直接决定了代码的形态和容易出错的地方。

顺序队列的代码里到处都是取模运算,因为你要在逻辑上把线性数组弯成环。取模运算的优先级、边界值的处理、队空队满的判断,这些坑都源于"用连续内存模拟循环"这个核心设计。你如果理解了这一点,就能预判哪些地方容易出问题——所有涉及下标移动的地方都要检查取模,所有涉及front和rear比较的地方都要考虑绕圈的情况。

链式队列的代码里到处都是指针操作,因为你要手动管理节点的连接和释放。指针操作顺序、空队列的特殊处理、内存泄漏的防范,这些坑都源于"用离散节点维护顺序关系"这个核心设计。你如果理解了这一点,就能预判哪些地方容易出问题——所有涉及指针赋值的地方都要考虑顺序,所有涉及节点删除的地方都要检查是否有其他指针还指向它。

约瑟夫环的代码则体现了数据结构选择对问题建模的影响。用队列来模拟,代码不到二十行,逻辑清晰到几乎不需要注释。如果用数组来模拟,你需要手动维护当前报数位置、标记已出列的人、处理数组越界绕回,代码量至少翻倍,而且容易出错。这就是数据结构的价值——选对了结构,问题本身就变简单了。

我在实际编码中总结了一个判断原则:如果问题的核心操作是"在一端加入、在另一端删除",就用队列;如果核心操作是"在一端加入、在同一端删除",就用栈;如果核心操作是"随机访问任意位置",就用数组或链表。约瑟夫环的核心操作是"跳过一个人(从队头移到队尾)"和"淘汰一个人(从队头删除)",正好符合队列的操作模式,所以队列是最自然的选择。

再补充一个实际调试中的经验:先用小数据量验证逻辑,再逐步增大。比如约瑟夫环,先用n等于5、m等于2跑一遍,手动推演结果,确认代码输出和手算一致。然后再用n等于7、m等于3验证。如果小数据量下结果正确,大数据量下出错,那基本是边界条件或者内存问题;如果小数据量下就错了,那就是核心逻辑有问题。这个排查思路帮我省了很多时间。

最后说一个关于模板类的小坑。上面的顺序队列和链式队列都用了模板,如果你把类的声明和实现分开写在.h和.cpp文件里,链接时会报"未定义引用"的错误。原因是模板的实例化需要在编译期完成,编译器看不到实现就无法生成代码。解决办法有两个:把实现也写在头文件里,或者在.cpp文件末尾显式实例化你需要的类型。我一般直接把实现写在头文件里,省事。

代码这东西,看一遍和写一遍完全是两回事。顺序队列的取模、链式队列的指针、约瑟夫环的边界,每一个我都建议你亲手敲一遍,故意改错几个地方,看看会出什么现象。比如把(rear + 1) % capacity的括号去掉,把出队时的rear = nullptr删掉,把约瑟夫环的count % m改成count == m,跑一下看看结果有什么变化。这种"故意犯错再修复"的练习方式,比照着正确代码抄一遍有效得多。

相关新闻

REA模型实战:用事件驱动解决业务与财务数据不一致

REA模型实战:用事件驱动解决业务与财务数据不一致

去年年中&#xff0c;我在梳理"模拟项目X"的订单履约链路时&#xff0c;被一个简单的问题卡住了&#xff1a;财务说账上还有120万应收账款&#xff0c;业务说早该催款的只有80万&#xff0c;两边数字对不上。系统里明明都用了同一套订单数据&#xff0c;为什么算出来…

2026/10/20 12:59:53 阅读更多 →
Java调用YOLOv11性能优化:GraalVM Native Image提升12倍吞吐实践

Java调用YOLOv11性能优化:GraalVM Native Image提升12倍吞吐实践

我先交代一下背景。最近在折腾一个工业质检项目&#xff0c;Java 后端要调用 YOLOv11 做实时缺陷检测&#xff0c;模型本身在 GPU 上跑得飞快&#xff0c;但整套 Java 调用链路拿出来一看&#xff0c;慢得离谱&#xff1a;单次请求最坏 600 多毫秒&#xff0c;并发一上来&#…

2026/10/20 12:59:53 阅读更多 →
需求预测与分仓规划实战:从回归建模到约束求解的完整攻略

需求预测与分仓规划实战:从回归建模到约束求解的完整攻略

简介&#xff1a;面向天池“菜鸟-需求预测与分仓规划”赛题&#xff0c;这套资源为参赛者和供应链数据分析学习者提供了一份可复现的竞赛方案。方案覆盖需求预测与分仓规划两大核心模块&#xff0c;采用XGBoost、GBDT、随机森林、SVR等多种回归模型&#xff0c;并对不同分仓单独…

2026/10/20 12:59:53 阅读更多 →

最新新闻

智能驾驶感知算法岗面试高频考点与实战指南

智能驾驶感知算法岗面试高频考点与实战指南

智能驾驶感知算法岗的面试&#xff0c;跟我平时帮人做模拟面试时看到的准备方式&#xff0c;几乎不在一个频道上。很多人拿到一份八股题集就开始背&#xff1a;Transformer结构、Focal Loss公式、NMS流程、BEV感知演进……背得滚瓜烂熟&#xff0c;结果一进面试间&#xff0c;被…

2026/10/20 13:38:46 阅读更多 →
Hyper-Laplacian先验快速去卷积:从原理到工程实现

Hyper-Laplacian先验快速去卷积:从原理到工程实现

简介&#xff1a;这份资源是图像去模糊方向经典论文《Fast Image Deconvolution using Hyper-Laplacian Priors》的配套Matlab实现&#xff0c;面向从事图像恢复、计算摄影与视觉研究的学生和开发者&#xff0c;用于解决模糊图像复原中卷积核未知、边缘细节难以保持的问题。压缩…

2026/10/20 13:38:46 阅读更多 →
TensorFlow从零手写ResNet18:80行代码详解残差连接与BasicBlock实现

TensorFlow从零手写ResNet18:80行代码详解残差连接与BasicBlock实现

1. 为什么80行代码值得认真拆解ResNet18这个网络结构&#xff0c;搞深度学习的人几乎没有不知道的。2015年那篇残差学习的论文出来之后&#xff0c;基本上把深层网络训练难的问题给解决了。但很多人第一次接触ResNet&#xff0c;要么是直接调tf.keras.applications.ResNet50&am…

2026/10/20 13:38:46 阅读更多 →
Hyper-Laplacian先验快速去卷积:查找表加速非凸优化

Hyper-Laplacian先验快速去卷积:查找表加速非凸优化

简介&#xff1a;这份资源是图像去模糊领域经典论文《Fast Image Deconvolution using Hyper-Laplacian Priors》的配套Matlab实现&#xff0c;面向从事图像恢复、计算摄影与视觉研究的学生和开发者&#xff0c;用于解决模糊图像复原及盲去卷积中卷积核与清晰图像联合估计的问题…

2026/10/20 13:38:46 阅读更多 →
10月arXiv机器学习论文盘点:强化学习、长尾分布与数据效率

10月arXiv机器学习论文盘点:强化学习、长尾分布与数据效率

1. 另类入口&#xff1a;当arXiv变成一座每周更新的森林如果说学术搜索像一张精准的地图&#xff0c;那arXiv的cs.LG板块就更像一片每周定时更新的森林——你永远知道自己能在这里找到最新的机器学习论文&#xff0c;但也正因为"最新"这两个字&#xff0c;每次走进来…

2026/10/20 13:38:46 阅读更多 →
AI编程工具进化:从代码补全到能独立交付项目的“许愿机”

AI编程工具进化:从代码补全到能独立交付项目的“许愿机”

说实话&#xff0c;我已经不太想用“Coding Agent”来称呼手上这批AI开发工具了。不是矫情&#xff0c;是最近连续几周用它们做真正的项目——不是教它写个冒泡排序或者生成一段样板代码&#xff0c;而是从需求梳理、数据结构设计到部署脚本、线上监控告警的完整链路走下来——…

2026/10/20 13:37:45 阅读更多 →

日新闻

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 阅读更多 →