From c7ccfd60c3b1dbbfaefb288001d37df4e638ce04 Mon Sep 17 00:00:00 2001 From: amarmaurya-com Date: Thu, 30 Oct 2025 10:41:19 +0530 Subject: [PATCH 1/4] Implemented BST with insert and traversal methods --- src/main/java/com/thealgorithms/tree/BST.java | 278 ++++++++++++++++++ .../java/com/thealgorithms/tree/BSTTest.java | 218 ++++++++++++++ 2 files changed, 496 insertions(+) create mode 100644 src/main/java/com/thealgorithms/tree/BST.java create mode 100644 src/test/java/com/thealgorithms/tree/BSTTest.java diff --git a/src/main/java/com/thealgorithms/tree/BST.java b/src/main/java/com/thealgorithms/tree/BST.java new file mode 100644 index 000000000000..b8c4b96b4cbd --- /dev/null +++ b/src/main/java/com/thealgorithms/tree/BST.java @@ -0,0 +1,278 @@ +package com.thealgorithms.tree; + +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; + +public class BST { + + /** + * Node class represents a node in the BST. + * 0->0->0 + * 0=Nodes\ + * each node contains divided into 3 section + * Key-> Actual value, + * left-> store the address of left tree, + * Right-> store the address of right tree + */ + private static class Node { + int key; + Node left, right; + + Node(int key) { + this.key = key; + left = right = null; + } + } + + // Root of the BST + // the first of Node tree + //0-> + private Node root; + + /** Create an empty BST. */ + public BST() { + root = null; + } + + /* =========================== + * INSERT + * =========================== */ + + /** + * Insert a value into the BST. Duplicate values are ignored (no-op). + * + * @param value value to insert + */ + public void insert(int value) { + root = insertRecursive(root, value); + } + + // Helper recursive method for insertion. + private Node insertRecursive(Node node, int value) { + // If we reached a null position, create and return a new node. + if (node == null) { + return new Node(value); + } + + // If value is less, go left; if greater, go right; if equal, do nothing. + if (value < node.key) { + node.left = insertRecursive(node.left, value); + } else if (value > node.key) { + node.right = insertRecursive(node.right, value); + } // else duplicate -> ignore + + return node; // return current (possibly updated) subtree root + } + + /* =========================== + * SEARCH + * =========================== */ + + /** + * Search the BST for a value. + * + * @param value value to search + * @return true if value exists in the BST, false otherwise + */ + public boolean search(int value) { + return searchRecursive(root, value); + } + + private boolean searchRecursive(Node node, int value) { + if (node == null) { + return false; // reached leaf, not found + } + if (value == node.key) { + return true; // found exact match + } else if (value < node.key) { + return searchRecursive(node.left, value); // search left subtree + } else { + return searchRecursive(node.right, value); // search right subtree + } + } + + /* =========================== + * DELETE + * =========================== */ + + /** + * Delete a value from the BST. If the value is not present, tree remains unchanged. + * + * @param value value to delete + */ + public void delete(int value) { + root = deleteRecursive(root, value); + } + + // Helper for deletion, handles three cases: + // 1) node is a leaf -> just remove + // 2) node has one child -> replace node with child + // 3) node has two children -> replace node with successor (smallest in right subtree) + private Node deleteRecursive(Node node, int value) { + if (node == null) { + return null; // value not found + } + + if (value < node.key) { + // target is in left subtree + node.left = deleteRecursive(node.left, value); + } else if (value > node.key) { + // target is in right subtree + node.right = deleteRecursive(node.right, value); + } else { + // node.key == value -> delete this node + // Case 1 & 2: node has 0 or 1 child + if (node.left == null) { + // return right child (could be null) to replace node + return node.right; + } else if (node.right == null) { + // return left child to replace node + return node.left; + } + + // Case 3: node has two children + // Find the inorder successor (smallest in the right subtree) + Node successor = findMinNode(node.right); + // Copy successor's value to this node + node.key = successor.key; + // Delete the successor node from right subtree + node.right = deleteRecursive(node.right, successor.key); + } + + return node; + } + + /** + * Find the minimum key in the BST. + * + * @return the smallest integer key in the tree + * @throws NoSuchElementException if the tree is empty + */ + public int findMin() { + if (root == null) { + throw new NoSuchElementException("BST is empty"); + } + return findMinNode(root).key; + } + + // Helper to find node with minimum key in a subtree (leftmost node) + private Node findMinNode(Node node) { + Node current = node; + // go as far left as possible + while (current.left != null) { + current = current.left; + } + return current; + } + + /** + * Find the maximum key in the BST. + * + * the largest integer key in the tree + * NoSuchElementException if the tree is empty + */ + public int findMax() { + if (root == null) { + throw new NoSuchElementException("BST is empty"); + } + Node current = root; + // go as far right as possible + while (current.right != null) { + current = current.right; + } + return current.key; + } + + + /** + * Print inorder traversal (Left, Node, Right). + * InOrder -> Left, key, Right + */ + public void printInorder() { + System.out.print("Inorder: "); + printInorderRecursive(root); + System.out.println(); + } + + private void printInorderRecursive(Node node) { + if (node == null) return; + printInorderRecursive(node.left); // left + System.out.print(node.key + " "); // node + printInorderRecursive(node.right); // right + } + + /** + * Print preorder traversal (Node, Left, Right). + * PreOrder -> key,Left, Right + */ + public void printPreorder() { + System.out.print("Preorder: "); + printPreorderRecursive(root); + System.out.println(); + } + + private void printPreorderRecursive(Node node) { + if (node == null) return; + System.out.print(node.key + " "); // node + printPreorderRecursive(node.left); // left + printPreorderRecursive(node.right); // right + } + + /** + * Print postorder traversal (Left, Right, Node). + *PreOrder -> key,Left, Right + */ + public void printPostorder() { + System.out.print("Postorder: "); + printPostorderRecursive(root); + System.out.println(); + } + + private void printPostorderRecursive(Node node) { + if (node == null) return; + printPostorderRecursive(node.left); // left + printPostorderRecursive(node.right); // right + System.out.print(node.key + " "); // node + } + + public List inorderList() { + List result = new ArrayList<>(); + inorderToList(root, result); + return result; + } + + private void inorderToList(Node node, List out) { + if (node == null) return; + inorderToList(node.left, out); + out.add(node.key); + inorderToList(node.right, out); + } + + + public List preorderList() { + List result = new ArrayList<>(); + preorderToList(root, result); + return result; + } + + private void preorderToList(Node node, List out) { + if (node == null) return; + out.add(node.key); + preorderToList(node.left, out); + preorderToList(node.right, out); + } + + public List postorderList() { + List result = new ArrayList<>(); + postorderToList(root, result); + return result; + } + + private void postorderToList(Node node, List out) { + if (node == null) return; + postorderToList(node.left, out); + postorderToList(node.right, out); + out.add(node.key); + } +} diff --git a/src/test/java/com/thealgorithms/tree/BSTTest.java b/src/test/java/com/thealgorithms/tree/BSTTest.java new file mode 100644 index 000000000000..cff3ab6aec81 --- /dev/null +++ b/src/test/java/com/thealgorithms/tree/BSTTest.java @@ -0,0 +1,218 @@ +package com.thealgorithms.tree; + +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; + +public class BSTTest { + + private static class Node { + int key; + Node left, right; + + Node(int key) { + this.key = key; + left = right = null; + } + } + + private Node root; + + public BSTTest() { + root = null; + } + + public void insert(int value) { + root = insertRecursive(root, value); + } + + private Node insertRecursive(Node node, int value) { + if (node == null) { + return new Node(value); + } + if (value < node.key) { + node.left = insertRecursive(node.left, value); + } else if (value > node.key) { + node.right = insertRecursive(node.right, value); + } + return node; + } + + public boolean search(int value) { + return searchRecursive(root, value); + } + + private boolean searchRecursive(Node node, int value) { + if (node == null) { + return false; + } + if (value == node.key) { + return true; + } else if (value < node.key) { + return searchRecursive(node.left, value); + } else { + return searchRecursive(node.right, value); + } + } + + public void delete(int value) { + root = deleteRecursive(root, value); + } + + private Node deleteRecursive(Node node, int value) { + if (node == null) { + return null; + } + if (value < node.key) { + node.left = deleteRecursive(node.left, value); + } else if (value > node.key) { + node.right = deleteRecursive(node.right, value); + } else { + if (node.left == null) { + return node.right; + } else if (node.right == null) { + return node.left; + } + Node successor = findMinNode(node.right); + node.key = successor.key; + node.right = deleteRecursive(node.right, successor.key); + } + return node; + } + + public int findMin() { + if (root == null) { + throw new NoSuchElementException("BST is empty"); + } + return findMinNode(root).key; + } + + private Node findMinNode(Node node) { + Node current = node; + while (current.left != null) { + current = current.left; + } + return current; + } + + public int findMax() { + if (root == null) { + throw new NoSuchElementException("BST is empty"); + } + Node current = root; + while (current.right != null) { + current = current.right; + } + return current.key; + } + + public void printInorder() { + System.out.print("Inorder: "); + printInorderRecursive(root); + System.out.println(); + } + + private void printInorderRecursive(Node node) { + if (node == null) return; + printInorderRecursive(node.left); + System.out.print(node.key + " "); + printInorderRecursive(node.right); + } + + public void printPreorder() { + System.out.print("Preorder: "); + printPreorderRecursive(root); + System.out.println(); + } + + private void printPreorderRecursive(Node node) { + if (node == null) return; + System.out.print(node.key + " "); + printPreorderRecursive(node.left); + printPreorderRecursive(node.right); + } + + public void printPostorder() { + System.out.print("Postorder: "); + printPostorderRecursive(root); + System.out.println(); + } + + private void printPostorderRecursive(Node node) { + if (node == null) return; + printPostorderRecursive(node.left); + printPostorderRecursive(node.right); + System.out.print(node.key + " "); + } + + public List inorderList() { + List result = new ArrayList<>(); + inorderToList(root, result); + return result; + } + + private void inorderToList(Node node, List out) { + if (node == null) return; + inorderToList(node.left, out); + out.add(node.key); + inorderToList(node.right, out); + } + + public List preorderList() { + List result = new ArrayList<>(); + preorderToList(root, result); + return result; + } + + private void preorderToList(Node node, List out) { + if (node == null) return; + out.add(node.key); + preorderToList(node.left, out); + preorderToList(node.right, out); + } + + public List postorderList() { + List result = new ArrayList<>(); + postorderToList(root, result); + return result; + } + + private void postorderToList(Node node, List out) { + if (node == null) return; + postorderToList(node.left, out); + postorderToList(node.right, out); + out.add(node.key); + } + + public static void main(String[] args) { + BSTTest bst = new BSTTest(); + + int[] values = {50, 30, 70, 20, 40, 60, 80}; + for (int v : values) { + bst.insert(v); + } + + bst.printInorder(); + bst.printPreorder(); + bst.printPostorder(); + + System.out.println("Inorder List: " + bst.inorderList()); + System.out.println("Preorder List: " + bst.preorderList()); + System.out.println("Postorder List: " + bst.postorderList()); + + System.out.println("Search 40: " + bst.search(40)); + System.out.println("Search 99: " + bst.search(99)); + + System.out.println("Min: " + bst.findMin()); + System.out.println("Max: " + bst.findMax()); + + bst.delete(20); + System.out.println("After deleting 20 (leaf): " + bst.inorderList()); + + bst.delete(30); + System.out.println("After deleting 30 (one child): " + bst.inorderList()); + + bst.delete(50); + System.out.println("After deleting 50 (two children): " + bst.inorderList()); + } +} From f3d7f0e7e4e837370a0abc6b9e8588c5da04af59 Mon Sep 17 00:00:00 2001 From: amarmaurya-com Date: Thu, 30 Oct 2025 19:21:05 +0530 Subject: [PATCH 2/4] Added AVL tree implementation with detailed comments --- src/main/java/com/thealgorithms/tree/AVL.java | 367 ++++++++++++++++++ .../java/com/thealgorithms/tree/AVLTest.java | 245 ++++++++++++ 2 files changed, 612 insertions(+) create mode 100644 src/main/java/com/thealgorithms/tree/AVL.java create mode 100644 src/test/java/com/thealgorithms/tree/AVLTest.java diff --git a/src/main/java/com/thealgorithms/tree/AVL.java b/src/main/java/com/thealgorithms/tree/AVL.java new file mode 100644 index 000000000000..50898dc2aa02 --- /dev/null +++ b/src/main/java/com/thealgorithms/tree/AVL.java @@ -0,0 +1,367 @@ +package com.thealgorithms.tree; + +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; + +/** + * AVL (Adelson-Velsky and Landis) Tree is a self-balancing Binary Search Tree. + * Operations supported: + * - insert, delete, search + * - inorder, preorder, postorder traversal + * - findMin(), findMax() + * + * Properties: + * - For every node: |height(left) - height(right)| <= 1 + * - Maintains O(log n) time complexity for insert/delete/search + */ +public class AVL { + + /** + * Inner class to represent a node in AVL Tree + */ + private static class Node { + int key; + int height; + Node left; + Node right; + + Node(int key) { + this.key = key; + this.height = 1; // New node starts as a leaf node with height = 1 + } + } + + // Root node of the AVL Tree + private Node root; + + // Constructor + public AVL() { + root = null; + } + + /* ======================== PUBLIC METHODS ======================== */ + + /** Insert a key into the AVL Tree */ + public void insert(int key) { + root = insertRecursive(root, key); + } + + /** Delete a key from the AVL Tree */ + public void delete(int key) { + root = deleteRecursive(root, key); + } + + /** Search a key in the AVL Tree */ + public boolean search(int key) { + return searchRecursive(root, key); + } + + /** Return the smallest key in the AVL Tree */ + public int findMin() { + if (root == null) throw new NoSuchElementException("AVL Tree is empty"); + return findMinNode(root).key; + } + + /** Return the largest key in the AVL Tree */ + public int findMax() { + if (root == null) throw new NoSuchElementException("AVL Tree is empty"); + Node cur = root; + while (cur.right != null) cur = cur.right; + return cur.key; + } + + /** Print nodes in Inorder (sorted order) */ + public void printInorder() { + System.out.print("Inorder: "); + printInorderRecursive(root); + System.out.println(); + } + + /** Print nodes in Preorder (Root → Left → Right) */ + public void printPreorder() { + System.out.print("Preorder: "); + printPreorderRecursive(root); + System.out.println(); + } + + /** Print nodes in Postorder (Left → Right → Root) */ + public void printPostorder() { + System.out.print("Postorder: "); + printPostorderRecursive(root); + System.out.println(); + } + + /** Return Inorder list (useful for testing) */ + public List inorderList() { + List res = new ArrayList<>(); + inorderToList(root, res); + return res; + } + + /** Return Preorder list (useful for testing) */ + public List preorderList() { + List res = new ArrayList<>(); + preorderToList(root, res); + return res; + } + + /** Return Postorder list (useful for testing) */ + public List postorderList() { + List res = new ArrayList<>(); + postorderToList(root, res); + return res; + } + + + /** + * Recursive insert: + * 1. Insert key like a normal BST + * 2. Update height of current node + * 3. Balance the node if it became unbalanced + */ + private Node insertRecursive(Node node, int key) { + // Step 1: Perform standard BST insert + if (node == null) return new Node(key); + + if (key < node.key) + node.left = insertRecursive(node.left, key); + else if (key > node.key) + node.right = insertRecursive(node.right, key); + else + return node; // Duplicates not allowed + + // Step 2: Update height of ancestor node + updateHeight(node); + + // Step 3: Balance the node and return new root + return balanceNode(node); + } + + /** + * Recursive delete: + * 1. Perform normal BST delete + * 2. Update height of current node + * 3. Balance it if necessary + */ + private Node deleteRecursive(Node node, int key) { + if (node == null) return null; + + // Step 1: Perform BST delete + if (key < node.key) + node.left = deleteRecursive(node.left, key); + else if (key > node.key) + node.right = deleteRecursive(node.right, key); + else { + // Node found + if (node.left == null || node.right == null) { + Node temp = (node.left != null) ? node.left : node.right; + + // No child case + if (temp == null) { + node = null; + } else { + node = temp; + } + } else { + // Node with two children → get inorder successor + Node successor = findMinNode(node.right); + node.key = successor.key; + node.right = deleteRecursive(node.right, successor.key); + } + } + + // If tree had only one node + if (node == null) return null; + + // Step 2: Update height + updateHeight(node); + + // Step 3: Rebalance node + return balanceNode(node); + } + + /** Recursive search like normal BST */ + private boolean searchRecursive(Node node, int key) { + if (node == null) return false; + if (key == node.key) return true; + return key < node.key ? searchRecursive(node.left, key) : searchRecursive(node.right, key); + } + + /** Find node with minimum key */ + private Node findMinNode(Node node) { + Node cur = node; + while (cur.left != null) cur = cur.left; + return cur; + } + + /* ======================== ROTATIONS & BALANCING ======================== */ + + /** Right rotation (used in LL or LR imbalance) */ + private Node rightRotate(Node y) { + Node x = y.left; + Node T2 = x.right; + + // Perform rotation + x.right = y; + y.left = T2; + + // Update heights + updateHeight(y); + updateHeight(x); + + return x; // New root + } + + /** Left rotation (used in RR or RL imbalance) */ + private Node leftRotate(Node x) { + Node y = x.right; + Node T2 = y.left; + + // Perform rotation + y.left = x; + x.right = T2; + + // Update heights + updateHeight(x); + updateHeight(y); + + return y; // New root + } + + /** + * Balances a node by checking its balance factor: + * + * - If > 1 → left heavy + * - If < -1 → right heavy + * + * Depending on the case, we do: + * - LL → Right Rotate + * - RR → Left Rotate + * - LR → Left Rotate child + Right Rotate + * - RL → Right Rotate child + Left Rotate + */ + private Node balanceNode(Node node) { + int balance = getBalance(node); + + // Case 1: Left Left (LL) + if (balance > 1 && getBalance(node.left) >= 0) + return rightRotate(node); + + // Case 2: Left Right (LR) + if (balance > 1 && getBalance(node.left) < 0) { + node.left = leftRotate(node.left); + return rightRotate(node); + } + + // Case 3: Right Right (RR) + if (balance < -1 && getBalance(node.right) <= 0) + return leftRotate(node); + + // Case 4: Right Left (RL) + if (balance < -1 && getBalance(node.right) > 0) { + node.right = rightRotate(node.right); + return leftRotate(node); + } + + return node; // Already balanced + } + + /* ======================== HELPER FUNCTIONS ======================== */ + + /** Returns height of a node */ + private int height(Node node) { + return node == null ? 0 : node.height; + } + + /** Updates height of a node based on its children */ + private void updateHeight(Node node) { + node.height = 1 + Math.max(height(node.left), height(node.right)); + } + + /** Calculates balance factor = height(left) - height(right) */ + private int getBalance(Node node) { + return node == null ? 0 : height(node.left) - height(node.right); + } + + /* ======================== TRAVERSALS ======================== */ + + private void printInorderRecursive(Node node) { + if (node == null) return; + printInorderRecursive(node.left); + System.out.print(node.key + " "); + printInorderRecursive(node.right); + } + + private void printPreorderRecursive(Node node) { + if (node == null) return; + System.out.print(node.key + " "); + printPreorderRecursive(node.left); + printPreorderRecursive(node.right); + } + + private void printPostorderRecursive(Node node) { + if (node == null) return; + printPostorderRecursive(node.left); + printPostorderRecursive(node.right); + System.out.print(node.key + " "); + } + + private void inorderToList(Node node, List out) { + if (node == null) return; + inorderToList(node.left, out); + out.add(node.key); + inorderToList(node.right, out); + } + + private void preorderToList(Node node, List out) { + if (node == null) return; + out.add(node.key); + preorderToList(node.left, out); + preorderToList(node.right, out); + } + + private void postorderToList(Node node, List out) { + if (node == null) return; + postorderToList(node.left, out); + postorderToList(node.right, out); + out.add(node.key); + } + + public static void main(String[] args) { + AVL avl = new AVL(); + + int[] values = {30, 20, 40, 10, 25, 35, 50, 5, 15, 27, 45, 60}; + + // Insert all values one by one + for (int v : values) avl.insert(v); + + // Display traversals + avl.printInorder(); // should show sorted order + avl.printPreorder(); + avl.printPostorder(); + + // Display traversal lists + System.out.println("Inorder List: " + avl.inorderList()); + System.out.println("Preorder List: " + avl.preorderList()); + System.out.println("Postorder List: " + avl.postorderList()); + + // Search examples + System.out.println("Search 27: " + avl.search(27)); // true + System.out.println("Search 99: " + avl.search(99)); // false + + // Min and Max + System.out.println("Min: " + avl.findMin()); + System.out.println("Max: " + avl.findMax()); + + // Delete operations and show tree after each + avl.delete(10); + System.out.println("After deleting 10: " + avl.inorderList()); + + avl.delete(30); + System.out.println("After deleting 30: " + avl.inorderList()); + + avl.delete(40); + System.out.println("After deleting 40: " + avl.inorderList()); + } +} diff --git a/src/test/java/com/thealgorithms/tree/AVLTest.java b/src/test/java/com/thealgorithms/tree/AVLTest.java new file mode 100644 index 000000000000..5ef0a7acb825 --- /dev/null +++ b/src/test/java/com/thealgorithms/tree/AVLTest.java @@ -0,0 +1,245 @@ +package com.thealgorithms.tree; + +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; + +public class AVLTest { + + private static class Node { + int key; + int height; + Node left, right; + + Node(int key) { + this.key = key; + this.height = 1; // new node is initially added at leaf + this.left = this.right = null; + } + } + + private Node root; + + public AVLTest() { + root = null; + } + + public void insert(int key) { + root = insertRecursive(root, key); + } + + public void delete(int key) { + root = deleteRecursive(root, key); + } + + public boolean search(int key) { + return searchRecursive(root, key); + } + + public int findMin() { + if (root == null) throw new NoSuchElementException("AVL is empty"); + return findMinNode(root).key; + } + + public int findMax() { + if (root == null) throw new NoSuchElementException("AVL is empty"); + Node cur = root; + while (cur.right != null) cur = cur.right; + return cur.key; + } + + public void printInorder() { + System.out.print("Inorder: "); + printInorderRecursive(root); + System.out.println(); + } + + public void printPreorder() { + System.out.print("Preorder: "); + printPreorderRecursive(root); + System.out.println(); + } + + public void printPostorder() { + System.out.print("Postorder: "); + printPostorderRecursive(root); + System.out.println(); + } + + public List inorderList() { + List res = new ArrayList<>(); + inorderToList(root, res); + return res; + } + + public List preorderList() { + List res = new ArrayList<>(); + preorderToList(root, res); + return res; + } + + public List postorderList() { + List res = new ArrayList<>(); + postorderToList(root, res); + return res; + } + + /* Recursive helpers */ + + private Node insertRecursive(Node node, int key) { + if (node == null) return new Node(key); + + if (key < node.key) node.left = insertRecursive(node.left, key); + else if (key > node.key) node.right = insertRecursive(node.right, key); + else return node; // duplicates ignored + + updateHeight(node); + return balanceNode(node); + } + + private Node deleteRecursive(Node node, int key) { + if (node == null) return null; + + if (key < node.key) node.left = deleteRecursive(node.left, key); + else if (key > node.key) node.right = deleteRecursive(node.right, key); + else { + if (node.left == null || node.right == null) { + Node temp = (node.left != null) ? node.left : node.right; + if (temp == null) { + node = null; + } else { + node = temp; + } + } else { + Node successor = findMinNode(node.right); + node.key = successor.key; + node.right = deleteRecursive(node.right, successor.key); + } + } + + if (node == null) return null; + + updateHeight(node); + return balanceNode(node); + } + + private boolean searchRecursive(Node node, int key) { + if (node == null) return false; + if (key == node.key) return true; + return key < node.key ? searchRecursive(node.left, key) : searchRecursive(node.right, key); + } + + private Node findMinNode(Node node) { + Node cur = node; + while (cur.left != null) cur = cur.left; + return cur; + } + + /* Rotations & Balancing */ + + private Node rightRotate(Node y) { + Node x = y.left; + Node T2 = x.right; + + x.right = y; + y.left = T2; + + updateHeight(y); + updateHeight(x); + + return x; + } + + private Node leftRotate(Node x) { + Node y = x.right; + Node T2 = y.left; + + y.left = x; + x.right = T2; + + updateHeight(x); + updateHeight(y); + + return y; + } + + private Node balanceNode(Node node) { + int balance = getBalance(node); + + if (balance > 1 && getBalance(node.left) >= 0) { + return rightRotate(node); // LL + } + + if (balance > 1 && getBalance(node.left) < 0) { + node.left = leftRotate(node.left); // LR: left then right + return rightRotate(node); + } + + if (balance < -1 && getBalance(node.right) <= 0) { + return leftRotate(node); // RR + } + + if (balance < -1 && getBalance(node.right) > 0) { + node.right = rightRotate(node.right); // RL: right then left + return leftRotate(node); + } + + return node; + } + + private int height(Node node) { + return node == null ? 0 : node.height; + } + + private void updateHeight(Node node) { + node.height = 1 + Math.max(height(node.left), height(node.right)); + } + + private int getBalance(Node node) { + return node == null ? 0 : height(node.left) - height(node.right); + } + + /* ============ Traversal helpers ============ */ + + private void printInorderRecursive(Node node) { + if (node == null) return; + printInorderRecursive(node.left); + System.out.print(node.key + " "); + printInorderRecursive(node.right); + } + + private void printPreorderRecursive(Node node) { + if (node == null) return; + System.out.print(node.key + " "); + printPreorderRecursive(node.left); + printPreorderRecursive(node.right); + } + + private void printPostorderRecursive(Node node) { + if (node == null) return; + printPostorderRecursive(node.left); + printPostorderRecursive(node.right); + System.out.print(node.key + " "); + } + + private void inorderToList(Node node, List out) { + if (node == null) return; + inorderToList(node.left, out); + out.add(node.key); + inorderToList(node.right, out); + } + + private void preorderToList(Node node, List out) { + if (node == null) return; + out.add(node.key); + preorderToList(node.left, out); + preorderToList(node.right, out); + } + + private void postorderToList(Node node, List out) { + if (node == null) return; + postorderToList(node.left, out); + postorderToList(node.right, out); + out.add(node.key); + } +} From d0024b701ca6f4934af11354c0c384d078bf9f77 Mon Sep 17 00:00:00 2001 From: amarmaurya-com Date: Thu, 30 Oct 2025 21:17:06 +0530 Subject: [PATCH 3/4] Added AVL tree implementation with detailed comments --- src/main/java/com/thealgorithms/tree/AVL.java | 38 +++-- src/main/java/com/thealgorithms/tree/BST.java | 74 +++++++-- .../java/com/thealgorithms/tree/AVLTest.java | 24 ++- .../java/com/thealgorithms/tree/BSTTest.java | 147 +++++++++++++++--- 4 files changed, 227 insertions(+), 56 deletions(-) diff --git a/src/main/java/com/thealgorithms/tree/AVL.java b/src/main/java/com/thealgorithms/tree/AVL.java index 50898dc2aa02..b16210c28152 100644 --- a/src/main/java/com/thealgorithms/tree/AVL.java +++ b/src/main/java/com/thealgorithms/tree/AVL.java @@ -122,7 +122,9 @@ public List postorderList() { */ private Node insertRecursive(Node node, int key) { // Step 1: Perform standard BST insert - if (node == null) return new Node(key); + if (node == null) { + return new Node(key); + } if (key < node.key) node.left = insertRecursive(node.left, key); @@ -245,8 +247,8 @@ private Node balanceNode(Node node) { int balance = getBalance(node); // Case 1: Left Left (LL) - if (balance > 1 && getBalance(node.left) >= 0) - return rightRotate(node); + if (balance > 1 && getBalance(node.left) >= 0) return rightRotate(node); + // Case 2: Left Right (LR) if (balance > 1 && getBalance(node.left) < 0) { @@ -255,8 +257,8 @@ private Node balanceNode(Node node) { } // Case 3: Right Right (RR) - if (balance < -1 && getBalance(node.right) <= 0) - return leftRotate(node); + if (balance < -1 && getBalance(node.right) <= 0) return leftRotate(node); + // Case 4: Right Left (RL) if (balance < -1 && getBalance(node.right) > 0) { @@ -287,42 +289,54 @@ private int getBalance(Node node) { /* ======================== TRAVERSALS ======================== */ private void printInorderRecursive(Node node) { - if (node == null) return; + if (node == null) { + return; + } printInorderRecursive(node.left); System.out.print(node.key + " "); printInorderRecursive(node.right); } private void printPreorderRecursive(Node node) { - if (node == null) return; + if (node == null) { + return; + } System.out.print(node.key + " "); printPreorderRecursive(node.left); printPreorderRecursive(node.right); } private void printPostorderRecursive(Node node) { - if (node == null) return; + if (node == null) { + return; + } printPostorderRecursive(node.left); printPostorderRecursive(node.right); System.out.print(node.key + " "); } private void inorderToList(Node node, List out) { - if (node == null) return; + if (node == null) { + return; + } inorderToList(node.left, out); out.add(node.key); inorderToList(node.right, out); } private void preorderToList(Node node, List out) { - if (node == null) return; + if (node == null) { + return; + } out.add(node.key); preorderToList(node.left, out); preorderToList(node.right, out); } private void postorderToList(Node node, List out) { - if (node == null) return; + if (node == null) { + return; + } postorderToList(node.left, out); postorderToList(node.right, out); out.add(node.key); @@ -337,7 +351,7 @@ public static void main(String[] args) { for (int v : values) avl.insert(v); // Display traversals - avl.printInorder(); // should show sorted order + avl.printInorder(); // should show sorted order avl.printPreorder(); avl.printPostorder(); diff --git a/src/main/java/com/thealgorithms/tree/BST.java b/src/main/java/com/thealgorithms/tree/BST.java index b8c4b96b4cbd..bdfe23b3d0c3 100644 --- a/src/main/java/com/thealgorithms/tree/BST.java +++ b/src/main/java/com/thealgorithms/tree/BST.java @@ -27,7 +27,7 @@ private static class Node { // Root of the BST // the first of Node tree - //0-> + // 0-> private Node root; /** Create an empty BST. */ @@ -196,10 +196,12 @@ public void printInorder() { } private void printInorderRecursive(Node node) { - if (node == null) return; - printInorderRecursive(node.left); // left - System.out.print(node.key + " "); // node - printInorderRecursive(node.right); // right + if (node == null) { + return; + } + printInorderRecursive(node.left); // left + System.out.print(node.key + " "); // node + printInorderRecursive(node.right); // right } /** @@ -213,10 +215,12 @@ public void printPreorder() { } private void printPreorderRecursive(Node node) { - if (node == null) return; - System.out.print(node.key + " "); // node - printPreorderRecursive(node.left); // left - printPreorderRecursive(node.right); // right + if (node == null) { + return; + } + System.out.print(node.key + " "); // node + printPreorderRecursive(node.left); // left + printPreorderRecursive(node.right); // right } /** @@ -230,20 +234,24 @@ public void printPostorder() { } private void printPostorderRecursive(Node node) { - if (node == null) return; - printPostorderRecursive(node.left); // left - printPostorderRecursive(node.right); // right - System.out.print(node.key + " "); // node + if (node == null) { + return; + } + printPostorderRecursive(node.left); // left + printPostorderRecursive(node.right); // right + System.out.print(node.key + " "); // node } - public List inorderList() { + public List inorderList() { List result = new ArrayList<>(); inorderToList(root, result); return result; } private void inorderToList(Node node, List out) { - if (node == null) return; + if (node == null) { + return; + } inorderToList(node.left, out); out.add(node.key); inorderToList(node.right, out); @@ -275,4 +283,40 @@ private void postorderToList(Node node, List out) { postorderToList(node.right, out); out.add(node.key); } + + public static void main(String[] args) { + BST bst = new BST(); + + // Insert values + int[] values = {50, 30, 70, 20, 40, 60, 80}; + for (int v : values) { + bst.insert(v); + } + + bst.printInorder(); + bst.printPreorder(); + bst.printPostorder(); + + System.out.println("Inorder List: " + bst.inorderList()); + System.out.println("Preorder List: " + bst.preorderList()); + System.out.println("Postorder List: " + bst.postorderList()); + + + System.out.println("Search 40: " + bst.search(40)); // true + System.out.println("Search 99: " + bst.search(99)); // false + + + System.out.println("Min: " + bst.findMin()); // 20 + System.out.println("Max: " + bst.findMax()); // 80 + + + bst.delete(20); + System.out.println("After deleting 20 (leaf): " + bst.inorderList()); + + bst.delete(30); + System.out.println("After deleting 30 (one child): " + bst.inorderList()); + + bst.delete(50); + System.out.println("After deleting 50 (two children): " + bst.inorderList()); + } } diff --git a/src/test/java/com/thealgorithms/tree/AVLTest.java b/src/test/java/com/thealgorithms/tree/AVLTest.java index 5ef0a7acb825..514945b999d2 100644 --- a/src/test/java/com/thealgorithms/tree/AVLTest.java +++ b/src/test/java/com/thealgorithms/tree/AVLTest.java @@ -89,19 +89,31 @@ public List postorderList() { private Node insertRecursive(Node node, int key) { if (node == null) return new Node(key); - if (key < node.key) node.left = insertRecursive(node.left, key); - else if (key > node.key) node.right = insertRecursive(node.right, key); - else return node; // duplicates ignored + if (key < node.key) { + node.left = insertRecursive(node.left, key); + } + else if (key > node.key) { + node.right = insertRecursive(node.right, key); + } + else { + return node; // duplicates ignored + } updateHeight(node); return balanceNode(node); } private Node deleteRecursive(Node node, int key) { - if (node == null) return null; + if (node == null) { + return null; + } - if (key < node.key) node.left = deleteRecursive(node.left, key); - else if (key > node.key) node.right = deleteRecursive(node.right, key); + if (key < node.key) { + node.left = deleteRecursive(node.left, key); + } + else if (key > node.key) { + node.right = deleteRecursive(node.right, key); + } else { if (node.left == null || node.right == null) { Node temp = (node.left != null) ? node.left : node.right; diff --git a/src/test/java/com/thealgorithms/tree/BSTTest.java b/src/test/java/com/thealgorithms/tree/BSTTest.java index cff3ab6aec81..8a460487a087 100644 --- a/src/test/java/com/thealgorithms/tree/BSTTest.java +++ b/src/test/java/com/thealgorithms/tree/BSTTest.java @@ -6,6 +6,15 @@ public class BSTTest { + /** + * Node class represents a node in the BST. + * 0->0->0 + * 0=Nodes\ + * each node contains divided into 3 section + * Key-> Actual value, + * left-> store the address of left tree, + * Right-> store the address of right tree + */ private static class Node { int key; Node left, right; @@ -16,70 +25,128 @@ private static class Node { } } + // Root of the BST + // the first of Node tree + //0-> private Node root; + /** Create an empty BST. */ public BSTTest() { root = null; } + /* =========================== + * INSERT + * =========================== */ + + /** + * Insert a value into the BST. Duplicate values are ignored (no-op). + * + * @param value value to insert + */ public void insert(int value) { root = insertRecursive(root, value); } + // Helper recursive method for insertion. private Node insertRecursive(Node node, int value) { + // If we reached a null position, create and return a new node. if (node == null) { return new Node(value); } + + // If value is less, go left; if greater, go right; if equal, do nothing. if (value < node.key) { node.left = insertRecursive(node.left, value); } else if (value > node.key) { node.right = insertRecursive(node.right, value); - } - return node; + } // else duplicate -> ignore + + return node; // return current (possibly updated) subtree root } + /* =========================== + * SEARCH + * =========================== */ + + /** + * Search the BST for a value. + * + */ public boolean search(int value) { return searchRecursive(root, value); } private boolean searchRecursive(Node node, int value) { if (node == null) { - return false; + return false; // reached leaf, not found } if (value == node.key) { - return true; + return true; // found exact match } else if (value < node.key) { - return searchRecursive(node.left, value); + return searchRecursive(node.left, value); // search left subtree } else { - return searchRecursive(node.right, value); + return searchRecursive(node.right, value); // search right subtree } } + /* =========================== + * DELETE + * =========================== */ + + /** + * Delete a value from the BST. If the value is not present, tree remains unchanged. + * + * @param value value to delete + */ public void delete(int value) { root = deleteRecursive(root, value); } + // Helper for deletion, handles three cases: + // 1) node is a leaf -> just remove + // 2) node has one child -> replace node with child + // 3) node has two children -> replace node with successor (smallest in right subtree) private Node deleteRecursive(Node node, int value) { if (node == null) { - return null; + return null; // value not found } + if (value < node.key) { + // target is in left subtree node.left = deleteRecursive(node.left, value); } else if (value > node.key) { + // target is in right subtree node.right = deleteRecursive(node.right, value); } else { + // node.key == value -> delete this node + // Case 1 & 2: node has 0 or 1 child if (node.left == null) { + // return right child (could be null) to replace node return node.right; } else if (node.right == null) { + // return left child to replace node return node.left; } + + // Case 3: node has two children + // Find the inorder successor (smallest in the right subtree) Node successor = findMinNode(node.right); + // Copy successor's value to this node node.key = successor.key; + // Delete the successor node from right subtree node.right = deleteRecursive(node.right, successor.key); } + return node; } + /** + * Find the minimum key in the BST. + * + * @return the smallest integer key in the tree + * @throws NoSuchElementException if the tree is empty + */ public int findMin() { if (root == null) { throw new NoSuchElementException("BST is empty"); @@ -87,25 +154,39 @@ public int findMin() { return findMinNode(root).key; } + // Helper to find node with minimum key in a subtree (leftmost node) private Node findMinNode(Node node) { Node current = node; + // go as far left as possible while (current.left != null) { current = current.left; } return current; } + /** + * Find the maximum key in the BST. + * + * the largest integer key in the tree + * NoSuchElementException if the tree is empty + */ public int findMax() { if (root == null) { throw new NoSuchElementException("BST is empty"); } Node current = root; + // go as far right as possible while (current.right != null) { current = current.right; } return current.key; } + + /** + * Print inorder traversal (Left, Node, Right). + * InOrder -> Left, key, Right + */ public void printInorder() { System.out.print("Inorder: "); printInorderRecursive(root); @@ -113,12 +194,18 @@ public void printInorder() { } private void printInorderRecursive(Node node) { - if (node == null) return; - printInorderRecursive(node.left); - System.out.print(node.key + " "); - printInorderRecursive(node.right); + if (node == null) { + return; + } + printInorderRecursive(node.left); // left + System.out.print(node.key + " "); // node + printInorderRecursive(node.right); // right } + /** + * Print preorder traversal (Node, Left, Right). + * PreOrder -> key,Left, Right + */ public void printPreorder() { System.out.print("Preorder: "); printPreorderRecursive(root); @@ -126,12 +213,18 @@ public void printPreorder() { } private void printPreorderRecursive(Node node) { - if (node == null) return; - System.out.print(node.key + " "); - printPreorderRecursive(node.left); - printPreorderRecursive(node.right); + if (node == null) { + return; + } + System.out.print(node.key + " "); // node + printPreorderRecursive(node.left); // left + printPreorderRecursive(node.right); // right } + /** + * Print postorder traversal (Left, Right, Node). + *PreOrder -> key,Left, Right + */ public void printPostorder() { System.out.print("Postorder: "); printPostorderRecursive(root); @@ -139,10 +232,12 @@ public void printPostorder() { } private void printPostorderRecursive(Node node) { - if (node == null) return; - printPostorderRecursive(node.left); - printPostorderRecursive(node.right); - System.out.print(node.key + " "); + if (node == null) { + return; + } + printPostorderRecursive(node.left); // left + printPostorderRecursive(node.right); // right + System.out.print(node.key + " "); // node } public List inorderList() { @@ -152,12 +247,15 @@ public List inorderList() { } private void inorderToList(Node node, List out) { - if (node == null) return; + if (node == null) { + return; + } inorderToList(node.left, out); out.add(node.key); inorderToList(node.right, out); } + public List preorderList() { List result = new ArrayList<>(); preorderToList(root, result); @@ -165,7 +263,9 @@ public List preorderList() { } private void preorderToList(Node node, List out) { - if (node == null) return; + if (node == null) { + return; + } out.add(node.key); preorderToList(node.left, out); preorderToList(node.right, out); @@ -178,12 +278,13 @@ public List postorderList() { } private void postorderToList(Node node, List out) { - if (node == null) return; + if (node == null) { + return; + } postorderToList(node.left, out); postorderToList(node.right, out); out.add(node.key); } - public static void main(String[] args) { BSTTest bst = new BSTTest(); From 406ca5e310e100f55470f2ede2b10bd8c68138a0 Mon Sep 17 00:00:00 2001 From: amarmaurya-com Date: Thu, 30 Oct 2025 21:52:28 +0530 Subject: [PATCH 4/4] Added AVL tree implementation with detailed comments --- src/main/java/com/thealgorithms/tree/AVL.java | 3 --- src/main/java/com/thealgorithms/tree/BST.java | 7 +----- .../java/com/thealgorithms/tree/AVLTest.java | 12 ++++------ .../java/com/thealgorithms/tree/BSTTest.java | 22 +++++++++---------- 4 files changed, 15 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/thealgorithms/tree/AVL.java b/src/main/java/com/thealgorithms/tree/AVL.java index b16210c28152..73cc5ccb4d9f 100644 --- a/src/main/java/com/thealgorithms/tree/AVL.java +++ b/src/main/java/com/thealgorithms/tree/AVL.java @@ -113,7 +113,6 @@ public List postorderList() { return res; } - /** * Recursive insert: * 1. Insert key like a normal BST @@ -249,7 +248,6 @@ private Node balanceNode(Node node) { // Case 1: Left Left (LL) if (balance > 1 && getBalance(node.left) >= 0) return rightRotate(node); - // Case 2: Left Right (LR) if (balance > 1 && getBalance(node.left) < 0) { node.left = leftRotate(node.left); @@ -259,7 +257,6 @@ private Node balanceNode(Node node) { // Case 3: Right Right (RR) if (balance < -1 && getBalance(node.right) <= 0) return leftRotate(node); - // Case 4: Right Left (RL) if (balance < -1 && getBalance(node.right) > 0) { node.right = rightRotate(node.right); diff --git a/src/main/java/com/thealgorithms/tree/BST.java b/src/main/java/com/thealgorithms/tree/BST.java index bdfe23b3d0c3..b42d4b49b182 100644 --- a/src/main/java/com/thealgorithms/tree/BST.java +++ b/src/main/java/com/thealgorithms/tree/BST.java @@ -184,7 +184,6 @@ public int findMax() { return current.key; } - /** * Print inorder traversal (Left, Node, Right). * InOrder -> Left, key, Right @@ -242,7 +241,7 @@ private void printPostorderRecursive(Node node) { System.out.print(node.key + " "); // node } - public List inorderList() { + public List inorderList() { List result = new ArrayList<>(); inorderToList(root, result); return result; @@ -257,7 +256,6 @@ private void inorderToList(Node node, List out) { inorderToList(node.right, out); } - public List preorderList() { List result = new ArrayList<>(); preorderToList(root, result); @@ -301,15 +299,12 @@ public static void main(String[] args) { System.out.println("Preorder List: " + bst.preorderList()); System.out.println("Postorder List: " + bst.postorderList()); - System.out.println("Search 40: " + bst.search(40)); // true System.out.println("Search 99: " + bst.search(99)); // false - System.out.println("Min: " + bst.findMin()); // 20 System.out.println("Max: " + bst.findMax()); // 80 - bst.delete(20); System.out.println("After deleting 20 (leaf): " + bst.inorderList()); diff --git a/src/test/java/com/thealgorithms/tree/AVLTest.java b/src/test/java/com/thealgorithms/tree/AVLTest.java index 514945b999d2..e53a710514f5 100644 --- a/src/test/java/com/thealgorithms/tree/AVLTest.java +++ b/src/test/java/com/thealgorithms/tree/AVLTest.java @@ -91,11 +91,9 @@ private Node insertRecursive(Node node, int key) { if (key < node.key) { node.left = insertRecursive(node.left, key); - } - else if (key > node.key) { + } else if (key > node.key) { node.right = insertRecursive(node.right, key); - } - else { + } else { return node; // duplicates ignored } @@ -110,11 +108,9 @@ private Node deleteRecursive(Node node, int key) { if (key < node.key) { node.left = deleteRecursive(node.left, key); - } - else if (key > node.key) { + } else if (key > node.key) { node.right = deleteRecursive(node.right, key); - } - else { + } else { if (node.left == null || node.right == null) { Node temp = (node.left != null) ? node.left : node.right; if (temp == null) { diff --git a/src/test/java/com/thealgorithms/tree/BSTTest.java b/src/test/java/com/thealgorithms/tree/BSTTest.java index 8a460487a087..c5af9cd16c74 100644 --- a/src/test/java/com/thealgorithms/tree/BSTTest.java +++ b/src/test/java/com/thealgorithms/tree/BSTTest.java @@ -27,7 +27,7 @@ private static class Node { // Root of the BST // the first of Node tree - //0-> + // 0-> private Node root; /** Create an empty BST. */ @@ -182,7 +182,6 @@ public int findMax() { return current.key; } - /** * Print inorder traversal (Left, Node, Right). * InOrder -> Left, key, Right @@ -197,9 +196,9 @@ private void printInorderRecursive(Node node) { if (node == null) { return; } - printInorderRecursive(node.left); // left - System.out.print(node.key + " "); // node - printInorderRecursive(node.right); // right + printInorderRecursive(node.left); // left + System.out.print(node.key + " "); // node + printInorderRecursive(node.right); // right } /** @@ -216,9 +215,9 @@ private void printPreorderRecursive(Node node) { if (node == null) { return; } - System.out.print(node.key + " "); // node - printPreorderRecursive(node.left); // left - printPreorderRecursive(node.right); // right + System.out.print(node.key + " "); // node + printPreorderRecursive(node.left); // left + printPreorderRecursive(node.right); // right } /** @@ -235,9 +234,9 @@ private void printPostorderRecursive(Node node) { if (node == null) { return; } - printPostorderRecursive(node.left); // left - printPostorderRecursive(node.right); // right - System.out.print(node.key + " "); // node + printPostorderRecursive(node.left); // left + printPostorderRecursive(node.right); // right + System.out.print(node.key + " "); // node } public List inorderList() { @@ -255,7 +254,6 @@ private void inorderToList(Node node, List out) { inorderToList(node.right, out); } - public List preorderList() { List result = new ArrayList<>(); preorderToList(root, result);