对称的二叉树(剑指OFFER 面试题28)

问题描述

以下三个二叉树,除了第一个二叉树A是对称的之外,后面两个B、C都不是对称二叉树。

二叉树A
对称二叉树

二叉树B
非对称二叉树

二叉树C
非对称二叉树
我们遍历二叉树通常有三种算法,前序中序和后序。在这3中遍历算法中,都是先遍历右子节点再遍历左子节点。那么我们可以换种思路,定义一个算法用来先遍历右子节点再遍历左子节点,比如:我们针对前序遍历,定义一个对称的遍历算法,先遍历父节点,再遍历它的右子节点,最后遍历它的左子节点。
如果用前序遍历算法遍历上述二叉树A,则遍历的序列是{8,6,5,7,6,7,5}.如果我们用自定义的对称前序遍历算法,则能得到{8,6,5,7,6,7,5},可以发现,两个序列都是一样的。
对于二叉树B来说,前序遍历算法得到的前序序列是{8,6,5,7,9,7,5},但是对称前序遍历序列为{8,9,5,7,6,7,5},这两个序列是不一样的,第二步和第五步是不一样的。
二叉树C有点特殊,它的节点都是一样的,前序遍历的序列为{7,7,7,7,7,7},而对称前序遍历的序列为{7,7,7,7,7,7},两个序列都是一样的,可是显然,从上述的图中可以看到,他们是不对称的,那么我们要怎样才能正确的判断这种类型的二叉树呢?那么我们这个时候可以考虑把遍历的空指针也添加进序列里。
二叉树C在考虑到指针为空之后,前序遍历为{7,7,7,null,null,7,null,null,7,7,null,null,null}。序列的前面三个7对应的是从根节点沿着指向左子节点的指针遍历经过的三个节点,接下来两个null指针是对应着第三层第一个7的两个子节点,其他的以此类推。而对称前序遍历序列为{7,7,null,7,null,null,7,7,null,null,7,null,null}。这两个序列从第三步开始就不一致了。
以上所述可以得知,我们能够通过比较它的前序序列就能够知道该二叉树是否对称。如果两个序列一样,那么二叉树就是对称的。

以下为参考测试代码:

using System;

namespace 对称的二叉树
{
    public class TreeNode
    {
        public int val;
        public TreeNode left;
        public TreeNode right;
        public TreeNode(int x)
        {
            val = x;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //Test1:检查对称二叉树能否输出true
            TreeNode tree1 = CreateTree1(null);
            Console.WriteLine("Test1:" + IsSymmetrical(tree1));
            //Test2:检查非对称二叉树输出是否为false
            TreeNode tree2 = CreateTree2(null);
            Console.WriteLine("Test2:" + IsSymmetrical(tree2));
            //Test3:检查在节点相同的情况下,能否根据null指针来判断树是否相等
            TreeNode tree3 = CreateTree3(null);
            Console.WriteLine("Test3:" + IsSymmetrical(tree3));
        }

        /// <summary>
        /// 判断该二叉树是否为对称二叉树
        /// </summary>
        /// <param name="pRoot">二叉树的根节点</param>
        /// <returns>是否为对称二叉树</returns>
        public static bool IsSymmetrical(TreeNode pRoot)
        {
            return IsSymmetrical(pRoot, pRoot);
        }

        /// <summary>
        /// 比较二叉树和镜像二叉树
        /// </summary>
        /// <param name="pRoot1">二叉树的根节点</param>
        /// <param name="pRoot2">镜像二叉树的根节点</param>
        /// <returns>是否为对称二叉树</returns>
        private static bool IsSymmetrical(TreeNode pRoot1,TreeNode pRoot2)
        {
            //如果两个节点都指向空,那么返回真
            if (pRoot1 == null && pRoot2 == null)
                return true;
            //如果两个节点只有其中一个指向空,那么返回假
            if (pRoot1 == null || pRoot2 == null)
                return false;
            //如果两个节点的值不相等,那么返回假
            if (pRoot1.val != pRoot2.val)
                return false;

            //二叉树的左子树与其右子树比较,相当于和它的对称部分比较,如果不一样返回false,则说明不是对称的二叉树
            return IsSymmetrical(pRoot1.left, pRoot2.right) && IsSymmetrical(pRoot1.right, pRoot2.left);
        }

        /// <summary>
        /// 创建对称二叉树
        /// </summary>
        /// <param name="root">二叉树的根节点</param>
        /// <returns>新建二叉树的根节点</returns>
        private static TreeNode CreateTree1(TreeNode root)
        {
            TreeNode tree = new TreeNode(8);
            if (root == null)
                root = tree;

            tree.left = new TreeNode(6);
            tree.right = new TreeNode(6);
            tree.left.left = new TreeNode(7);
            tree.left.right = new TreeNode(5);
            tree.right.left = new TreeNode(5);
            tree.right.right = new TreeNode(7);

            return root;
        }

        /// <summary>
        /// 创建非对称二叉树
        /// </summary>
        /// <param name="root">二叉树的根节点</param>
        /// <returns>新建二叉树的根节点</returns>
        private static TreeNode CreateTree2(TreeNode root)
        {
            TreeNode tree = new TreeNode(8);
            if (root == null)
                root = tree;

            tree.left = new TreeNode(6);
            tree.right = new TreeNode(9);
            tree.left.left = new TreeNode(7);
            tree.left.right = new TreeNode(5);
            tree.right.left = new TreeNode(5);
            tree.right.right = new TreeNode(7);

            return root;
        }

        /// <summary>
        /// 创建非对称二叉树
        /// </summary>
        /// <param name="root">二叉树的根节点</param>
        /// <returns>新建二叉树的根节点</returns>
        private static TreeNode CreateTree3(TreeNode root)
        {
            TreeNode tree = new TreeNode(7);
            if (root == null)
                root = tree;

            tree.left = new TreeNode(7);
            tree.right = new TreeNode(7);
            tree.left.left = new TreeNode(7);
            tree.left.right = new TreeNode(7);
            tree.right.left = new TreeNode(7);

            return root;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_33575542/article/details/80762033