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..df5641c7801a --- /dev/null +++ b/src/main/java/com/thealgorithms/tree/AVL.java @@ -0,0 +1,295 @@ +package com.thealgorithms.tree; + +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; + +public class AVL { + + private static class Node { + int key; + int height; + Node left; + Node right; + + Node(int key) { + this.key = key; + this.height = 1; + this.left = null; + this.right = null; + } + } + + private Node root; + + public AVL() { + 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 Tree is empty"); + } + return findMinNode(root).key; + } + + 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; + } + + 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; + } + + 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; + } + + 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 = null; + if (node.left != null) { + temp = node.left; + } else { + temp = 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; + } + if (key < node.key) { + return searchRecursive(node.left, key); + } else { + return searchRecursive(node.right, key); + } + } + + private Node findMinNode(Node node) { + Node cur = node; + while (cur.left != null) { + cur = cur.left; + } + return cur; + } + + 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); + } + + if (balance > 1 && getBalance(node.left) < 0) { + node.left = leftRotate(node.left); + return rightRotate(node); + } + + if (balance < -1 && getBalance(node.right) <= 0) { + return leftRotate(node); + } + + if (balance < -1 && getBalance(node.right) > 0) { + node.right = rightRotate(node.right); + return leftRotate(node); + } + + return node; + } + + private int height(Node node) { + if (node == null) { + return 0; + } else { + return node.height; + } + } + + private void updateHeight(Node node) { + node.height = 1 + Math.max(height(node.left), height(node.right)); + } + + private int getBalance(Node node) { + if (node == null) { + return 0; + } else { + return height(node.left) - height(node.right); + } + } + + 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); + } +} 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..43f1c55f5f19 --- /dev/null +++ b/src/main/java/com/thealgorithms/tree/BST.java @@ -0,0 +1,267 @@ +package com.thealgorithms.tree; + +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; + +public class BST { + + private static class Node { + int key; + Node left; + Node right; + + Node(int key) { + this.key = key; + this.left = null; + this.right = null; + } + } + + private Node root; + + public BST() { + this.root = null; + } + + /* =========================== + * INSERT + * =========================== */ + + public void insert(int value) { + this.root = insertRecursive(this.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); + } else { + // duplicate -> ignore + } + + return node; + } + + /* =========================== + * SEARCH + * =========================== */ + + public boolean search(int value) { + return searchRecursive(this.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); + } + } + + /* =========================== + * DELETE + * =========================== */ + + public void delete(int value) { + this.root = deleteRecursive(this.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; + } + + /* =========================== + * MIN/MAX + * =========================== */ + + public int findMin() { + if (this.root == null) { + throw new NoSuchElementException("BST is empty"); + } + return findMinNode(this.root).key; + } + + private Node findMinNode(Node node) { + Node current = node; + while (current.left != null) { + current = current.left; + } + return current; + } + + public int findMax() { + if (this.root == null) { + throw new NoSuchElementException("BST is empty"); + } + Node current = this.root; + while (current.right != null) { + current = current.right; + } + return current.key; + } + + /* =========================== + * TRAVERSALS + * =========================== */ + + public void printInorder() { + System.out.print("Inorder: "); + printInorderRecursive(this.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(this.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(this.root); + System.out.println(); + } + + private void printPostorderRecursive(Node node) { + if (node == null) { + return; + } + printPostorderRecursive(node.left); + printPostorderRecursive(node.right); + System.out.print(node.key + " "); + } + + /* =========================== + * LIST OUTPUT + * =========================== */ + + public List inorderList() { + List result = new ArrayList<>(); + inorderToList(this.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(this.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(this.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); + } + + /* =========================== + * MAIN (TEST) + * =========================== */ + + public static void main(String[] args) { + BST bst = new BST(); + + 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()); + } +} 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..a24a4e031b89 --- /dev/null +++ b/src/test/java/com/thealgorithms/tree/AVLTest.java @@ -0,0 +1,325 @@ +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; + Node right; + + Node(int key) { + this.key = key; + this.height = 1; + this.left = null; + this.right = null; + } + } + + private Node root; + + public AVLTest() { + this.root = null; + } + + public void insert(int key) { + this.root = insertRecursive(this.root, key); + } + + public void delete(int key) { + this.root = deleteRecursive(this.root, key); + } + + public boolean search(int key) { + return searchRecursive(this.root, key); + } + + public int findMin() { + if (this.root == null) { + throw new NoSuchElementException("AVL is empty"); + } + return findMinNode(this.root).key; + } + + public int findMax() { + if (this.root == null) { + throw new NoSuchElementException("AVL is empty"); + } + Node cur = this.root; + while (cur.right != null) { + cur = cur.right; + } + return cur.key; + } + + public void printInorder() { + System.out.print("Inorder: "); + printInorderRecursive(this.root); + System.out.println(); + } + + public void printPreorder() { + System.out.print("Preorder: "); + printPreorderRecursive(this.root); + System.out.println(); + } + + public void printPostorder() { + System.out.print("Postorder: "); + printPostorderRecursive(this.root); + System.out.println(); + } + + public List inorderList() { + List res = new ArrayList<>(); + inorderToList(this.root, res); + return res; + } + + public List preorderList() { + List res = new ArrayList<>(); + preorderToList(this.root, res); + return res; + } + + public List postorderList() { + List res = new ArrayList<>(); + postorderToList(this.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; + } + if (key < node.key) { + return searchRecursive(node.left, key); + } else { + return 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 + 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 + return leftRotate(node); + } + + return node; + } + + private int height(Node node) { + if (node == null) { + return 0; + } + return node.height; + } + + private void updateHeight(Node node) { + node.height = 1 + Math.max(height(node.left), height(node.right)); + } + + private int getBalance(Node node) { + if (node == null) { + return 0; + } + return 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); + } + public static void main(String[] args) { + AVL avl = new AVL(); + + int[] values = {30, 20, 40, 10, 25, 35, 50, 5, 15, 27, 45, 60}; + + for (int v : values) { + avl.insert(v); + } + + avl.printInorder(); + avl.printPreorder(); + avl.printPostorder(); + + System.out.println("Inorder List: " + avl.inorderList()); + System.out.println("Preorder List: " + avl.preorderList()); + System.out.println("Postorder List: " + avl.postorderList()); + + System.out.println("Search 27: " + avl.search(27)); + System.out.println("Search 99: " + avl.search(99)); + + System.out.println("Min: " + avl.findMin()); + System.out.println("Max: " + avl.findMax()); + + 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/BSTTest.java b/src/test/java/com/thealgorithms/tree/BSTTest.java new file mode 100644 index 000000000000..f1570e72c91e --- /dev/null +++ b/src/test/java/com/thealgorithms/tree/BSTTest.java @@ -0,0 +1,239 @@ +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; + Node right; + + Node(int key) { + this.key = key; + this.left = null; + this.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); + } else { + // else duplicate -> ignore + } + + 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; + } else { + 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()); + } +}