【算法--链表】114.二叉树展开为链表--通俗讲解

算法通俗讲解推荐阅读:
【算法--链表】83.删除排序链表中的重复元素--通俗讲解
【算法--链表】删除排序链表中的重复元素 II--通俗讲解
【算法--链表】86.分割链表--通俗讲解
【算法】92.翻转链表Ⅱ--通俗讲解
【算法--链表】109.有序链表转换二叉搜索树--通俗讲解


通俗易懂讲解"二叉树展开为链表"算法题目

一、题目是啥?一句话说清

给你一个二叉树的根节点,将它展开为一个单链表,其中节点的right指针指向下一个节点,left指针始终为null,且展开后的链表顺序与二叉树的先序遍历顺序相同。

示例:

  • 输入:root = [1,2,5,3,4,null,6]
  • 输出:[1,null,2,null,3,null,4,null,5,null,6](展开后的链表顺序为先序遍历顺序1,2,3,4,5,6)

二、解题核心

使用递归或迭代方法,对于每个节点,将其左子树插入到右子树之前,并保持先序遍历顺序。 这就像把一棵树拆成一条直线,保持从根节点开始先左后右的顺序。

三、关键在哪里?(3个核心点)

想理解并解决这道题,必须抓住以下三个关键点:

1. 先序遍历顺序保持

  • 是什么:展开后的链表顺序必须与二叉树的先序遍历(根节点、左子树、右子树)顺序一致。
  • 为什么重要:这是题目的基本要求,如果顺序错误,结果就不正确。

2. 原地修改指针

  • 是什么:直接修改原二叉树的指针,而不是创建新节点。
  • 为什么重要:题目要求原地修改,这样可以节省空间,但需要谨慎操作指针,避免丢失节点引用。

3. 左子树插入右子树之前

  • 是什么:对于每个节点,如果左子树不为空,找到左子树的最右节点,将右子树连接到该最右节点的right指针,然后将左子树移动到右子树位置。
  • 为什么重要:这确保了左子树的所有节点都在右子树之前,同时保持先序遍历顺序。

四、看图理解流程(通俗理解版本)

让我们用二叉树 [1,2,5,3,4,null,6] 的例子来可视化过程:

  1. 初始二叉树
markdown 复制代码
    1
   / \
  2   5
 / \   \
3   4   6
  1. 处理根节点1
    • 左子树不为空(节点2),找到左子树的最右节点(节点4)。
    • 将根节点的右子树(节点5)连接到节点4的right指针。
    • 将根节点的左子树(节点2)移动到右子树位置,左指针设为null。
    • 当前树变为:
markdown 复制代码
1
 \
  2
 / \
3   4
     \
      5
       \
        6
  1. 处理节点2
    • 左子树不为空(节点3),找到左子树的最右节点(节点3本身,因为无右子节点)。
    • 将节点2的右子树(节点4)连接到节点3的right指针。
    • 将节点2的左子树(节点3)移动到右子树位置,左指针设为null。
    • 当前树变为:
markdown 复制代码
1
 \
  2
   \
    3
     \
      4
       \
        5
         \
          6
  1. 处理节点3

    • 左子树为空,无需处理,继续处理右子树(节点4)。
  2. 处理节点4

    • 左子树为空,无需处理,继续处理右子树(节点5)。
  3. 处理节点5

    • 左子树为空,但右子树不为空(节点6),无需特殊操作。
  4. 最终链表: 所有节点通过right指针连接,left指针为null:1 → 2 → 3 → 4 → 5 → 6

五、C++ 代码实现(附详细注释)

cpp 复制代码
#include <iostream>
using namespace std;

// 二叉树节点定义
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

class Solution {
public:
    void flatten(TreeNode* root) {
        // 当前节点不为空时进行处理
        while (root != nullptr) {
            // 如果左子树为空,直接处理右子树
            if (root->left == nullptr) {
                root = root->right;
            } else {
                // 找到左子树的最右节点
                TreeNode* pre = root->left;
                while (pre->right != nullptr) {
                    pre = pre->right;
                }
                // 将右子树连接到左子树的最右节点
                pre->right = root->right;
                // 将左子树移动到右子树位置
                root->right = root->left;
                root->left = nullptr;
                // 处理下一个节点
                root = root->right;
            }
        }
    }
};

// 辅助函数:打印展开后的链表
void printFlattenedTree(TreeNode* root) {
    while (root != nullptr) {
        cout << root->val << " ";
        root = root->right;
    }
    cout << endl;
}

// 测试代码
int main() {
    // 构建示例二叉树:[1,2,5,3,4,null,6]
    TreeNode* root = new TreeNode(1);
    root->left = new TreeNode(2);
    root->right = new TreeNode(5);
    root->left->left = new TreeNode(3);
    root->left->right = new TreeNode(4);
    root->right->right = new TreeNode(6);
    
    Solution solution;
    solution.flatten(root);
    
    printFlattenedTree(root); // 输出:1 2 3 4 5 6
    
    // 释放内存(实际面试中可能不需要完整释放)
    return 0;
}

六、注意事项

  • 指针操作安全:在修改指针时,确保不会丢失节点的引用,特别是在寻找左子树的最右节点时。
  • 递归与迭代:这里使用迭代方法,避免了递归的栈空间开销,更高效。但递归方法也可以实现,需要注意递归深度。
  • 左子树为空的情况:如果左子树为空,直接处理右子树,简化操作。
  • 时间复杂度:每个节点被访问常数次,时间复杂度为 O(n),其中 n 是节点数。
  • 空间复杂度:迭代方法只使用常数额外空间,空间复杂度为 O(1)。

掌握这三点,你就能高效解决二叉树展开为链表问题。这道题考察了对二叉树遍历和指针操作的理解。多练习几次,注意细节,就能熟练运用。

相关推荐
道可到23 分钟前
淘宝面试原题 Java 面试通关笔记 02|从编译到运行——Java 背后的计算模型(面试可复述版)
java·后端·面试
2401_8414956431 分钟前
【机器学习】朴素贝叶斯法
人工智能·python·数学·算法·机器学习·概率论·朴素贝叶斯法
Nathan2024061636 分钟前
Kotlin-Sealed与Open的使用
android·前端·面试
程序员二黑42 分钟前
告别硬编码!5个让Web自动化脚本更稳定的定位策略
面试·单元测试·测试
时间醉酒1 小时前
逻辑回归(四):从原理到实战-训练,评估与应用指南
人工智能·python·算法·机器学习·逻辑回归
Zheng照邻、1 小时前
VLM Prompt优化之 DynaPrompt(ICLR 2025)论文总结
人工智能·算法·语言模型·prompt·aigc
CoovallyAIHub1 小时前
机器人“大脑”遭遇认知冻结攻击!复旦等提出FreezeVLA,一张图片即可瘫痪多模态大模型
深度学习·算法·计算机视觉
无敌最俊朗@2 小时前
死锁 (Deadlock) 深度解析
算法
懒羊羊不懒@2 小时前
C语言指针进阶(进阶)
java·开发语言·面试
西阳未落2 小时前
欧拉路径与欧拉回路
算法·深度优先