二叉树转双向链表复用left/right指针:pre记录前驱并动态更新,head仅在首次访问时赋值锁定起点,中序递归自然衔接子树,循环链表需遍历结束后首尾相连。

二叉树转双向链表的核心不在新建结构,而在复用原有指针——把 left 当作 prev,把 right 当作 next,全程不分配新节点。关键在于变量如何定义、何时更新、边界怎么处理。
pre 指针:记录上一个已接入链表的节点
pre 是贯穿整个中序遍历的“游标”,它始终指向当前正在处理节点的前驱节点(即链表尾部)。初始为 None 或 null,表示尚未接入任何节点。
- 每次访问到一个节点时,先将其
left指向pre - 若
pre非空,再让pre.right指向当前节点,完成双向连接 - 最后把
pre更新为当前节点,为下一次遍历准备
head 变量:只赋值一次,锁定链表起点
head 用于保存中序遍历遇到的第一个节点,也就是整棵树最左端的节点。它只在 pre 为空时被赋值一次,之后不再改动。
- 当
pre == null时,说明这是中序第一个访问到的节点,此时head = current - 后续所有节点都不再影响 head,确保返回的是真正的“最左节点”
- 无需额外查找——head 就是首次触发
pre赋值的那个节点
递归调用中的指针衔接逻辑
中序递归本身不返回值,但靠 pre 的持续传递,让父子/兄弟节点自然串连。重点注意子树衔接处的指针归属:
- 左子树遍历完后,
pre指向左子树最右节点(即左链表尾) - 处理根节点时,自动与该尾节点双向连接
- 右子树遍历开始时,
pre已是根节点,右子树第一个访问节点(其最左节点)会接在根之后
收尾处理:是否需要成环?看题目要求
多数题目只要求排序双向链表,但部分变体(如剑指 Offer 36)明确要求循环双向链表。
- 非循环:返回 head 即可,头节点
left == null,尾节点right == null - 循环:遍历完成后,让
head.left = pre(此时 pre 是尾节点),同时pre.right = head - 注意:循环操作必须在中序遍历完全结束后进行,不能在递归过程中做










