Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
316 changes: 95 additions & 221 deletions src/main/java/com/thealgorithms/datastructures/trees/AVLTree.java
Original file line number Diff line number Diff line change
@@ -1,269 +1,143 @@
package com.thealgorithms.datastructures.trees;

import java.util.ArrayList;
import java.util.List;

/**
* Represents an AVL Tree, a self-balancing binary search tree.
* In an AVL tree, the heights of the two child subtrees of any node
* differ by at most one. If they differ by more than one at any time,
* rebalancing is performed to restore this property.
* AVL Tree (Adelson-Velsky and Landis Tree) implementation.
* A self-balancing Binary Search Tree where the difference between heights
* of left and right subtrees cannot be more than one for all nodes.
*
* @author Raghu0703
*/
public class AVLTree {

private Node root;

private static class Node {
private int key;
private int balance;
private int height;
private Node left;
private Node right;
private Node parent;
public final class AVLTree {
static class Node {
int data;
int height;
Node left;
Node right;

Node(int k, Node p) {
key = k;
parent = p;
}

public Integer getBalance() {
return balance;
Node(int data) {
this.data = data;
this.height = 1;
this.left = null;
this.right = null;
}
}

/**
* Inserts a new key into the AVL tree.
*
* @param key the key to be inserted
* @return {@code true} if the key was inserted, {@code false} if the key already exists
*/
public boolean insert(int key) {
if (root == null) {
root = new Node(key, null);
} else {
Node n = root;
Node parent;
while (true) {
if (n.key == key) {
return false;
}

parent = n;
boolean goLeft = n.key > key;
n = goLeft ? n.left : n.right;
private Node root;

if (n == null) {
if (goLeft) {
parent.left = new Node(key, parent);
} else {
parent.right = new Node(key, parent);
}
rebalance(parent);
break;
}
}
}
return true;
public AVLTree() {
this.root = null;
}

/**
* Deletes a key from the AVL tree.
*
* @param delKey the key to be deleted
*/
public void delete(int delKey) {
if (root == null) {
return;
}

// Find the node to be deleted
Node node = root;
Node child = root;
while (child != null) {
node = child;
child = delKey >= node.key ? node.right : node.left;
if (delKey == node.key) {
delete(node);
return;
}
}
private int height(Node node) {
return node == null ? 0 : node.height;
}

private void delete(Node node) {
if (node.left == null && node.right == null) {
// Leaf node
if (node.parent == null) {
root = null;
} else {
Node parent = node.parent;
if (parent.left == node) {
parent.left = null;
} else {
parent.right = null;
}
rebalance(parent);
}
return;
}

// Node has one or two children
Node child;
if (node.left != null) {
child = node.left;
while (child.right != null) {
child = child.right;
}
} else {
child = node.right;
while (child.left != null) {
child = child.left;
}
}
node.key = child.key;
delete(child);
private int getBalance(Node node) {
return node == null ? 0 : height(node.left) - height(node.right);
}

/**
* Returns a list of balance factors for each node in the tree.
*
* @return a list of integers representing the balance factors of the nodes
*/
public List<Integer> returnBalance() {
List<Integer> balances = new ArrayList<>();
returnBalance(root, balances);
return balances;
private void updateHeight(Node node) {
node.height = Math.max(height(node.left), height(node.right)) + 1;
}

private void returnBalance(Node n, List<Integer> balances) {
if (n != null) {
returnBalance(n.left, balances);
balances.add(n.getBalance());
returnBalance(n.right, balances);
}
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;
}

/**
* Searches for a key in the AVL tree.
*
* @param key the key to be searched
* @return true if the key is found, false otherwise
*/
public boolean search(int key) {
Node result = searchHelper(this.root, key);
return result != null;
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 searchHelper(Node root, int key) {
if (root == null || root.key == key) {
return root;
}

if (root.key > key) {
return searchHelper(root.left, key);
}
return searchHelper(root.right, key);
public void insert(int value) {
root = insertRec(root, value);
}

private void rebalance(Node n) {
setBalance(n);
if (n.balance == -2) {
if (height(n.left.left) >= height(n.left.right)) {
n = rotateRight(n);
} else {
n = rotateLeftThenRight(n);
}
} else if (n.balance == 2) {
if (height(n.right.right) >= height(n.right.left)) {
n = rotateLeft(n);
} else {
n = rotateRightThenLeft(n);
}
private Node insertRec(Node node, int value) {
if (node == null) {
return new Node(value);
}

if (n.parent != null) {
rebalance(n.parent);
if (value < node.data) {
node.left = insertRec(node.left, value);
} else if (value > node.data) {
node.right = insertRec(node.right, value);
} else {
root = n;
return node;
}
}

private Node rotateLeft(Node a) {
Node b = a.right;
b.parent = a.parent;

a.right = b.left;

if (a.right != null) {
a.right.parent = a;
updateHeight(node);
int balance = getBalance(node);
if (balance > 1 && value < node.left.data) {
return rightRotate(node);
}

b.left = a;
a.parent = b;

if (b.parent != null) {
if (b.parent.right == a) {
b.parent.right = b;
} else {
b.parent.left = b;
}
if (balance < -1 && value > node.right.data) {
return leftRotate(node);
}

setBalance(a, b);
return b;
if (balance > 1 && value > node.left.data) {
node.left = leftRotate(node.left);
return rightRotate(node);
}
if (balance < -1 && value < node.right.data) {
node.right = rightRotate(node.right);
return leftRotate(node);
}
return node;
}

private Node rotateRight(Node a) {
Node b = a.left;
b.parent = a.parent;

a.left = b.right;
public boolean search(int value) {
return searchRec(root, value);
}

if (a.left != null) {
a.left.parent = a;
private boolean searchRec(Node node, int value) {
if (node == null) {
return false;
}

b.right = a;
a.parent = b;

if (b.parent != null) {
if (b.parent.right == a) {
b.parent.right = b;
} else {
b.parent.left = b;
}
if (value == node.data) {
return true;
}
return value < node.data ? searchRec(node.left, value) : searchRec(node.right, value);
}

setBalance(a, b);
return b;
public boolean isEmpty() {
return root == null;
}

private Node rotateLeftThenRight(Node n) {
n.left = rotateLeft(n.left);
return rotateRight(n);
public int getHeight() {
return height(root);
}

private Node rotateRightThenLeft(Node n) {
n.right = rotateRight(n.right);
return rotateLeft(n);
public boolean isBalanced() {
return isBalancedRec(root);
}

private int height(Node n) {
if (n == null) {
return -1;
private boolean isBalancedRec(Node node) {
if (node == null) {
return true;
}
return n.height;
int balance = getBalance(node);
return Math.abs(balance) <= 1 && isBalancedRec(node.left) && isBalancedRec(node.right);
}

private void setBalance(Node... nodes) {
for (Node n : nodes) {
reheight(n);
n.balance = height(n.right) - height(n.left);
}
public String inorder() {
StringBuilder sb = new StringBuilder();
inorderRec(root, sb);
return sb.toString().trim();
}

private void reheight(Node node) {
private void inorderRec(Node node, StringBuilder sb) {
if (node != null) {
node.height = 1 + Math.max(height(node.left), height(node.right));
inorderRec(node.left, sb);
sb.append(node.data).append(" ");
inorderRec(node.right, sb);
}
}
}
Loading
Loading