How to check mirror in N-ary tree using hashing in Java
In computer science and data structures, trees are the basic structures that depict hierarchical data. A very interesting problem about trees is verifying if two
Understanding and solving the problem of checking mirrors in N-ary trees has several real-world applications and benefits. Here are some domains where this problem is relevant:
Network topology and design: In network design, it is essential to understand the symmetry and redundancy of network structures. Ensuring that network topologies are mirrored can provide insights into load balancing and fault tolerance.
User interface design: When creating user interfaces that need to mirror layouts for different orientations or localizations, checking the mirrored structure programmatically can ensure consistency and correctness in the design.
Robotics and path planning: In robotics, mirrored tree structures can be used to plan symmetric paths or to verify that two paths are symmetric, which is useful in synchronized robot movements.
Data synchronization: Ensuring that mirrored data structures are consistent across different systems is crucial for data integrity in distributed systems and cloud computing.
Genetic research: In bioinformatics, tree structures are used to show the
. Mirroring trees can be used by evolutionists in order to study the evolution of species.phylogenetic trees A phylogenetic tree is a graphical representation of the evolutionary relationships between biological entities, usually sequences or species.
What is a mirror in N-ary trees?
Two N-ary trees are considered mirrors of each other if they exhibit the following properties:
The root nodes are the same (or equivalent).
The children of each node in one tree are in the reverse order of the children in the corresponding node in the other tree.
Note: The tree structure and the values should mirror each other, node for node (each node in one tree should have a corresponding node in the other tree at the same level, but in reverse order), in both trees.
For the above two N-ary trees, we have the edges as:
N-ary tree
edge : N-ary tree
edge : N-ary tree
edge : N-ary tree
edge :
Since the roots of both trees are the same and the children of each node in ‘N-ary tree
Hashing to check mirroring
Hashing is a technique that maps data to a fixed-size output, which can be used to compare complex structures quickly. To check if two N-ary trees are mirrors, we can hash the structure and values of each tree and compare the results.
The following steps outline our approach:
Hash the tree structure: Traverse the tree and generate a hash based on the structure and values of each node.
Check the mirror property: Determine if the hashed values of two trees indicate that they are mirrors of each other.
Handle children’s order: Ensure that the order of children in one tree is the reverse of the other.
Let’s understand this process with the help of an illustration:
Implementation
Let’s create a program that checks whether two N-ary trees are mirrors of each other or not using hashing.
import java.util.List;import java.util.ArrayList;import java.util.Collections;public class MirrorChecker {// Hash a tree to create a unique representationprivate static String hashTree(TreeNode node, boolean reverseOrder) {if (node == null) {return "";}// Start the hash with the node's valueStringBuilder hashBuilder = new StringBuilder();hashBuilder.append(node.value);// Create a list to store the hashes of the childrenList<String> childrenHashes = new ArrayList<>();for (TreeNode child : node.children) {childrenHashes.add(hashTree(child, reverseOrder));}// Sort or reverse the order of the children hashes based on the 'reverseOrder' flagif (reverseOrder) {Collections.reverse(childrenHashes);} else {Collections.sort(childrenHashes);}// Append the sorted/reversed hashes to the main hashfor (String childHash : childrenHashes) {hashBuilder.append("-").append(childHash);}return hashBuilder.toString();}// Check if two trees are mirrors by comparing their hashespublic static boolean areMirrors(TreeNode tree1, TreeNode tree2) {// Get the hash for the first tree with normal orderString hash1 = hashTree(tree1, false);// Get the hash for the second tree with reversed orderString hash2 = hashTree(tree2, true);return hash1.equals(hash2);}public static void main(String[] args) {// Create the first treeTreeNode root1 = new TreeNode(1);TreeNode child11 = new TreeNode(2);TreeNode child12 = new TreeNode(3);root1.addChild(child11);root1.addChild(child12);// Create the second tree (mirror of the first)TreeNode root2 = new TreeNode(1);TreeNode child21 = new TreeNode(3);TreeNode child22 = new TreeNode(2);root2.addChild(child21);root2.addChild(child22);// Check if the trees are mirrorsboolean isMirror = areMirrors(root1, root2);System.out.println("Are the trees mirrors? " + isMirror); // Expected output: true}}
Code explanation of MirrorChecker.java file
Let’s look at the breakdown of the MirrorChecker.java file below:
Lines 1–3: Imports
List,ArrayList, andCollections.Collectionsis used for sorting and reversing lists, whileListandArrayListare used to represent N-ary tree structures.Lines 7–36: Implements a method
hashTreethat generates a hash representation of N-ary tree node. ThereverseOrderparameter determines if the children should be hashed in reverse order.Lines 8–10: Checks if the
nodeisnull. If so, returns an empty string, indicating no more nodes to process.Lines 13–14: Initializes a
StringBuilderand appends the node’svalueto start building the hash.Line 17: Creates a list
childrenHashesto store the hash representations of the children nodes.Lines 19–21: Iterates over the
childrenlist and recursively callshashTree, adding each result tochildrenHashes.Lines 24–28: If
reverseOrderistrue, reverseschildrenHashes. Otherwise, sorts it to maintain consistent ordering.Lines 31–33: Appends each hash from
childrenHashestohashBuilder, forming the complete hash representation.
Lines 39–47: Implements the
areMirrorsmethod, which checks if two N-ary trees are mirrors of each other by comparing their hash representations.Lines 41–44: Gets the hash for the first tree in normal order and for the second tree in reverse order.
Line 46: Returns the result of the comparison after comparing the two hash values. If they are equal, the trees are considered mirrors.
Lines 59–67: The
mainmethod creates two trees and checks if they are mirrors of each other, using theareMirrorsmethod to determine if the hash representations indicate mirroring.Lines 51–55: Creates the first tree with a root node of
1and child nodes2and3.Lines 58–62: Creates the second tree with a root node of
1, but with child nodes in reverse order:3and2.Line 65: Calls
areMirrorsmethod to check if these two trees are mirrors and stores the result in variableisMirror.Line 66: Outputs whether the trees are mirrors. If
areMirrorsreturnstrue, the output will be “Are the trees mirrors? true.”
Code explanation of TreeNode.java file
Let’s look at the breakdown of the TreeNode.java file below:
Lines 1–2: Imports the
ListandArrayListclasses from thejava.utilpackage, allowing the creation of lists to manage children nodes in the N-ary tree.Lines 4–16:
Defines a class
TreeNoderepresenting a node in N-ary tree.The class has two fields:
value(an integer representing the node’s data) andchildren(a list to store references to child nodes).
Lines 8–15:
Line 8: Constructor for
TreeNodethat initializes thevaluewith the given argument and creates an empty list forchildren.Line 10: Initializes the
childrenlist with a newArrayList.Lines 13–15: Here, we have a method
addChildthat adds a givenTreeNodeto thechildrenlist.
Quiz
Let’s challenge your understanding of this Answer. This will help you assess how well you’ve grasped the key concepts we’ve discussed.
What is the purpose of hashing the N-ary tree in the hashTree method of the MirrorChecker class?
private static String hashTree(TreeNode node, boolean reverseOrder) {
if (node == null) {
return "";
}
StringBuilder hashBuilder = new StringBuilder();
hashBuilder.append(node.value);
List<String> childrenHashes = new ArrayList<>();
for (TreeNode child : node.children) {
childrenHashes.add(hashTree(child, reverseOrder));
}
if (reverseOrder) {
Collections.reverse(childrenHashes);
} else {
Collections.sort(childrenHashes);
}
for (String childHash : childrenHashes) {
hashBuilder.append("-").append(childHash);
}
return hashBuilder.toString();
}
To store the tree in a compressed format
To ensure the uniqueness of the tree’s representation
To encrypt the tree data for security purposes
To improve the performance of tree traversal operations
Free Resources