1. 简介

在计算机科学中,二叉树 是一种每个节点最多有两个子节点的数据结构。

本文将介绍如何判断一个二叉树是否对称。

2. 什么是对称二叉树?

在二叉树中,每个节点包含两个子树:左子树和右子树。一个子树可以是空、一个单独的节点,或者另一个完整的二叉树。
如果根节点的左子树是右子树的镜像反射,那么这棵二叉树就是对称的。

例如,下面这棵树是对称的:

symmetric

而下面这棵树虽然左右子树结构相同,但值不同,因此不是对称的:

non symmetric 1

3. 递归解法

根据对称的定义,我们可以使用如下规则来判断两个二叉树是否互为镜像:

  • 两个根节点的值必须相同
  • 一棵树的左子树必须与另一棵树的右子树互为镜像

将这些条件转换为递归实现如下:

boolean isSymmetric(TreeNode root) {
    if (root == null) {
        return true;
    }
    return isMirror(root.left, root.right);
}

boolean isMirror(TreeNode root1, TreeNode root2) {
    if (root1 == null && root2 == null) return true;
    if (root1 == null || root2 == null) return false;
    return root1.val == root2.val
        && isMirror(root1.left, root2.right)
        && isMirror(root1.right, root2.left);
}

这段代码中,我们使用了一个辅助函数 isMirror 来判断两个子树是否镜像对称。先处理空节点的情况,再递归比较左右子树。

时间复杂度: O(n),其中 n 是节点总数。我们每个节点访问一次。

4. 迭代解法

除了递归,我们也可以使用迭代方式实现。思路是:按层遍历,每一层的节点应呈现对称结构。

比如下图中的结构,每层节点应满足对称特性:

level

实现方式是使用一个队列来辅助遍历:

boolean isSymmetric(TreeNode root) {
    if (root == null) return true;

    Queue<TreeNode> queue = new LinkedList<>();
    queue.add(root.left);
    queue.add(root.right);

    while (!queue.isEmpty()) {
        TreeNode node1 = queue.poll();
        TreeNode node2 = queue.poll();

        if (node1 == null && node2 == null) continue;
        if (node1 == null || node2 == null) return false;
        if (node1.val != node2.val) return false;

        queue.add(node1.left);
        queue.add(node2.right);
        queue.add(node1.right);
        queue.add(node2.left);
    }

    return true;
}

每次从队列中取出两个节点进行比较,然后将它们的子节点以镜像顺序入队。这种方式也保证了我们访问了所有节点一次。

优点: 避免递归可能导致的栈溢出问题
缺点: 实现略复杂,需要维护队列结构

时间复杂度: O(n),每个节点访问一次

5. 小结

本文介绍了判断二叉树是否对称的两种方法:

  • 递归法:实现简单,逻辑清晰,适合大多数场景
  • 迭代法:避免栈溢出问题,适合处理深度较大的树

两种方法的时间复杂度均为 O(n),空间复杂度取决于树的高度或队列的长度。

踩坑提醒:

  • 在判断镜像时容易搞混左右子树的顺序,建议画图辅助理解
  • 注意空节点的处理,否则容易出现空指针异常

选择实现方式时,建议优先使用递归,逻辑清晰,除非遇到递归深度限制问题再考虑迭代实现。


原始标题:How to Check If a Binary Tree Is Symmetric?