1.
Function to Find the Lowest Common Ancestor (LCA) of Two Nodes in a Binary Search Tree
class TreeNode {
int value;
TreeNode left, right;
TreeNode(int value) {
this.value = value;
left = right = null;
public class BinarySearchTree {
public TreeNode findLCA(TreeNode root, TreeNode p, TreeNode q) {
// Base case
if (root == null) {
return null;
// If both nodes are smaller, LCA is in the left subtree
if (p.value < root.value && q.value < root.value) {
return findLCA(root.left, p, q);
// If both nodes are greater, LCA is in the right subtree
if (p.value > root.value && q.value > root.value) {
return findLCA(root.right, p, q);
// If one node is on either side or is the root, root is the LCA
return root;
}
}
Explanation:
This function uses the properties of the BST to navigate the tree and find the LCA. It checks if
both nodes are smaller or larger than the current root to move left or right, respectively.
2. Function to Construct a Binary Tree from In-order and Pre-order Traversal Arrays
class TreeNode {
int value;
TreeNode left, right;
TreeNode(int value) {
this.value = value;
left = right = null;
public class BinaryTree {
private int preIndex = 0;
public TreeNode buildTree(int[] inorder, int[] preorder) {
return buildTreeUtil(inorder, preorder, 0, inorder.length - 1);
private TreeNode buildTreeUtil(int[] inorder, int[] preorder, int inStart, int inEnd) {
if (inStart > inEnd) {
return null;
// Get the root node from preorder traversal
TreeNode root = new TreeNode(preorder[preIndex++]);
// Find the index of the root in inorder traversal
int rootIndex = findIndex(inorder, inStart, inEnd, root.value);
// Build the left and right subtrees recursively
root.left = buildTreeUtil(inorder, preorder, inStart, rootIndex - 1);
root.right = buildTreeUtil(inorder, preorder, rootIndex + 1, inEnd);
return root;
private int findIndex(int[] inorder, int inStart, int inEnd, int value) {
for (int i = inStart; i <= inEnd; i++) {
if (inorder[i] == value) {
return i;
return -1;
Explanation:
This function builds a binary tree using the preorder array to get the root node and the
inorder array to find the position of the root and split the tree into left and right subtrees
recursively.
3. Time Complexity of In-order Traversal on a Binary Search Tree
// In-order traversal
void inOrder(TreeNode root) {
if (root == null) {
return;
inOrder(root.left);
System.out.print(root.value + " ");
inOrder(root.right);
}
Explanation:
Time Complexity: O(n), where n is the number of nodes in the tree. Each node is visited
exactly once during the traversal.
4. Time Complexity of Inserting a Sequence of Elements into a Binary Search Tree
public class BinarySearchTree {
TreeNode root;
// Insert a node into the BST
public void insert(int value) {
root = insertRec(root, value);
private TreeNode insertRec(TreeNode root, int value) {
if (root == null) {
root = new TreeNode(value);
return root;
if (value < root.value) {
root.left = insertRec(root.left, value);
} else {
root.right = insertRec(root.right, value);
return root;
Explanation:
Time Complexity:
o Worst-case: O(n), where n is the number of nodes (for a skewed tree, like a linked
list).
o Best-case: O(log n), where the tree is balanced.
o Balancing trees: Tree balancing algorithms (like AVL or Red-Black trees) can improve
performance to O(log n) for insertion, making the tree more efficient.
5. Efficiency of Different Tree Traversal Algorithms (In-order, Pre-order, Post-order)
// In-order, Pre-order, and Post-order Traversal Examples:
// In-order Traversal
void inOrder(TreeNode root) {
if (root == null) return;
inOrder(root.left);
System.out.print(root.value + " ");
inOrder(root.right);
// Pre-order Traversal
void preOrder(TreeNode root) {
if (root == null) return;
System.out.print(root.value + " ");
preOrder(root.left);
preOrder(root.right);
// Post-order Traversal
void postOrder(TreeNode root) {
if (root == null) return;
postOrder(root.left);
postOrder(root.right);
System.out.print(root.value + " ");
Explanation:
In-order Traversal: Efficient for BSTs because it visits nodes in sorted order. Time complexity
is O(n), and space complexity is O(h) for the recursion stack, where h is the height of the
tree.
Pre-order Traversal: Can be used for copying the tree, but it does not guarantee sorted
output. Time complexity is O(n), and space complexity is O(h).
Post-order Traversal: Useful for tree deletion or evaluating expressions, but like the others, it
has O(n) time complexity and O(h) space complexity.
6. Class to Implement a Basic Binary Tree with Insert, Delete, and Traversal Operations
class TreeNode {
int value;
TreeNode left, right;
public TreeNode(int value) {
this.value = value;
left = right = null;
public class BinaryTree {
private TreeNode root;
// Insert a node in the binary tree
public void insert(int value) {
root = insertRec(root, value);
private TreeNode insertRec(TreeNode root, int value) {
if (root == null) {
root = new TreeNode(value);
return root;
if (value < root.value) {
root.left = insertRec(root.left, value);
} else {
root.right = insertRec(root.right, value);
}
return root;
// Delete a node in the binary tree
public void delete(int value) {
root = deleteRec(root, value);
private TreeNode deleteRec(TreeNode root, int value) {
if (root == null) return root;
if (value < root.value) {
root.left = deleteRec(root.left, value);
} else if (value > root.value) {
root.right = deleteRec(root.right, value);
} else {
// Node with only one child or no child
if (root.left == null) {
return root.right;
} else if (root.right == null) {
return root.left;
// Node with two children, get the inorder successor (smallest in the right subtree)
root.value = minValue(root.right);
// Delete the inorder successor
root.right = deleteRec(root.right, root.value);
return root;
}
// Find the minimum value node in the tree
private int minValue(TreeNode root) {
int minValue = root.value;
while (root.left != null) {
minValue = root.left.value;
root = root.left;
return minValue;
// In-order traversal
public void inOrder() {
inOrderRec(root);
private void inOrderRec(TreeNode root) {
if (root == null) return;
inOrderRec(root.left);
System.out.print(root.value + " ");
inOrderRec(root.right);
// Pre-order traversal
public void preOrder() {
preOrderRec(root);
private void preOrderRec(TreeNode root) {
if (root == null) return;
System.out.print(root.value + " ");
preOrderRec(root.left);
preOrderRec(root.right);
// Post-order traversal
public void postOrder() {
postOrderRec(root);
private void postOrderRec(TreeNode root) {
if (root == null) return;
postOrderRec(root.left);
postOrderRec(root.right);
System.out.print(root.value + " ");
// Level-order traversal (Breadth-First)
public void levelOrder() {
if (root == null) return;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
System.out.print(node.value + " ");
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
}
}
7. Function to Perform In-order Traversal of a Binary Tree
public void inOrderTraversal(TreeNode root) {
if (root == null) return;
inOrderTraversal(root.left);
System.out.print(root.value + " ");
inOrderTraversal(root.right);
Explanation:
In-order Traversal: This traversal visits the left subtree, then the current node, and finally the
right subtree. It results in nodes being visited in ascending order for a BST.
8. Function to Perform Pre-order Traversal of a Binary Tree
public void preOrderTraversal(TreeNode root) {
if (root == null) return;
System.out.print(root.value + " ");
preOrderTraversal(root.left);
preOrderTraversal(root.right);
Explanation:
Pre-order Traversal: This traversal visits the current node first, then the left subtree, and
finally the right subtree.
9. Function to Perform Post-order Traversal of a Binary Tree
public void postOrderTraversal(TreeNode root) {
if (root == null) return;
postOrderTraversal(root.left);
postOrderTraversal(root.right);
System.out.print(root.value + " ");
Explanation:
Post-order Traversal: This traversal visits the left subtree first, then the right subtree, and
finally the current node.
10. Function to Perform Level-order Traversal of a Binary Tree
public void levelOrderTraversal(TreeNode root) {
if (root == null) return;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
System.out.print(node.value + " ");
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
Explanation:
Level-order Traversal: Also known as Breadth-First Traversal, this traversal visits all nodes at
the present depth level before moving on to nodes at the next depth level. We use a queue
to keep track of nodes at each level.
11. Construct a Binary Tree from Given In-order and Post-order Traversal Arrays
To construct a binary tree from given in-order and post-order traversals, we can use the following
approach:
public class BinaryTree {
private int postIndex;
public TreeNode buildTree(int[] inorder, int[] postorder) {
postIndex = postorder.length - 1;
return buildTreeUtil(inorder, postorder, 0, inorder.length - 1);
private TreeNode buildTreeUtil(int[] inorder, int[] postorder, int inStart, int inEnd) {
if (inStart > inEnd) return null;
// Get the root value from postorder array
TreeNode root = new TreeNode(postorder[postIndex--]);
// Find the root index in the inorder array
int rootIndex = findIndex(inorder, inStart, inEnd, root.value);
// Recursively build the right and left subtrees
root.right = buildTreeUtil(inorder, postorder, rootIndex + 1, inEnd);
root.left = buildTreeUtil(inorder, postorder, inStart, rootIndex - 1);
return root;
private int findIndex(int[] inorder, int inStart, int inEnd, int value) {
for (int i = inStart; i <= inEnd; i++) {
if (inorder[i] == value) return i;
return -1;
Explanation:
In-order and Post-order Construction:
o The last element in the post-order array is the root of the tree. We find this root in
the in-order array, which divides the tree into left and right subtrees. Recursively
construct the subtrees from this information.
Example of Usage:
public static void main(String[] args) {
BinaryTree tree = new BinaryTree();
// Insert nodes into the tree
tree.insert(3);
tree.insert(1);
tree.insert(4);
tree.insert(0);
tree.insert(5);
tree.insert(2);
// Perform various traversals
System.out.println("In-order traversal:");
tree.inOrder(); // Output: 0 1 2 3 4 5
System.out.println("\nPre-order traversal:");
tree.preOrder(); // Output: 3 1 0 2 4 5
System.out.println("\nPost-order traversal:");
tree.postOrder(); // Output: 0 2 1 5 4 3
System.out.println("\nLevel-order traversal:");
tree.levelOrder(); // Output: 3 1 4 0 2 5
// Construct a tree from in-order and post-order
int[] inorder = {3, 1, 4, 0, 5, 2};
int[] postorder = {0, 1, 3, 4, 2, 5};
TreeNode root = tree.buildTree(inorder, postorder);
System.out.println("\nIn-order traversal of constructed tree:");
tree.inOrderTraversal(root); // Output: 3 1 4 0 5 2
Conclusion:
Insert, Delete, and Traversal Operations: We implemented basic insert, delete, and traversal
operations on a binary tree.
Traversal Functions: We implemented in-order, pre-order, post-order, and level-order
traversals.
Tree Construction: We constructed a binary tree from in-order and post-order traversals
using recursion.
This covers the requested tasks, providing a complete understanding of binary tree operations and
traversals.