Skip to content

Instantly share code, notes, and snippets.

@laihaotao
Created April 26, 2018 06:06
import java.util.ArrayList;
import java.util.Stack;
/**
* Created by Haotao Lai on 2016-11-27.
* contact: h_lai@encs.concordia.ca
*/
public class MyAVLTree {
private static StringBuilder sb;
private MyAVLNode root;
private int allKeyIdx;
private int size;
public MyAVLTree() {
}
public MyAVLTree(MyLinkedList list) {
this.size = list.getSize();
this.root = transformListToTree(list);
}
public int[] allKeys() {
allKeyIdx = 0;
int[] arr = new int[size];
allKeysAuxiliary(root, arr);
return arr;
}
public void add(int key, Object value) {
this.root = insert(root, key, value);
}
public void remove(int key) {
this.root = delete(root, key);
}
public ArrayList<Object> getValue(int key) {
return getValueAux(root, key);
}
private ArrayList<Object> getValueAux(MyAVLNode root, int key) {
if (root != null) {
if (root.key == key) return root.values;
if (key < root.key) return getValueAux(root.left, key);
if (key > root.key) return getValueAux(root.right, key);
}
return null;
}
public int nextKey(int key) {
MyAVLNode root = this.root;
Stack<MyAVLNode> visitedPath = new Stack<>();
while (root != null) {
// remember the node which has been visited
visitedPath.push(root);
// go left subtree
if (key > root.key) {
root = root.right;
continue;
}
// go right subtree
if (key < root.key) {
root = root.left;
continue;
}
// if the key equal to the current node's key
if (root.right != null) {
// if the node has right subtree
return minValueNode(root.right).key;
} else {
// if the node do not has right subtree
visitedPath.pop(); // pop out the current node itself
while (visitedPath.peek().key < key) {
// if the top element is less than the given key
// pop them out, search for the ancestor
visitedPath.pop();
if (visitedPath.isEmpty()) {
// reach the root
return -1;
}
}
// find the first ancestor whose key is greater than the given key
return visitedPath.pop().key;
}
}
// if root is null, means can't find the given key, or the
// key is the maximum key in the tree, then return -1
return -1;
}
public int prevKey(int key) {
MyAVLNode root = this.root;
if (root == null) return -1;
Stack<MyAVLNode> visitedPath = new Stack<>();
while (root != null) {
// remember the node which has been visited
visitedPath.push(root);
// go left subtree
if (key > root.key) {
root = root.right;
continue;
}
// go right subtree
if (key < root.key) {
root = root.left;
continue;
}
// if the key equal to the current node's key
if (root.left != null) {
return maxValueNode(root.left).key;
}else {
// if the node do not has right subtree
visitedPath.pop(); // pop out the current node itself
while (visitedPath.peek().key > key) {
// if the top element is less than the given key
// pop them out, search for the ancestor
visitedPath.pop();
if (visitedPath.isEmpty()) {
// reach the root
return -1;
}
}
// find the first ancestor whose key is greater than the given key
return visitedPath.pop().key;
}
}
return -1;
}
public ArrayList rangeKey(int key1, int key2) {
return null;
}
public void inOrderTraversal() {
sb = new StringBuilder();
inOrderAuxiliary(root);
}
public int getSize() {
return size;
}
public MyAVLNode getRoot() {
return root;
}
private MyAVLNode insert(MyAVLNode node, int key, Object value) {
// if root is null
if (node == null) {
MyAVLNode n = new MyAVLNode(key, value);
size++;
return n;
}
// recursively find the correct position
if (key < node.key)
// go left subtree
node.left = insert(node.left, key, value);
else if (key > node.key)
// go right subtree
node.right = insert(node.right, key, value);
else {
// if the key is exist
node.values.add(value);
return node;
}
// update teh height of the node when recursively find the
// correct position for insertion
node.height = 1 + Math.max(height(node.left),
height(node.right));
// get the balance factor
int balance = getBalance(node);
// If node becomes unbalanced, then there are 4 cases
// Case 1
if (balance > 1 && key < node.left.key)
return rightRotate(node);
// Case 4
if (balance < -1 && key > node.right.key)
return leftRotate(node);
// Case 2
if (balance > 1 && key > node.left.key) {
node.left = leftRotate(node.left);
return rightRotate(node);
}
// Case 3
if (balance < -1 && key < node.right.key) {
node.right = rightRotate(node.right);
return leftRotate(node);
}
// if balanced, then return the (unchanged) node pointer
return node;
}
private MyAVLNode delete(MyAVLNode root, int key) {
if (root == null) return null;
// recursively find the target node for deletion
if (key < root.key)
// go left subtree
root.left = delete(root.left, key);
else if (key > root.key)
// go right subtree
root.right = delete(root.right, key);
else {// if found the node with target key
size--;
// node with only one child or no child
if ((root.left == null) || (root.right == null)) {
MyAVLNode temp = null;
// if left child is null, it may has right child
if (null == root.left) temp = root.right;// assign the right child to variable temp
else temp = root.left;// if left child is not null, means absolutely has left child
// if temp still null means has no child (the right child
// assign to temp is null)
if (temp == null) root = null;
else root = temp;// if it has child
} else {
// node with two children: Get the in order
// successor (smallest in the right subtree)
MyAVLNode temp = minValueNode(root.right);
// Copy the in order successor's data to this node
root.key = temp.key;
root.values = temp.values;
// Delete the in order successor
root.right = delete(root.right, temp.key);
}
}
if (root == null) return null;
root.height = Math.max(height(root.left), height(root.right)) + 1;
int balance = getBalance(root);
// If this node becomes unbalanced, then there are 4 cases
// Left Left Case
if (balance > 1 && getBalance(root.left) >= 0)
return rightRotate(root);
// Left Right Case
if (balance > 1 && getBalance(root.left) < 0) {
root.left = leftRotate(root.left);
return rightRotate(root);
}
// Right Right Case
if (balance < -1 && getBalance(root.right) <= 0)
return leftRotate(root);
// Right Left Case
if (balance < -1 && getBalance(root.right) > 0) {
root.right = rightRotate(root.right);
return leftRotate(root);
}
return root;
}
private MyAVLNode minValueNode(MyAVLNode node) {
MyAVLNode current = node;
while (current.left != null)
current = current.left;
return current;
}
private MyAVLNode maxValueNode(MyAVLNode node) {
MyAVLNode current = node;
while (current.right != null)
current = current.right;
return current;
}
private MyAVLNode leftRotate(MyAVLNode x) {
MyAVLNode y = x.right;
MyAVLNode T2 = y.left;
// Perform rotation
y.left = x;
x.right = T2;
// Update heights
x.height = Math.max(height(x.left), height(x.right)) + 1;
y.height = Math.max(height(y.left), height(y.right)) + 1;
// Return new root
return y;
}
private MyAVLNode rightRotate(MyAVLNode y) {
MyAVLNode x = y.left;
MyAVLNode T2 = x.right;
// Perform rotation
x.right = y;
y.left = T2;
// Update heights
y.height = Math.max(height(y.left), height(y.right)) + 1;
x.height = Math.max(height(x.left), height(x.right)) + 1;
// Return new root
return x;
}
// Get Balance factor of node N
private int getBalance(MyAVLNode n) {
if (n == null)
return 0;
return height(n.left) - height(n.right);
}
// A utility function to get height of the tree
private int height(MyAVLNode n) {
if (n == null) return 0;
return n.height;
}
private MyAVLNode transformListToTree(MyLinkedList list) {
MySLLNode head = list.getFirst();
while (head.hasNext()) {
add(head.getKey(), head.getValue());
head = head.next();
}
return root;
}
private int calculateHeight(MyAVLNode n) {
if (n == null) return 0;
return Math.max(calculateHeight(n.left), calculateHeight(n.right));
}
private void inOrderAuxiliary(MyAVLNode node) {
if (node.left != null)
inOrderAuxiliary(node.left);
// sb.append("[").append(node.key).append("]").append("(")
// .append(node.height).append(")").append(", ");
ArrayList<Object> values = node.values;
for (Object o : values) {
sb.append((int) o).append(", ");
}
if (node.right != null)
inOrderAuxiliary(node.right);
}
private void allKeysAuxiliary(MyAVLNode node, int[] arr) {
if (node.left != null)
allKeysAuxiliary(node.left, arr);
arr[allKeyIdx++] = node.key;
if (node.right != null)
allKeysAuxiliary(node.right, arr);
}
@Override
public String toString() {
inOrderTraversal();
return sb.substring(0, sb.lastIndexOf(","));
}
}
class MyAVLNode {
MyAVLNode left;
MyAVLNode right;
int height;
int key;
ArrayList<Object> values = new ArrayList<>();
public MyAVLNode(int key) {
this.key = key;
height = 1;
}
public MyAVLNode(int key, ArrayList<Object> values) {
this.key = key;
this.values = values;
height = 1;
}
public MyAVLNode(int key, Object values) {
this.key = key;
this.values.add(values);
height = 1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment