Created
April 26, 2018 06:06
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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