反转链表核心思路详解:从指针操作到递归迭代全掌握
链表这类题目说不上难但十几年里每次面试、每次带新人、每次看线上代码我都能碰到把反转写错的例子。写链表反转最考验的就是对指针或引用操作的清晰度——你有没有理清“谁指向谁、什么时候断链、断链前要把谁保存下来”这三件事。搞清楚这三点链表题目才算真正入门。这篇内容来自我接触过的真实场景有嵌入式底层的链表操作代码有笔试里的单链表逆序也有给新同事讲解C结构体链表基本语法时的反复演练。今天我把反转链表从思路、代码到变种全部拆开讲适合刚接触链表的同学也适合想系统复习链表问题的老手。文章里不会只给标准答案还会把每一步为什么要这么做、踩过哪些坑交代清楚。1. 先聊透单链表的结构1.1 节点和你手里那根“线”单链表是所有链表家族的最小公共单位。一个节点通常只有两个字段数据域和指针域。在C语言里结构体大概是这个模样typedef struct node { int data; struct node *next; } Node;在C里写法差不多只是结构体里可以直接放构造函数方便初始化struct Node { int data; Node* next; Node(int val) : data(val), next(nullptr) {} };Python和Java用的是类和对象思路完全一致一个存储值、一个存储下一个节点的引用。class ListNode: def __init__(self, val0, nextNone): self.val val self.next nextpublic class ListNode { int val; ListNode next; ListNode() {} ListNode(int val) { this.val val; } ListNode(int val, ListNode next) { this.val val; this.next next; } }链表的本质是“用指针把分散的内存串起来”。数组要求内存连续链表不要求数组按索引访问是O(1)链表必须从头遍历到目标位置是O(n)。这也是为什么链表插入和删除很方便只要改相邻节点的指针不需要像数组那样搬动后续所有元素。1.2 带头结点和不带头结点的差别很多教材和OS层面的实现都会区分“带头结点”和“不带头结点”。带头结点的链表有一个额外的头节点它的data不存储有效业务数据纯粹是为了统一插入删除逻辑让空表和非空表的操作一致。不带头结点的链表头指针直接指向第一个有效节点。反转的时候这两种处理方式有细微差别带头结点的链表反转的是头结点后面的那段不带头结点的链表要反转的是整条链。笔试和面试题默认都是不带头结点的单链表因为更裸、更考验基本功。你写代码前先确认清楚题目给的链表到底带不带头结点否则很容易出现多了一个节点或少了一个节点的问题。循环单链表算另一个变种尾节点的next不是null而是指回head。反转循环链表时最后一步要把原来的头节点设为新的尾节点并把它的next指回新的头节点否则循环性质会被破坏。2. 反转链表的核心思路2.1 你要处理的其实是“断链”问题反转一个单链表从直观上看就是让每个节点的next指向前一个节点。但链表是单向的你无法回头看前一个节点所以操作时必须用指针把“前一个节点”记住。其次一旦你改了当前节点的next原来next指向的后续节点就找不到了所以在修改之前必须把下一个节点先保存下来。说到底反转就是三句话保存下一个节点防止断链后丢失。把当前节点的next指向前一个节点。所有指针向后移动一位继续处理剩余部分。这三句话落到代码里就是一个迭代循环。你把它背下来不丢人但关键是要理解什么时候保存、什么时候修改、什么时候移动理解这三者的先后顺序基本就不会出错了。2.2 迭代法逐个节点改造迭代法是最直观、也最推荐新手先掌握的方法。它维护三个指针prev前驱节点、cur当前节点、next后继节点。假设原链表是1 - 2 - 3 - 4 - null初始状态prev为nullcur为1。进入循环next保存为2。让1的next指向prev也就是null此时1变成新链表的尾部。prev移动到1cur移动到2。重复以上过程直到cur为null。循环结束时prev恰好停在原链表的最后一个节点4上它成为新链表的头节点。所以你直接返回prev即可。如果以C语言表达核心代码不超过十行Node* reverseList(Node* head) { Node *prev NULL, *cur head, *next NULL; while (cur ! NULL) { next cur-next; // 第一步保存后继 cur-next prev; // 第二步反转指针 prev cur; // 第三步移动prev cur next; // 第四步移动cur } return prev; }这个过程的每一步我都建议新手在纸上画一遍。画到第三步和第四步的时候特别留意prev和cur的移动顺序如果你先把cur移到next再去改prev那就乱套了。很多初学者的错误代码就是这两行顺序写反了。2.3 递归法的思维转换递归法没有那么直观但它写出来非常简洁。递归的思考方式是假设我已经把当前节点后面的所有节点都反转好了那我只需要把当前节点接到这个反转后链表的尾节点上。Node* reverseListRecursive(Node* head) { if (head NULL || head-next NULL) { return head; } Node* newHead reverseListRecursive(head-next); head-next-next head; head-next NULL; return newHead; }这段代码里终止条件是“当前节点为空或者当前节点的下一个节点为空”因为当链表只有一个节点时反转结果就是它本身。递归返回上来的newHead始终是原链表的尾节点它在逐层返回过程中保持不变。真正做反转动作的是这两行head-next-next head; head-next NULL;从head的角度看它的下一个节点就是已经反转好的子链表的尾节点。让那个节点的next指向head再把head的next置空就完成了当前层的反转。不过我必须提醒你递归在处理超长链表时有爆栈风险。链表的递归深度等于链表长度几万、几十万节点的链表在默认栈空间下很容易出问题。所以笔试、面试场景用递归没问题但涉及生产环境的嵌入式数据链路我还是建议用迭代法。这里我画了一个简单的展开过程方便理解递归回代时的指针变化原链表1 - 2 - 3 - null递归到节点3时head-next为null返回3。回到节点2此时newHead是3执行 head-next-next head意思是3的next指向2再执行 head-next null原本2指向3的链接断开此时3 - 2 - null。回到节点1newHead仍然是3执行 head-next-next head即2的next指向1再执行 head-next null断掉1到2的链接最终形成 3 - 2 - 1 - null。递归法代码很短但它需要你习惯“先信任子问题已经完成”的思维方式。我第一次带新人时有人盯着这段代码看了半小时还没转过来这很正常。我的建议是每天写一遍递归反转连写一周脑子里的那根弦就搭上了。3. 反转链表的变种与进阶3.1 反转链表中一段区间如果说反转整条链表是基础题那“反转链表中的某一段”就是它的直接推广比如LeetCode第92题反转从位置m到n之间的节点m和n从1开始计数。思路并不复杂先找到第m-1个节点记作pre从第m个节点开始做(n-m)次局部反转实际上就是“把头插法的起点不断后移把后面的节点依次插到pre之后”。我直接说一种比较省脑子的实现方式先保留pre不动每次把当前节点cur后面的那个节点移动到pre的后面。这个过程重复n-m次就完成了区间反转。来看C实现ListNode* reverseBetween(ListNode* head, int m, int n) { if (head nullptr || m n) return head; ListNode dummy(0); dummy.next head; ListNode* pre dummy; for (int i 1; i m; i) { pre pre-next; } ListNode* cur pre-next; for (int i m; i n; i) { ListNode* next cur-next; cur-next next-next; next-next pre-next; pre-next next; } return dummy.next; }这里的dummy节点C里就是栈上一个临时节点非常有用。它人为制造一个不存储业务数据的头节点让m1的边界情况可以被统一处理当m等于1时pre就是dummy不需要额外判断pre是否为null。这个技巧在链表题目里出镜率极高我后面还会用到。3.2 每K个节点一组反转另一个高频变种是“K个一组反转链表”LeetCode第25题。要求每K个一组做反转组内反转后组间还要保持原顺序。做这道题我习惯分三步第一步统计链表长度算出共有几组完整的K。第二步对每一组执行局部反转反转前先记录当前组的头节点即pre的下一个节点。第三步把反转后的组的尾部接到下一组的头部。这里同样可以用dummy节点来简化边界。实现上因为组内反转和上一节区间反转的核心动作一样所以代码可以复用“移动节点到pre后面”的模式只是外层套一个循环。ListNode* reverseKGroup(ListNode* head, int k) { if (!head || k 1) return head; ListNode dummy(0); dummy.next head; ListNode* pre dummy; int len 0; for (ListNode* p head; p; p p-next) len; int groups len / k; for (int i 0; i groups; i) { ListNode* cur pre-next; for (int j 0; j k - 1; j) { ListNode* next cur-next; cur-next next-next; next-next pre-next; pre-next next; } pre cur; } return dummy.next; }这段代码最妙的点是每完成一组反转后pre正好指向这一组反转后的最后一个节点即原来的第一个节点也就是下一组的前驱。这个关系如果你不画图很容易写错。我见过很多人在这里把pre更新成别的节点导致下一组反转时pre-next指向错误。3.3 交替反转和中心扩展还有一类题目是在反转基础上做组合比如判断回文链表。经典做法是先找到链表的中点把后半段反转再从前半段头节点和后半段新头节点同时向后遍历比较节点值是否相等。找中点用快慢指针快指针每次走两步慢指针每次走一步。快指针到尾部时慢指针正好在中间位置。如果节点总数为偶数慢指针落在中间偏右如果为奇数慢指针落在正中间。此时把慢指针后面的链表反转就可以开始比较了。这类结合题本质上是“反转链表”能力在新场景里的复用。你先把反转基本功练熟后面遇到回文判断、两数相加链表形式、重排链表思路会顺很多。4. 多种语言落地与细节差异4.1 Python里的简洁与陷阱Python写链表反转代码可以非常简洁def reverse_list(head: ListNode) - ListNode: prev None cur head while cur: next_node cur.next cur.next prev prev cur cur next_node return prevPython的语法糖虽然多但链表操作没法偷懒该保存的引用还是要保存。一个常见的坑是有人在next_node赋值时写成next_node cur.next.next以为这样可以少走一步但这会导致当前的cur在修改next后下一次循环时无法正确获得下一个节点。另外Python里对象赋值是引用赋值所有节点本质上都是对象引用。你写prev, prev.next, cur cur, prev, cur.next这种三连赋值时要特别小心因为Python会先把右边的表达式全部求值再统一赋值所以这种写法在某些情况下是安全的。但为了可读性和避免误判我建议在链表操作里还是老老实实写成三行不要去炫技。4.2 Java的引用传递与GCJava和Python类似节点是对象引用。不过Java没有指针算术你不需要担心访存越界但容易出现“逻辑上丢链”的问题。丢链在Java里不会立刻报错GC也不会马上回收它只是让链表在逻辑上短了一截。这类问题在面试中不好发现在真实代码中更难排查。Java实现反转public ListNode reverseList(ListNode head) { ListNode prev null; ListNode cur head; while (cur ! null) { ListNode next cur.next; cur.next prev; prev cur; cur next; } return prev; }对比C语言版你会发现除了类型声明不同结构一模一样。这就是链表反转的通用性不管哪种语言本质都是“保存、指回、移动”三步循环。4.3 C/C的指针细节和内存安全C语言处理链表最需要关心的是空指针。很多段错误都来源于对null节点的next进行访问。我在嵌入式环境里写链表时会习惯性地在每个函数入口加上空指针判断if (head NULL) return NULL;注意反转函数里循环条件是cur ! NULL这个条件保证在循环体内访问cur-next是安全的。但有些人在循环结束时把cur-next赋值给prev此时cur已经为null就会出错。这类bug在调试器中表现为“访问了0x00000000地址”。C中如果使用STL或智能指针管理链表节点反转逻辑可以不变但构造节点模板时需要小心make_shared的顺序避免循环引用。我建议纯学算法时就用裸指针简单直接生产环境再考虑封装。4.4 常见语言实现对比语言节点类型核心风险反转核心语句C结构体指针空指针、内存泄漏cur-next prev;C结构体/类指针空指针、引用混乱同C语法更丰富Java类引用丢链难察觉cur.next prev;Python类引用引用误用、赋值顺序cur.next prev这四类语言的核心思想完全一致差异只体现在语法和运行时特性上。你在刷题时建议固定用一门语言把思路练透再换另一门语言验证自己对“引用赋值”的理解效果比多刷十道简单题更好。5. 常见错误和排查技巧实录5.1 三类高频Bug速查我在带人和自己写代码的过程中把链表反转的错误归纳成三类断链、成环、边界错。断链是指某一步操作后链表的后续节点找不到了。根因通常是没有在修改next之前保存下一个节点。排查方法是在循环内部打印cur-next的值对比是否有节点瞬间丢失。成环是指误把某个已经反转好的节点又指回之前的节点导致链表内部出现环形结构。常见于递归写法中处理尾节点next时写错对象。排查方法是在末尾检查新头节点一路走到null的步数如果步数超过原链表长度说明有环。边界错是指在空链表、单节点链表或反转区间覆盖整条链表时处理逻辑不完善。我的经验是把空链表、单节点、双节点、三节点四种极简输入先跑一遍能兜住大部分边界问题。5.2 调试工具和不变量检查链表调试最原始也最有效的方法是写一个遍历函数void printList(Node* head) { while (head) { printf(%d - , head-data); head head-next; } printf(null\n); }每次修改指针后调用一次能直观看到链表形态。如果你的环境支持断点调试记得在指针修改处设置条件断点比如当current target节点地址时触发。还有一个非常有用的不变量反转过程中从prev开始向前追溯可以走回原链表头部方向从cur开始向后可以走回原链表尾部方向两者不会相交。我在代码里检查过这个性质一旦被破坏说明头插或者指针移动有误。5.3 实际项目中的典型事故有一次线上出现内存越界最后定位到一个嵌入式协议栈的链表反转代码。问题出在链表节点是从内存池里分配的内存池的节点数量固定反转操作里有一个循环变量写成了后置自增导致越界访问。整个过程排查了很久因为越界不是立刻崩溃而是隔了一段执行路径后才暴露。从这里总结出一条经验凡是操作外部传入的链表不要假设它一定是以null结尾。有些老代码里链表节点尾部可能链接到哨兵节点反转前先确认链表终止条件再决定循环边界。6. 反转链表在真实场景中的价值6.1 内核与嵌入式的双向诉求反转链表并不是只有在面试题里才有存在感。在内核源代码里链表操作极为频繁经常需要在“正向遍历”和“反向遍历”之间切换。如果你没有双向链表可用反向遍历就得先把链表反转或者用递归压栈再弹栈。嵌入式环境内存紧张很多底层模块不引入复杂容器就靠单链表硬扛。一个典型需求是日志缓冲区满时需要把最新记录排在前面这时把存储日志的链表反转一下比插入头部要方便得多。因为日志节点可能来自不同中断优先级统一头插会造成优先级反转。这里的“反转”逻辑本质上就是我上面讲的迭代法。6.2 面试考察的并非代码本身面试官反复考反转链表不是为了那一百行代码而是看你的思维过程。你是否先说了思路是否主动讨论边界条件是否分析了时间复杂度和空间复杂度迭代法的时间复杂度是O(n)空间复杂度是O(1)递归法时间复杂度是O(n)但空间复杂度是O(n)栈深度。能把这个差异讲清楚比默写代码更能体现水平。很多同学在面试时直接把标准答案背出来结果面试官换个问法“如果头节点可能被修改呢”“如果链表有环呢”立马卡住。我的建议是逆向思考原始思路把链表的抽象结构吃透。链表题目万变不离其宗本质就是对节点引用的重排。理解这一点再变态的变种你也能抓主线。6.3 从反转链表到系统设计思维反转链表教会我的不仅是算法还有两种工程思维。一种是“先备份再修改”的安全意识在修改共享资源之前先把必要信息保存下来。这和数据库事务里先写日志再落盘是同一个道理。另一种是“dummy边界”的建模技巧在真实世界中很多问题都有边界情况硬编码处理边界只会让代码越来越乱不如人为引入一个虚拟节点让所有情况都变得整齐划一。这两点是我觉得链表反转带给工程师最重要的东西。7. 一个我私藏的调试技巧最后分享一个我经常用的“慢速反转观察法”。初学者在纸上画图总是一下子画完三步回头发现和代码对不上。我教新人的时候要求他们把循环体的四行代码分别标注为“保存、指回、移动、移动”每执行一行就在图上对应节点旁边画一个小箭头。坚持画一个链长5的完整过程基本就再也不会乱了。我自己在写一个复杂变种比如K组反转加区间限制之前也会先用5个节点的链表快速做一遍模拟。模拟不要求严谨但能帮我提前发现“next的next到底是谁”这种容易混淆的点。如果你经常在链表题上debug很久不妨试试先用小规模样例手推等指针关系理顺了再写代码。这个习惯帮我节省的时间远比想象中多。

相关新闻

Spring Boot毕业设计:电子产品销售平台从0到1完整开发指南

Spring Boot毕业设计:电子产品销售平台从0到1完整开发指南

又到毕业设计季,后台私信里问电子产品销售平台相关内容的最多。今年我不打算重复“跟着视频敲一遍”的老话,而是站在一个过来人的角度,把这类平台从0到1真正需要想清楚的几件事一次讲透:技术栈怎么选、库表怎么设计、下单链路怎么…

2026/10/3 3:00:56 阅读更多 →
奈奎斯特定理与香农定理:数字通信的采样边界与信道容量极限

奈奎斯特定理与香农定理:数字通信的采样边界与信道容量极限

1. 为什么数字世界里绕不开这两个公式做通信、音频、图像处理这行,只要跟“信号”沾边,奈奎斯特定理和香农定理就是躲不开的两块基石。我在做嵌入式音频采集的时候第一次正面撞上它们,当时只是照抄别人的采样率设置,结果换了一个传…

2026/10/3 2:59:55 阅读更多 →
企业内部网络管理系统实战:SpringBoot+Vue3+MyBatis

企业内部网络管理系统实战:SpringBoot+Vue3+MyBatis

企业里管网络的同学,估计都有同一种体验:设备台账在 Excel 里,IP 规划记在脑子里,工单记录散落在微信对话里,领导问起来“机房有多少台交换机”“某个 IP 现在通不通”的时候,只能现场翻表、问人、靠记忆。…

2026/10/3 2:59:55 阅读更多 →

最新新闻

SpringBoot+Vue+MySQL人事管理系统搭建实战与二次开发指南

SpringBoot+Vue+MySQL人事管理系统搭建实战与二次开发指南

我从一个实际项目交付的角度来聊聊这套人事系统。市面上叫"人事管理系统"的源码很多,但大多数要么后端老旧、要么前端没分离,真要拿来学习或者二次开发,折腾环境的时间比看代码的时间还长。这次拿到的是SpringBoot后端Vue前端MySQL…

2026/10/3 3:44:35 阅读更多 →
QT+VTK实现DICOM三维重建:体渲染与交互式剖切实战

QT+VTK实现DICOM三维重建:体渲染与交互式剖切实战

简介:本资源是一套面向医学影像处理与可视化开发者的实战型C项目源码,聚焦CT图像三维重建技术实现,适用于高校医工交叉方向学生、医疗软件开发者及VTK/QT进阶学习者。项目基于Qt构建跨平台图形界面,集成VTK完成CT序列图像预处理、…

2026/10/3 3:44:35 阅读更多 →
工资管理系统数据流程图解析:从数据字典到系统实现

工资管理系统数据流程图解析:从数据字典到系统实现

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

2026/10/3 3:44:35 阅读更多 →
同步发电机三相短路理论计算与MATLAB/Simulink仿真对比

同步发电机三相短路理论计算与MATLAB/Simulink仿真对比

同步发电机三相短路,一直是电力系统分析里最“硬核”的场景之一。前两天我重新把一个500MW汽轮发电机的机端三相短路案例,从手算标幺值到MATLAB/Simulink里搭模型完整做了一遍,整个过程很有意思:一边是教材上的次暂态、暂态、稳态…

2026/10/3 3:44:35 阅读更多 →
OpenShell使用指南:找回经典开始菜单与高效Windows定制

OpenShell使用指南:找回经典开始菜单与高效Windows定制

如果问我重装完Windows之后第一件事装什么,我的答案永远是OpenShell,没有任何悬念。这个工具当年叫Classic Shell,后来社区接手改名为OpenShell,一路从Win7跟到Win11,我办公室的电脑、家里的主力机、客厅的HTPC&#x…

2026/10/3 3:44:35 阅读更多 →
Scratch离线部署实战:从静态资源托管到页面异常排查

Scratch离线部署实战:从静态资源托管到页面异常排查

1. 部署前的思路梳理:先搞清楚你的Scratch离线版到底是什么形态Scratch离线部署这件事,听起来像是“下个安装包装一下”那么简单,但真到实操环节,你会发现坑比想象中多得多。尤其当你想做的是“把Scratch部署到内网服务器&#xf…

2026/10/3 3:43:34 阅读更多 →

日新闻

把回忆蒸馏成 AI 的浪漫实验:为什么你需要前任.skill 完整指南

把回忆蒸馏成 AI 的浪漫实验:为什么你需要前任.skill 完整指南

把回忆蒸馏成 AI 的浪漫实验:为什么你需要前任.skill 完整指南 【免费下载链接】ex-skill 前任 skill 项目地址: https://gitcode.com/gh_mirrors/exsk/ex-skill 前任.skill 是一个运行在 Claude Code 上的开源 Skill:导入微信、iMessage、短信、…

2026/10/3 0:00:27 阅读更多 →
45个经典Linux面试题:从命令到网络排障的完整考点解析

45个经典Linux面试题:从命令到网络排障的完整考点解析

刚开始带应届生的时候,我最头疼的就是他们拿着一摞Linux面试题背得滚瓜烂熟,一上机全露馅。后来自己从被面的人变成面别人的人,才慢慢摸清楚:Linux面试题考的根本不是答案本身,而是你面对一个不确定的系统问题时&#…

2026/10/3 0:01:28 阅读更多 →
SAP生产预留实战指南:MB21/MB23/MB25协同与MRP集成

SAP生产预留实战指南:MB21/MB23/MB25协同与MRP集成

简介:本资源是一份面向SAP ABAP开发人员、生产计划专员及ERP实施顾问的实操型操作指南,聚焦SAP生产预留核心业务场景,系统解决物料预留创建、查询、校验与批量处理等高频问题。文档以结构化方式覆盖预留背景原理、OMC2编码规则、工厂级参数配…

2026/10/3 0:01:28 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/10/1 19:40:48 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/10/1 19:41:40 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/10/1 20:05:24 阅读更多 →

月新闻

我发现了一个新思路:用 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/2 10:36:31 阅读更多 →
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/2 5:26:06 阅读更多 →
黑夜航拍船只数据集训练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/2 6:09:11 阅读更多 →