Create Binary Tree From Inorder Preorder

A
a
```package com.thealgorithms.datastructures.trees;

import com.thealgorithms.datastructures.trees.BinaryTree.Node;
import java.util.HashMap;
import java.util.Map;

/**
* Approach: Naive Solution: Create root node from first value present in
* preorder traversal. Look for the index of root node's value in inorder
* traversal. That will tell total nodes present in left subtree and right
* subtree. Based on that index create left and right subtree. Complexity: Time:
* O(n^2) for each node there is iteration to find index in inorder array Space:
* Stack size = O(height) = O(lg(n))
*
* Optimized Solution: Instead of iterating over inorder array to find index of
* root value, create a hashmap and find out the index of root value.
* Complexity: Time: O(n) hashmap reduced iteration to find index in inorder
* array Space: O(n) space taken by hashmap
*
*/
public class CreateBinaryTreeFromInorderPreorder {

public static void main(String[] args) {
test(new Integer[] {}, new Integer[] {}); // empty tree
test(new Integer[] { 1 }, new Integer[] { 1 }); // single node tree
test(new Integer[] { 1, 2, 3, 4 }, new Integer[] { 1, 2, 3, 4 }); // right skewed tree
test(new Integer[] { 1, 2, 3, 4 }, new Integer[] { 4, 3, 2, 1 }); // left skewed tree
test(
new Integer[] { 3, 9, 20, 15, 7 },
new Integer[] { 9, 3, 15, 20, 7 }
); // normal tree
}

private static void test(
final Integer[] preorder,
final Integer[] inorder
) {
System.out.println(
"\n===================================================="
);
System.out.println("Naive Solution...");
BinaryTree root = new BinaryTree(
createTree(preorder, inorder, 0, 0, inorder.length)
);
System.out.println("Preorder Traversal: ");
root.preOrder(root.getRoot());
System.out.println("\nInorder Traversal: ");
root.inOrder(root.getRoot());
System.out.println("\nPostOrder Traversal: ");
root.postOrder(root.getRoot());

Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i], i);
}
BinaryTree optimizedRoot = new BinaryTree(
createTreeOptimized(preorder, inorder, 0, 0, inorder.length, map)
);
System.out.println("\n\nOptimized solution...");
System.out.println("Preorder Traversal: ");
optimizedRoot.preOrder(root.getRoot());
System.out.println("\nInorder Traversal: ");
optimizedRoot.inOrder(root.getRoot());
System.out.println("\nPostOrder Traversal: ");
optimizedRoot.postOrder(root.getRoot());
}

private static Node createTree(
final Integer[] preorder,
final Integer[] inorder,
final int preStart,
final int inStart,
final int size
) {
if (size == 0) {
return null;
}

Node root = new Node(preorder[preStart]);
int i = inStart;
while (preorder[preStart] != inorder[i]) {
i++;
}
int leftNodesCount = i - inStart;
int rightNodesCount = size - leftNodesCount - 1;
root.left =
createTree(
preorder,
inorder,
preStart + 1,
inStart,
leftNodesCount
);
root.right =
createTree(
preorder,
inorder,
preStart + leftNodesCount + 1,
i + 1,
rightNodesCount
);
return root;
}

private static Node createTreeOptimized(
final Integer[] preorder,
final Integer[] inorder,
final int preStart,
final int inStart,
final int size,
final Map<Integer, Integer> inorderMap
) {
if (size == 0) {
return null;
}

Node root = new Node(preorder[preStart]);
int i = inorderMap.get(preorder[preStart]);
int leftNodesCount = i - inStart;
int rightNodesCount = size - leftNodesCount - 1;
root.left =
createTreeOptimized(
preorder,
inorder,
preStart + 1,
inStart,
leftNodesCount,
inorderMap
);
root.right =
createTreeOptimized(
preorder,
inorder,
preStart + leftNodesCount + 1,
i + 1,
rightNodesCount,
inorderMap
);
return root;
}
}
```