坚持刷题|二叉树展开为链表


Hello,大家好,我是阿月。坚持刷题,老年痴呆追不上我,今天刷:二叉树展开为链表

题目

添加链接描述
在这里插入图片描述

考察点

考察点主要是对二叉树的遍历和指针操作的理解,以及对递归或迭代的运用能力:

  • 对二叉树遍历的理解:在展开二叉树为链表的过程中,需要对二叉树进行遍历,这里需要使用前序遍历(Pre-order traversal)的思想。
  • 对指针操作的理解:展开二叉树为链表需要进行指针的移动和重定向,需要理解如何通过指针操作改变二叉树的结构。
  • 对迭代的理解:使用迭代的方法来展开二叉树,这需要理解迭代的思想,并能够设计迭代的逻辑。
  • 对递归的理解:除了迭代,展开二叉树为链表也可以通过递归的方式实现,需要能够理解并实现递归的解法。

代码实现

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    
    TreeNode(int x) {
        val = x;
    }
}

public class FlattenBinaryTreeToLinkedList {
    public void flatten(TreeNode root) {
        if (root == null) {
            return;
        }
        
        while (root != null) {
            if (root.left != null) {
                TreeNode mostRight = root.left;
                while (mostRight.right != null) {
                    mostRight = mostRight.right;
                }
                mostRight.right = root.right;
                root.right = root.left;
                root.left = null;
            }
            root = root.right;
        }
    }
    
    public static void main(String[] args) {
        FlattenBinaryTreeToLinkedList solution = new FlattenBinaryTreeToLinkedList();

        // 创建二叉树
        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.flatten(root);

        // 输出展开后的链表
        while (root != null) {
            System.out.print(root.val + " ");
            root = root.right;
        }
    }
}

实现总结

以上实现是将一个给定的二叉树展开为一个右侧链表的过程:

  1. 迭代方法:该实现采用了迭代的方式。它通过模拟前序遍历的过程,在遍历二叉树的同时进行展开。这种方法不需要额外的空间,具有较好的空间复杂度。

  2. 指针操作:展开二叉树的关键在于对指针的操作。通过不断地将左子树接到右子树的地方,然后将原右子树连接到左子树的最右边节点的右子树上,最后将当前节点的左子树置为空,将右子树移动到左子树上,实现了二叉树的展开。

  3. 时间复杂度:展开过程的时间复杂度与二叉树的节点数量成正比,为O(N),其中N是二叉树的节点数。

  4. 空间复杂度:该实现的空间复杂度为O(1),因为只使用了常数级别的额外空间用于指针的操作,而没有额外的数据结构存储节点。

  5. 适用性:这种方法适用于任意形状的二叉树。它不依赖于二叉树的特定形状或顺序,只需要通过简单的指针操作就可以展开为链表。

该实现能够在不改变原始树结构的情况下将二叉树展开为链表。

扩展问题

用递归的方式实现

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int x) {
        val = x;
    }
}

public class FlattenBinaryTreeToLinkedListRecursive {
    public void flatten(TreeNode root) {
        if (root == null) {
            return;
        }
        flatten(root.left);
        flatten(root.right);

        TreeNode tempRight = root.right;
        root.right = root.left;
        root.left = null;

        TreeNode current = root;
        while (current.right != null) {
            current = current.right;
        }
        current.right = tempRight;
    }

    public static void main(String[] args) {
        FlattenBinaryTreeToLinkedListRecursive solution = new FlattenBinaryTreeToLinkedListRecursive();

        // 创建二叉树
        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.flatten(root);

        // 输出展开后的链表
        while (root != null) {
            System.out.print(root.val + " ");
            root = root.right;
        }
    }
}

递归方法的思路是:

  • 递归地将左子树和右子树展开为链表。
  • 将左子树展开后的链表接到根节点的右子节点位置上。
  • 将原先的右子树展开后的链表接到左子树展开后的链表的末尾。

这个方法的时间复杂度与节点数成正比,空间复杂度取决于递归栈的深度,因此是O(N),其中N是二叉树的节点数。

在展开二叉树为链表的过程中,递归和迭代两种方法各有什么优缺点?

优点缺点适用情况
递归- 简洁清晰
- 易于理解
- 代码简洁
- 堆栈溢出
- 性能问题
- 问题可以自然映射为递归模型
- 递归深度不会导致栈溢出
迭代- 性能优化
- 可控制
- 代码复杂度
- 理解难度
- 处理大量数据
- 迭代过程相对简单明了
- 性能要求较高

选择适当的方法取决于问题的性质、复杂度和性能要求,可参见坚持刷题 | 递归与迭代的区别

可能的扩展问题

  1. 二叉树的其他变换操作:除了展开为链表,还可以进行其他类型的变换操作吗?比如将二叉树转换为双向链表、将二叉树按照层级顺序展开等等。

  2. 二叉树的遍历方法:如何利用不同的二叉树遍历方法来展开二叉树为链表?比如前序遍历、中序遍历、后序遍历等。

  3. 二叉树的平衡性:在展开二叉树为链表时,是否会影响二叉树的平衡性?如何确保展开后的链表仍然保持二叉树的平衡性?

  4. 二叉树的应用场景:展开二叉树为链表有哪些实际的应用场景?在什么情况下会需要将二叉树转换为链表?

  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hello 阿月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值