ProgramGuru

Check if Two Binary Trees are Mirror Images

Problem and examples

Given two binary trees, your task is to determine whether they are mirror images of each other. Two trees are said to be mirrors if the structure of one tree is the reverse of the other and their corresponding node values are the same. This check must be done recursively for all corresponding nodes.
Tree 1 Tree 2 Are Mirror? Description
[1, 2, 3, 4, 5] [1, 3, 2, null, null, 5, 4] true Tree 2 is the mirror image of Tree 1: left and right children are swapped at every node.
[10, 20, 30] [10, 30, 20] true Left and right subtrees are perfectly mirrored.
[1, 2, 3] [1, 2, 3] false Both trees have the same structure, but are not mirrors (no left-right reversal).
[] [] true Two empty trees are trivially mirrors of each other.
[1] [1] true Single-node trees with the same value are mirrors.
[1, 2] [1, null, 2] true Tree 1 has a left child; Tree 2 has a right child. Structures mirror each other.

How it works

Understanding the Problem

We are given two binary trees and asked to determine whether they are mirror images of each other. This means that the structure and values of one tree must exactly reflect those of the other, but in a mirrored way. Specifically, for every node in the first tree, its left child must match the right child of the corresponding node in the second tree, and vice versa.

This problem is common in recursion-based tree problems and tests your ability to compare tree structures and values symmetrically.

Step-by-Step Solution with Example

Step 1: Understand the Mirror Concept

Two trees are mirrors if:

  • They are both empty (null)
  • Or, their root nodes have equal values, and their left and right subtrees are mirrors of each other in opposite directions

Step 2: Use a Recursive Approach

The simplest and cleanest way to solve this is using recursion. We define a function isMirror(tree1, tree2) that checks:

  • If both trees are null, return true
  • If only one is null, return false
  • If values don't match, return false
  • Recursively check isMirror(tree1.left, tree2.right) and isMirror(tree1.right, tree2.left)

Step 3: Apply the Approach to an Example

Let’s take two trees:


Tree A         Tree B
   1              1
  /             /  2   3          3   2

We compare:

  • Roots: 1 == 1 ✅
  • Left of A (2) with Right of B (2) ✅
  • Right of A (3) with Left of B (3) ✅

All checks pass recursively, so these trees are mirror images.

Step 4: Implement the Code


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

Edge Cases

Case 1: Both Trees Are Empty

Two null trees are mirrors by definition. Return true.

Case 2: One Tree is Empty

One null and one non-null tree can never be mirrors. Return false.

Case 3: Different Root Values

If the roots are not equal, trees can't be mirrors. Check t1.val != t2.val.

Case 4: Matching Roots, Unmatched Subtrees

Even if roots match, if the left and right children don't mirror each other in structure and value, return false.

Case 5: Single Node Trees

If both trees are single nodes with the same value, they are mirrors. If either node has children and the other doesn’t, they’re not mirrors.

Finally

This problem teaches the power of recursion and symmetry. The key idea is to mirror the traversal — compare left of one with right of the other and continue down the tree. Always consider the base cases carefully, and remember to match both structure and value. With these principles, you can confidently identify mirror trees!

  1. Given two binary trees, if both trees are empty, they are mirrors; if one is empty and the other is not, they are not mirrors.
  2. Compare the root nodes of both trees. If the values are not equal, the trees are not mirrors.
  3. Recursively check if the left subtree of the first tree is a mirror of the right subtree of the second tree, and if the right subtree of the first tree is a mirror of the left subtree of the second tree.
  4. If both recursive checks return true, then the two trees are mirror images of each other.

Implementation and efficiency

C implementation

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
} TreeNode;

TreeNode* createNode(int val) {
    TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
    node->val = val;
    node->left = node->right = NULL;
    return node;
}

bool isMirror(TreeNode* t1, TreeNode* t2) {
    if (t1 == NULL && t2 == NULL) return true;
    if (t1 == NULL || t2 == NULL) return false;
    return (t1->val == t2->val) &&
           isMirror(t1->left, t2->right) &&
           isMirror(t1->right, t2->left);
}

int main() {
    TreeNode* tree1 = createNode(1);
    tree1->left = createNode(2);
    tree1->right = createNode(3);

    TreeNode* tree2 = createNode(1);
    tree2->left = createNode(3);
    tree2->right = createNode(2);

    printf("%s\n", isMirror(tree1, tree2) ? "true" : "false");
    return 0;
}

C++ implementation

#include <iostream>
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left, *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

bool isMirror(TreeNode* t1, TreeNode* t2) {
    if (!t1 && !t2) return true;
    if (!t1 || !t2) return false;
    return (t1->val == t2->val) &&
           isMirror(t1->left, t2->right) &&
           isMirror(t1->right, t2->left);
}

int main() {
    TreeNode* tree1 = new TreeNode(1);
    tree1->left = new TreeNode(2);
    tree1->right = new TreeNode(3);

    TreeNode* tree2 = new TreeNode(1);
    tree2->left = new TreeNode(3);
    tree2->right = new TreeNode(2);

    cout << (isMirror(tree1, tree2) ? "true" : "false") << endl;
    return 0;
}

Python implementation

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def isMirror(t1, t2):
    if not t1 and not t2:
        return True
    if not t1 or not t2:
        return False
    return (t1.val == t2.val and
            isMirror(t1.left, t2.right) and
            isMirror(t1.right, t2.left))

if __name__ == '__main__':
    tree1 = TreeNode(1, TreeNode(2), TreeNode(3))
    tree2 = TreeNode(1, TreeNode(3), TreeNode(2))
    print(isMirror(tree1, tree2))

Java implementation

class TreeNode {
    int val;
    TreeNode left, right;
    TreeNode(int x) { val = x; }
}

public class MirrorTrees {
    public boolean isMirror(TreeNode t1, TreeNode t2) {
        if (t1 == null && t2 == null) return true;
        if (t1 == null || t2 == null) return false;
        return (t1.val == t2.val) &&
               isMirror(t1.left, t2.right) &&
               isMirror(t1.right, t2.left);
    }

    public static void main(String[] args) {
        MirrorTrees sol = new MirrorTrees();
        TreeNode tree1 = new TreeNode(1);
        tree1.left = new TreeNode(2);
        tree1.right = new TreeNode(3);

        TreeNode tree2 = new TreeNode(1);
        tree2.left = new TreeNode(3);
        tree2.right = new TreeNode(2);

        System.out.println(sol.isMirror(tree1, tree2));
    }
}

JavaScript implementation

class TreeNode {
    constructor(val, left = null, right = null) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

function isMirror(t1, t2) {
    if (!t1 && !t2) return true;
    if (!t1 || !t2) return false;
    return (t1.val === t2.val) &&
           isMirror(t1.left, t2.right) &&
           isMirror(t1.right, t2.left);
}

const tree1 = new TreeNode(1, new TreeNode(2), new TreeNode(3));
const tree2 = new TreeNode(1, new TreeNode(3), new TreeNode(2));
console.log(isMirror(tree1, tree2));

Go implementation

package main

import (
    "fmt"
)

type TreeNode struct {
    val   int
    left  *TreeNode
    right *TreeNode
}

func isMirror(t1, t2 *TreeNode) bool {
    if t1 == nil && t2 == nil {
        return true
    }
    if t1 == nil || t2 == nil {
        return false
    }
    return t1.val == t2.val &&
        isMirror(t1.left, t2.right) &&
        isMirror(t1.right, t2.left)
}

func main() {
    tree1 := &TreeNode{1, &TreeNode{2, nil, nil}, &TreeNode{3, nil, nil}}
    tree2 := &TreeNode{1, &TreeNode{3, nil, nil}, &TreeNode{2, nil, nil}}
    fmt.Println(isMirror(tree1, tree2))
}

Rust implementation

struct TreeNode {
    val: i32,
    left: Option<Box<TreeNode>>,
    right: Option<Box<TreeNode>>,
}

fn is_mirror(t1: &Option<Box<TreeNode>>, t2: &Option<Box<TreeNode>>) -> bool {
    match (t1, t2) {
        (None, None) => true,
        (Some(n1), Some(n2)) => {
            n1.val == n2.val &&
            is_mirror(&n1.left, &n2.right) &&
            is_mirror(&n1.right, &n2.left)
        },
        _ => false,
    }
}

fn main() {
    let tree1 = Some(Box::new(TreeNode {
        val: 1,
        left: Some(Box::new(TreeNode { val: 2, left: None, right: None })),
        right: Some(Box::new(TreeNode { val: 3, left: None, right: None })),
    }));

    let tree2 = Some(Box::new(TreeNode {
        val: 1,
        left: Some(Box::new(TreeNode { val: 3, left: None, right: None })),
        right: Some(Box::new(TreeNode { val: 2, left: None, right: None })),
    }));

    println!("{}", is_mirror(&tree1, &tree2));
}

Kotlin implementation

class TreeNode(val value: Int) {
    var left: TreeNode? = null
    var right: TreeNode? = null
}

fun isMirror(t1: TreeNode?, t2: TreeNode?): Boolean {
    if (t1 == null && t2 == null) return true
    if (t1 == null || t2 == null) return false
    return (t1.value == t2.value) &&
           isMirror(t1.left, t2.right) &&
           isMirror(t1.right, t2.left)
}

fun main() {
    val tree1 = TreeNode(1)
    tree1.left = TreeNode(2)
    tree1.right = TreeNode(3)

    val tree2 = TreeNode(1)
    tree2.left = TreeNode(3)
    tree2.right = TreeNode(2)

    println(isMirror(tree1, tree2))
}

Swift implementation

class TreeNode {
    var val: Int
    var left: TreeNode?
    var right: TreeNode?
    init(_ val: Int) {
        self.val = val
        self.left = nil
        self.right = nil
    }
}

func isMirror(_ t1: TreeNode?, _ t2: TreeNode?) -> Bool {
    if t1 == nil && t2 == nil { return true }
    if t1 == nil || t2 == nil { return false }
    return t1!.val == t2!.val &&
           isMirror(t1!.left, t2!.right) &&
           isMirror(t1!.right, t2!.left)
}

let tree1 = TreeNode(1)
tree1.left = TreeNode(2)
tree1.right = TreeNode(3)

let tree2 = TreeNode(1)
tree2.left = TreeNode(3)
tree2.right = TreeNode(2)

print(isMirror(tree1, tree2))

TypeScript implementation

class TreeNode {
    val: number;
    left: TreeNode | null;
    right: TreeNode | null;

    constructor(val: number, left: TreeNode | null = null, right: TreeNode | null = null) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

function isMirror(t1: TreeNode | null, t2: TreeNode | null): boolean {
    if (!t1 && !t2) return true;
    if (!t1 || !t2) return false;
    return t1.val === t2.val &&
           isMirror(t1.left, t2.right) &&
           isMirror(t1.right, t2.left);
}

const tree1 = new TreeNode(1, new TreeNode(2), new TreeNode(3));
const tree2 = new TreeNode(1, new TreeNode(3), new TreeNode(2));
console.log(isMirror(tree1, tree2));