问题描述
以下三个二叉树,除了第一个二叉树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;
}
}
}