首页 > 编程语言 >Java 实现二叉树展平为链表

Java 实现二叉树展平为链表

时间:2024-09-02 16:51:24浏览次数:14  
标签:左子 current right 右子 展平 链表 二叉树 节点

Java 实现二叉树展平为链表

前言

处理二叉树节点,迭代连接右子节点,移至左侧并清除左子连接,整合进链表,右子节点待处理

在处理二叉树数据结构时,有时需要将其转换成一种特殊的形态,即链表。

这种转换可以简化某些算法的操作,例如遍历或访问树中的节点。

本文将介绍如何使用Java编程语言将一个二叉树展平为链表,使得每个节点仅具有一个右子节点。

问题背景

给定一个二叉树,要求将该二叉树转换为一个链表,其中每个节点都只拥有一个右子节点。转换后的链表应该按照原二叉树的前序遍历顺序排列节点。

解决方案

为了达成目标,我们可以通过反复迭代的方法来逐个处理二叉树的节点。

在每次迭代中,若当前节点拥有左子树,我们便寻找该左子树的最右侧节点,并将其右子节点连接到当前节点的右侧。

随后,将当前节点的原始右子节点移至左侧,并清除其左子节点连接。

通过这种方式,原节点被整合进链表结构中,同时其右侧子节点成为下一个待处理的对象。

代码实现

首先定义二叉树节点类 TreeNode

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

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

然后定义解决方案类 Solution,并在其中实现 flatten 方法:

public class Solution {
    public void flatten(TreeNode root) {
        while (root != null) {
            if (root.left == null) {
                // 如果当前节点没有左子树,则移动到右子树
                root = root.right;
            } else {
                // 找到左子树的最右节点
                TreeNode pre = root.left;
                while (pre.right != null) {
                    pre = pre.right;
                }

                // 将左子树的最右节点的右子节点连接到当前节点的右子节点
                pre.right = root.right;

                // 将当前节点的右子节点设置为其左子节点
                root.right = root.left;

                // 清除当前节点的左子节点
                root.left = null;

                // 继续处理当前节点的右子节点
                root = root.right;
            }
        }
    }
}

代码分析

  • 循环条件:当 root 不为空时,进入循环处理。
  • 左子树为空的情况:如果当前节点没有左子树,则直接移动到其右子树。
  • 左子树非空的情况:如果当前节点有左子树,则找到左子树的最右侧节点,并将其右子节点指向当前节点的右子树。然后,将当前节点的右子节点设置为其左子树,同时清除当前节点的左子节点。最后,更新 root 为新的右子树的根节点,继续处理。

结论

通过上述方法,我们可以有效地将任意二叉树转换为一个链表,使得每个节点仅有右子节点。这种方法不使用额外的空间,空间复杂度为 O(1),并且时间复杂度为 O(n),其中 n 是二叉树中的节点数。这种技术在处理某些特定类型的二叉树问题时非常有用,可以简化算法的实现并提高效率。

使用原地算法(O(1) 空间复杂度)将二叉树展平为链表

在处理二叉树时,有时需要将二叉树转换为链表的形式,以简化某些操作,如遍历或搜索。本文将介绍如何使用原地算法,即 O(1) 空间复杂度的方法,将二叉树展平为链表。

问题描述

给定一个二叉树,要求将二叉树转换为一个链表,使得每个节点都只拥有一个右子节点。转换后的链表应该按照原二叉树的前序遍历顺序排列节点。

解决方案

为了在 O(1) 空间复杂度内完成二叉树的展平,我们需要使用迭代的方法来处理二叉树的节点。这种方法不需要额外的栈或队列来保存节点信息,而是直接在树的结构上进行修改。

代码实现

首先定义二叉树节点类 TreeNode

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

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

然后定义解决方案类 Solution,并在其中实现 flatten 方法:

public class Solution {
    public void flatten(TreeNode root) {
        TreeNode current = root;
        while (current != null) {
            if (current.left != null) {
                // 找到左子树的最右节点
                TreeNode pre = current.left;
                while (pre.right != null) {
                    pre = pre.right;
                }

                // 将左子树的最右节点的右子节点连接到当前节点的右子节点
                pre.right = current.right;

                // 将当前节点的右子节点设置为其左子节点
                current.right = current.left;

                // 清除当前节点的左子节点
                current.left = null;
            }

            // 移动到当前节点的右子节点
            current = current.right;
        }
    }
}

代码分析

  1. 循环条件:当 current 不为空时,进入循环处理。
  2. 左子树非空的情况:如果当前节点有左子树,则找到左子树的最右侧节点,并将其右子节点指向当前节点的右子树。然后,将当前节点的右子节点设置为其左子树,同时清除当前节点的左子节点。
  3. 移动到下一个节点:更新 current 为新的右子树的根节点,继续处理。

优化思路

虽然上述方法能够正确地将二叉树展平为链表,但在某些情况下,找到左子树的最右节点可能会导致不必要的遍历。我们可以进一步优化算法,避免重复寻找左子树的最右节点。

优化后的代码如下:

public class Solution {
    public void flatten(TreeNode root) {
        TreeNode current = root;
        while (current != null) {
            if (current.left != null) {
                // 找到左子树的最右节点
                TreeNode pre = current.left;
                while (pre.right != null) {
                    pre = pre.right;
                }

                // 连接当前节点的右子节点到左子树的最右节点
                pre.right = current.right;

                // 将当前节点的右子节点设置为其左子节点
                current.right = current.left;

                // 清除当前节点的左子节点
                current.left = null;
            }

            // 移动到当前节点的右子节点
            current = current.right;
        }
    }
}

结论

在这里插入图片描述

通过上述方法,我们能够在 O(1) 空间复杂度下将二叉树转换为链表。这种方法不仅节省了空间,而且保证了二叉树的结构在原地被修改,无需额外的数据结构支持。这种方法适用于需要将二叉树转换为链表的各种应用场景。

标签:左子,current,right,右子,展平,链表,二叉树,节点
From: https://blog.csdn.net/m0_67187271/article/details/141810983

相关文章

  • 图的表示与查询:散列表与链表的对比
    图的表示与查询:散列表与链表的对比一、引言二、使用散列表表示图的边伪代码实现如下:C代码实现如下:三、期望时间分析四、散列表表示的缺陷五、使用链表表示图的边伪代码实现如下:六、链表表示的缺陷七、结论摘要:本文探讨了图的表示方法,特别是针对边......
  • 二叉树的遍历
    先序遍历usingnamespacestd;//定义二叉树节点结构体structTreeNode{charData;//节点的数据TreeNode*left;//左子节点TreeNode*right;//右子节点//构造函数TreeNode(chardata,TreeNode*leftChild=nullptr,T......
  • Go平衡二叉树
    packagemainimport("fmt")typeAVLNodestruct{dataintheightintleft,right*AVLNode}funcmax(a,bint)int{ifa>b{returna}returnb}funcheight(p*AVLNode)int{ifp!=nil{......
  • 排序算法之二叉树排序详细解读(附带Java代码解读)
    二叉树排序(BinaryTreeSort)是一种基于二叉搜索树(BinarySearchTree,BST)实现的排序算法。它的基本思想是利用二叉搜索树的性质来实现排序,通过将元素插入到二叉搜索树中,然后对树进行中序遍历来获取排序后的元素。基本概念二叉搜索树(BST):对于二叉搜索树中的每一个节点,其左......
  • 二叉树的直径(LeetCode)
    题目给你一棵二叉树的根节点,返回该树的 直径 。二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。两节点之间路径的 长度 由它们之间边数表示。解题classTreeNode:def__init__(self,val=0,left=......
  • 力扣237题详解:删除链表中的节点的模拟面试问答
    在本篇文章中,我们将详细解读力扣第237题“删除链表中的节点”。通过学习本篇文章,读者将掌握如何在单链表中删除给定的节点,并了解相关的复杂度分析和模拟面试问答。每种方法都将配以详细的解释,以便于理解。问题描述力扣第237题“删除链表中的节点”描述如下:请编写一个函......
  • 代码随想录刷题day13丨二叉树理论基础,递归遍历,迭代遍历,统一迭代,层序遍历
    代码随想录刷题day13丨二叉树理论基础,递归遍历,迭代遍历,统一迭代,层序遍历1.二叉树理论基础1.1二叉树种类满二叉树概述:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。这棵二叉树为满二叉树,也可以说深度为k,有2^k-1个节......
  • 【数据结构】二叉树基础(带你了解二叉树)
     ......
  • Python 数据结构——二叉树(最最最最最实用的二叉树教程)
    本文章以实用为主,所以不多废话直接开整本文所介绍的二叉树是最基础的二叉树,不是二叉搜索树,也不是平衡二叉树,就基本的二叉树二叉树的创建基本二叉树的创建其实比链表还要简单,只需创建一个节点的类即可,随后用指针将其串起来。不同于链表的是,二叉树为一个父节点连接到两个子节......
  • 对称二叉树-101
    题目描述给你一个二叉树的根节点root,检查它是否轴对称。解题思路这里我们相当于是比较根节点左右两颗子树,我们依次向左右子树的左右两个方向进行遍历,我们比较左子树的左孩子和右子树的右孩子,左子树的右孩子和右子树的左孩子,这里如果不好理解可以看下面这个图片,如果两个子节......