我的编程空间,编程开发者的网络收藏夹
学习永远不晚

镜像二叉树的示例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

镜像二叉树的示例分析

镜像二叉树的示例分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

算法这个东西很难,纵使你了解了其中的逻辑,用代码写出来仍然不是一件容易的事,内部有太多的细节需要处理。为了便于大伙轻松理解算法逻辑,对于所有的题目,我会使用图文加动画的形式进行讲解,让读者可以轻松理解算法逻辑的同时,还可以留下深刻的影像不容易遗忘。

镜像二叉树的示例分析

好,下面我们开始今天的算法题:镜像二叉树,就是将一颗二叉树上的左右节点全部交换,就好比镜子里的二叉树,左右方向是反过来的。

二叉树节点表示

镜像二叉树的示例分析
class Node<T> {
    T value;
    Node<T> left;
    Node<T> right;

    Node(T value) {
        this.value = value;
    }

    Node(T value, Node<T> left, Node<T> right) {
        this.value = value;
        this.left = left;
        this.right = right;
    }
}


一个参数的构造器是叶子节点,三个参数的构造器是中间节点,看到这里读者应该知道这是 Java 语言,我使用了范型 

构造二叉树

镜像二叉树的示例分析
Node<Integer> node2 = new Node<>(2);
Node<Integer> node3 = new Node<>(3);
Node<Integer> node1 = new Node<>(1, node2, node3);

// 一次性构造
Node<Integer> node1 = new Node<>(1, new Node<>(2), new Node<>(3));

呈现二叉树结构

如果我们正确写出了镜像算法,那如何来直观验证镜像的结构是否正确呢?LeetCode 使用的是单元测试,它使用一系列的单元测试和压力测试脚本代码来验证用户编写的算法的正确性和性能。但是我们不要这样做,因为不直观。我们选择对二叉树的结构内容进行直观的呈现,如此就可以使用肉眼来进行快速验证。如何直观呈现呢?我们使用最简单的括号表示法,它并不是最直观的,但是它易于实现。

镜像二叉树的示例分析
class Node<T> {
  T value;
  Node<T> left;
  Node<T> right;

  public String toString() {
    // 叶节点
    if (left == right) {
        return String.format("[%d]", value);
    }
    // 中间节点
    return String.format("(%d, %s, %s)", value, left, right);
  }
}

Node<Integer> node2 = new Node<>(2);
Node<Integer> node3 = new Node<>(3);
Node<Integer> node1 = new Node<>(1, node2, node3);

System.out.println(node1);
System.out.println(node2);
System.out.println(node3);
---------------------
[2]
[3]
(1, [2], [3])

递归镜像二叉树

镜像二叉树有两种算法,一种是递归,一种是迭代。递归的算法简单易于理解,我们先使用递归算法来求解。递归的思想就是深度遍历,遇到一个节点,先递归镜像它的左子树,再递归镜像它的右子树,然后再交换自己的左右子树。如果遇到的是叶子节点,就不必处理了。为了避免无限递归,一定要及时设置好递归的停止条件,在这里停止条件就是遇到了叶节点。

镜像二叉树的示例分析
public void mirrorFrom(Node<T> node) {
    // 叶子结点
    if (node.left == node.right) {
        return;
    }
    // 递归镜像左子树
    if (node.left != null)
        mirrorFrom(node.left);
    // 递归镜像右子树
    if (node.right != null)
        mirrorFrom(node.right);
    // 交换当前节点的左右子树
    Node<T> tmp = node.left;
    node.left = node.right;
    node.right = tmp;
}

迭代镜像二叉树

递归算法的优势在于逻辑简单,缺点在于每一次递归调用函数都会增加一个新的函数堆栈,如果树的深度太深,函数的堆栈内存就会持续走高,一不小心就会触发臭名昭著的异常 StackOverflowException。如果二叉树分布比较均匀,那么树就不会太深,但是遇到偏向的二叉树,比如所有的子节点都挂在了右节点上,二叉树就退化成了线性链表,链表的长度就是树的深度,那这颗树的深度就比较可怕了。

镜像二叉树的示例分析


所以下面我来介绍第二种算法 —— 迭代算法。迭代的基本思想就是将递归算法转换成循环算法,用一个 for 循环来交换所有节点的左右子树。我们需要再重新理解一下算法的目标,这个目标非常简单,就是遍历整颗二叉树,将遍历途中遇到的所有中间节点的左右指针交换一下。

那如何设计这个循环呢?一个很明显的方法是分层循环,第一次循环处理第 1 层二叉树节点,也就是唯一的根节点。下一个循环处理第 2 层二叉树节点,也就是根节点的两个儿子。如此一直处理到最底层,循环的终止条件就是后代节点没有了。所以我们需要使用一个容器来容纳下一次循环需要处理的后代节点。

镜像二叉树的示例分析
public MirrorBinaryTree<T> mirrorByLoop() {
    // 空树不必处理
    if (root == null) {
        return this;
    }
    // 当前循环需要处理的节点
    LinkedList<Node<T>> expandings = new LinkedList<>();
    expandings.add(root);
    // 没有后台节点就可以终止循环
    while (!expandings.isEmpty()) {
        // 下一次循环需要处理的节点
        // 也就是当前节点的所有儿子节点
        LinkedList<Node<T>> nextExpandings = new LinkedList<>();
        // 遍历处理当前层的所有节点
        for (Node<T> node : expandings) {
            // 将后代节点收集起来,留着下一次循环
            if (node.left != null) {
                nextExpandings.add(node.left);
            }
            if (node.right != null) {
                nextExpandings.add(node.right);
            }
            // 交换当前节点的左右指针
            Node<T> tmp = node.left;
            node.left = node.right;
            node.right = tmp;
        }
        // 将后代节点设置为下一轮循环的目标节点
        expandings = nextExpandings;
    }
    return this;
}

完整代码

下面的完整代码可以拷贝过去直接运行,如果读者还是不够明白欢迎在留言区及时提问。

package leetcode;

import java.util.LinkedList;

public class MirrorBinaryTree<T> {

    static class Node<T> {
        T value;
        Node<T> left;
        Node<T> right;

        Node(T value) {
            this.value = value;
        }

        Node(T value, Node<T> left, Node<T> right) {
            this(value);
            this.left = left;
            this.right = right;
        }

        public String toString() {
            if (left == right) {
                return String.format("[%d]", value);
            }
            return String.format("(%d, %s, %s)", value, left, right);
        }

    }

    private Node<T> root;

    public MirrorBinaryTree(Node<T> root) {
        this.root = root;
    }

    public MirrorBinaryTree<T> mirrorByLoop() {
        if (root == null) {
            return this;
        }
        LinkedList<Node<T>> expandings = new LinkedList<>();
        expandings.add(root);
        while (!expandings.isEmpty()) {
            LinkedList<Node<T>> nextExpandings = new LinkedList<>();
            for (Node<T> node : expandings) {
                if (node.left != null) {
                    nextExpandings.add(node.left);
                }
                if (node.right != null) {
                    nextExpandings.add(node.right);
                }
                Node<T> tmp = node.left;
                node.left = node.right;
                node.right = tmp;
            }
            expandings = nextExpandings;
        }
        return this;
    }

    public MirrorBinaryTree<T> mirrorByRecursive() {
        mirrorFrom(root);
        return this;
    }

    public void mirrorFrom(Node<T> node) {
        if (node.left == node.right) {
            return;
        }

        if (node.left != null)
            mirrorFrom(node.left);
        if (node.right != null)
            mirrorFrom(node.right);

        Node<T> tmp = node.left;
        node.left = node.right;
        node.right = tmp;
    }

    public String toString() {
        if (root == null) {
            return "()";
        }
        return root.toString();
    }

    public static void main(String[] args) {
        Node<Integer> root = new Node<>(
                1, 
                new Node<>(
                        2, 
                        new Node<>(4), 
                        new Node<>(
                                5, 
                                new Node<>(8),
                                null)),
                new Node<>(
                        3, 
                        new Node<>(
                                6, 
                                null, 
                                new Node<>(9)), 
                        new Node<>(7)));
        MirrorBinaryTree<Integer> tree = new MirrorBinaryTree<>(root);
        System.out.println(tree);
        tree.mirrorByRecursive();
        System.out.println(tree);
        tree.mirrorByLoop();
        System.out.println(tree);
    }

}
---------------
(1, (2, [4], (5, [8], null)), (3, (6, null, [9]), [7]))
(1, (3, [7], (6, [9], null)), (2, (5, null, [8]), [4]))
(1, (2, [4], (5, [8], null)), (3, (6, null, [9]), [7]))

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注编程网行业资讯频道,感谢您对编程网的支持。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

镜像二叉树的示例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

镜像二叉树的示例分析

镜像二叉树的示例分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。算法这个东西很难,纵使你了解了其中的逻辑,用代码写出来仍然不是一件容易的事,内部有太多的细节需
2023-06-04

Java中二叉树与N叉树的示例分析

这篇文章主要介绍了Java中二叉树与N叉树的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。题目一 解法/** * Definition for a binary tr
2023-06-29

C语言中二叉树的示例分析

这篇文章主要为大家展示了“C语言中二叉树的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C语言中二叉树的示例分析”这篇文章吧。树概念及结构树是一种 非线性 的数据结构,它是由 n ( n
2023-06-29

java二叉树面试题的示例分析

小编给大家分享一下java二叉树面试题的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!二叉树的深度题目:输入一颗二叉树的根节点,求该树的的深度。输入一颗二
2023-06-20

C++树与二叉树实例分析

这篇“C++树与二叉树实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C++树与二叉树实例分析”文章吧。树树的定义Q:
2023-06-30

java面试题解LeetCode27二叉树的镜像实例

这篇文章主要为大家介绍了java面试题解LeetCode27二叉树的镜像实例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-05

C语言平衡二叉树的示例分析

这篇文章给大家分享的是有关C语言平衡二叉树的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。平衡二叉树(Balanced Binary Tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一
2023-06-25

C++二叉搜索树实例分析

本篇内容介绍了“C++二叉搜索树实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!独一无二的二叉搜索树Given an integer
2023-06-19

Java二叉搜索树增、插、删、创的示例分析

小编给大家分享一下Java二叉搜索树增、插、删、创的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!①概念二叉搜索树又称二叉排序树,它或者是一棵空树**,或者是具有以下性质的二叉树:若它的左子树不为空,则左子树上所有
2023-06-29

Java平衡二叉树实例分析

这篇文章主要讲解了“Java平衡二叉树实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java平衡二叉树实例分析”吧!AVL树的引入搜索二叉树有着极高的搜索效率,但是搜索二叉树会出现以
2023-06-30

Docker镜像的示例分析

这篇文章主要为大家展示了“Docker镜像的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Docker镜像的示例分析”这篇文章吧。一:思维导图二:镜像的生命周期三:镜像的组织结构四:镜像
2023-06-04

C++使用LeetCode实现二叉搜索树的示例分析

这篇文章将为大家详细讲解有关C++使用LeetCode实现二叉搜索树的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Given an integer n, generate all structu
2023-06-20

java二叉树中数据插入算法的示例分析

这篇文章主要介绍java二叉树中数据插入算法的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!例题:leetcode 第701题二叉树插入数据题目:给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉
2023-06-22

Java中二叉树与斐波那契函数的示例分析

这篇文章主要介绍Java中二叉树与斐波那契函数的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!题目一解法class Solution { public int fib(int n) { i
2023-06-29

java二叉搜索树使用实例分析

本篇内容主要讲解“java二叉搜索树使用实例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java二叉搜索树使用实例分析”吧!概念二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性
2023-06-29

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录