剑指offer系列之十七:二叉树的镜像

题目描述

操作给定的二叉树,将其变换为源二叉树的镜像。
输入描述:

二叉树的镜像定义:源二叉树
8
/ \
6 10
/ \ / \
5 7 9 11
镜像二叉树
8
/ \
10 6
/ \ / \
11 9 7 5

仔细观察原二叉树与镜像二叉树,可以发现镜像二叉树实际上就是把每个节点的左右孩子结点进行了交换,比如在遍历到8这个节点时候,首先交换其左右孩子6和10,其对应的子树也应该进行交换。所以我们可以采用前序遍历的方法进行操作,每当遇到一个结点的时候,首先判断其是否有左右孩子(有其中之一即可),如果有的话,就交换其左右孩子,然后继续遍历其左右子树,只要不为空就继续交换其左右孩子节点(在交换具有孩子结点的结点的时候,其孩子结点也一并被交换了)。下面是基于这种思路的实现代码(已被牛客AC):

package com.rhwayfun.offer;

import java.util.Stack;

public class TreeMirror {
    //二叉树结点定义
    public static class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;

        public TreeNode(int val) {
            this.val = val;

        }

    }

    //采用递归的方式进行交换
    public void Mirror(TreeNode root) {
        if (root == null || (root.left == null && root.right == null))
            return;

        TreeNode nodeTemp = root.left;
        root.left = root.right;
        root.right = nodeTemp;

        if (root.left != null) {
            Mirror(root.left);
        }
        if (root.right != null) {
            Mirror(root.right);
        }
    }

    //采用非递归的方式进行交换
    public void Mirror2(TreeNode root) {
        if (root == null || (root.left == null && root.right == null))
            return;

        Stack<TreeNode> s = new Stack<TreeNode>();
        s.push(root);
        while (!s.isEmpty()) {
            TreeNode node = s.pop();
            //交换左右孩子结点
            TreeNode nodeTemp = node.left;
            node.left = node.right;
            node.right = nodeTemp;
            //遍历左子树
            if (node.left != null)
                s.push(node.left);
            //遍历右子树
            if (node.right != null)
                s.push(node.right);
        }
    }

    //前序遍历
    public void preOrderTarverse(TreeNode root) {
        Stack<TreeNode> s = new Stack<TreeNode>();
        while (root != null || !s.isEmpty()) {
            //遍历左子树
            while (root != null) {
                System.out.println(root.val);
                s.push(root);
                root = root.left;
            }
            // 左子树遍历结束,继续遍历右子树
            if (!s.isEmpty()) {
                root = s.pop();
                root = root.right;
            }
        }
    }

    public static void main(String[] args) {
        TreeNode root = new TreeNode(8);
        TreeNode node1 = new TreeNode(6);
        TreeNode node2 = new TreeNode(10);
        TreeNode node3 = new TreeNode(5);
        TreeNode node4 = new TreeNode(7);
        TreeNode node5 = new TreeNode(9);
        TreeNode node6 = new TreeNode(11);

        root.left = node1;
        root.right = node2;
        node1.left = node3;
        node1.right = node4;
        node2.left = node5;
        node2.right = node6;

        TreeMirror r = new TreeMirror();
        r.Mirror2(root);

        r.preOrderTarverse(root);
    }
}
时间: 2024-11-18 22:01:20

剑指offer系列之十七:二叉树的镜像的相关文章

剑指offer系列之五十七:二叉树的下一个节点

题目描述 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针. 根据中序遍历的特点,要找到一个节点的下一个节点无非就是三种情况:1.有右子树,这时只需要把其右孩子作为下一个遍历的(并不是要找的)节点,然后沿着该节点的左子树(如果有的话)出发,直到遇到叶子节点,那么该叶子节点就是其下一个要找的节点:2.没有右子树,则判断该节点是否是其父节点的左孩子,如果是则其下一个要找的节点是其父节点:3.如果不是其父节点的左孩子,

剑指offer系列之四十七:不用加减乘除做加法

题目描述 写一个函数,求两个整数之和,要求在函数体内不得使用+.-.*./四则运算符号 既然不能使用加减乘除,那么只剩下位运算和逻辑运算了.采用位运算的思路分为三步走:第一步,不进位对两个做异或运算(因为不考虑进位,1与1,0与0的异或运算的结果刚好是两者相加的结果):第二步,通过与运算得到两个数的进位值,因为只有1与1进行与运算的时候才会产生进位,所以产生的进位可以看成是两者先进行与运算再左移一位:第三步,把前两步的结果做与运算得到最后的结果.个人觉得这种思路是在是太赞了.OK,事就成了.下面

剑指offer系列之二十六:输出字符串的全排列

题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 结果请按字母顺序输出. 输入描述: 输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母. 此题与剑指offer原题存在一些初入,在原题中并没有规定字符串中字符是否有重复的出现.不过思路是一致的,只不过是添加额外的判断罢了.下面说说我的思路吧:先不考虑是否出现重读字符,要对一个字符进行全排列,可以

剑指offer系列之十二:调整数组顺序使奇数位于偶数前面

题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. 这道题第一思路自然是这样的:从头开始遍历这个数组,如果遇到偶数就把这个数之后的所有数往前移动一位,这样数组会留出一个空位,移动完毕之后把该偶数放到该空位即可.这样处理的话需要两次循环,一次是遍历,另一次是移位,所以时间复杂度是O(n2).下面是这种思路的实现代码(已被牛客AC): public void reOrd

剑指offer系列之三:在二维数组中查找元素

题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 由于题目条件的成立,所以使得这道题可以使用对角线的方法完成,可以从右上角的元素考虑,如果目标查找元素小于右上角的元素,那么不可能在右上角元素所在的列,如果目标大于剩余列的右上角的元素,那么不可能在该右上角元素所在的行.依照这个规律,就可以完成目标元素的查找(参考剑指offer书中的思路).基于此,我写出如下的代码(已被

剑指offer系列之五十六:对称二叉树的判断

题目描述 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的. 前面有一题是打印输出某二叉树的镜像,回想其实现的思路是:采用层序遍历的思路对每一个遍历的节点,如果其有孩子节点,那么就交换两者.直到遍历的节点没有孩子节点为止,然而此题是对二叉树木镜像的判断,明显是更简单的,只需要进行两个判断:对节点的左孩子与其兄弟节点右孩子的判断以及对节点右孩子与其兄弟节点左孩子的判断.这样就完成对对一棵二叉树是否对称的判断.下面是具体的实现代码(已被牛客

《剑指offer》-判断对称二叉树

题目描述 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的. 思路上还是广度优先搜索(BFS)来做的.BFS是依托于STL的queue作为容器作为存储空间的,并且树的每一层节点的处理都放到一个内部的while循环中: 使用一个vector存储层内节点元素值,然后判断这个vector是否为对称的.如果对称,还要考虑元素个数,除了第一层之外都应该是偶数个元素.这样的话没有考虑到null节点的处理. 如果节点为null则存储一个0(假定样例节

剑指offer系列之五十四:按之字形顺序打印二叉树

题目描述 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推. 此题明显是层序遍历的思路.由于需要按照之字形打印每一层,相当于在打印每一行之前需要判断上一行打印的顺序.比如,如果上一行打印的顺序使从左到右,那么下一行的打印顺序应该是从右到左.实现的这点可以采用奇数行从左到右打印,偶数行从右到左进行打印.还可直接设置 一个布尔变量,每打印一行就改变一次该变量的值.其他的就是层序遍历的思路了.下面是我实现的代

剑指offer系列之二十一:从上到下打印二叉树

题目描述 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 此题实际上就是二叉树层序遍历方法的考察,具体思路是:使用一个集合(或者栈,但是相对来说使用栈操作会方便一些)来保存遍历的节点,还需要创建一个集合用来保存最后输出的遍历序列.从根节点开始遍历,首先把该节点放入集合中,并输出其值,之后便从集合中移除该节点,不过在此之前需要判断该节点是否有左右孩子,如果有左右(满足其一就可以)孩子,便把左右孩子放入集合中.每次输出值后便把节点具体的值放入遍历集合中,作为最后的返回结果. 下面是基于这种思