/** {@inheritDoc} */ @Override protected boolean validateNode(Node<T> node) { boolean bst = super.validateNode(node); if (!bst) return false; AVLNode<T> avlNode = (AVLNode<T>) node; int balanceFactor = avlNode.getBalanceFactor(); if (balanceFactor > 1 || balanceFactor < -1) { return false; } if (avlNode.isLeaf()) { if (avlNode.height != 1) return false; } else { AVLNode<T> avlNodeLesser = (AVLNode<T>) avlNode.lesser; int lesserHeight = 1; if (avlNodeLesser != null) lesserHeight = avlNodeLesser.height; AVLNode<T> avlNodeGreater = (AVLNode<T>) avlNode.greater; int greaterHeight = 1; if (avlNodeGreater != null) greaterHeight = avlNodeGreater.height; if (avlNode.height == (lesserHeight + 1) || avlNode.height == (greaterHeight + 1)) return true; return false; } return true; }
static AVLNode rebalancing(AVLNode root) { root.ht = Math.max(height(root.left), height(root.right)) + 1; int bf = height(root.left) - height(root.right); if (bf > 1) { bf = height(root.left.left) - height(root.left.right); if (bf < 0) { root.left = rotate(root.left, true); } root = rotate(root, false); } else if (bf < -1) { bf = height(root.right.left) - height(root.right.right); if (bf > 0) { root.right = rotate(root.right, false); } root = rotate(root, true); } return root; }
/** {@inheritDoc} */ @Override protected Node<T> removeValue(T value) { // Find node to remove Node<T> nodeToRemoved = this.getNode(value); if (nodeToRemoved == null) return null; // Find the replacement node Node<T> replacementNode = this.getReplacementNode(nodeToRemoved); // Find the parent of the replacement node to re-factor the height/balance of the tree AVLNode<T> nodeToRefactor = null; if (replacementNode != null) nodeToRefactor = (AVLNode<T>) replacementNode.parent; if (nodeToRefactor == null) nodeToRefactor = (AVLNode<T>) nodeToRemoved.parent; if (nodeToRefactor != null && nodeToRefactor == nodeToRemoved) nodeToRefactor = (AVLNode<T>) replacementNode; // Replace the node replaceNodeWithNode(nodeToRemoved, replacementNode); // Re-balance the tree all the way up the tree while (nodeToRefactor != null) { nodeToRefactor.updateHeight(); balanceAfterDelete(nodeToRefactor); nodeToRefactor = (AVLNode<T>) nodeToRefactor.parent; } return nodeToRemoved; }
protected AVLNode<T> insert(T data, AVLNode<T> t) throws Exception { if (t == null) t = new AVLNode<T>(data); else if (data.compareTo(t.data) < 0) { t.left = insert(data, t.left); if (height(t.left) - height(t.right) == 2) { if (data.compareTo(t.left.data) < 0) { t = rotateWithLeftChild(t); countSingleRotations++; } else { t = doubleRotateWithleftChild(t); countDoubleRotations++; } } } else if (data.compareTo(t.data) > 0) { t.right = insert(data, t.right); if (height(t.right) - height(t.left) == 2) { if (data.compareTo(t.right.data) > 0) { t = rotateWithRightChild(t); countSingleRotations++; } else { t = doubleRotateWithRightChild(t); countDoubleRotations++; } } } else { throw new Exception("Attempting to insert to duplicate value"); } t.height = max(height(t.left), height(t.right)) + 1; return t; }
protected AVLNode<T> rotateWithRightChild(AVLNode<T> root) { AVLNode<T> newRoot = root.right; root.right = newRoot.left; newRoot.left = root; root.height = max(height(root.left), height(root.right)) + 1; newRoot.height = max(height(newRoot.right), root.height) + 1; return newRoot; }
/* * Returns the parent tree */ public AVLNode<E> get_parent_helper(AVLNode<E> currentNode, AVLNode<E> root, AVLNode<E> x) { if (currentNode == null) return null; // System.out.println("current " + currentNode.getElement() + " and x " + x.getElement() ); // System.out.println(".equls is " + currentNode.getElement().equals(x.getElement())); if (currentNode.getElement().equals(x.getElement())) { return root; } AVLNode<E> value = get_parent_helper(currentNode.getLeft(), currentNode, x); if (value == null) return get_parent_helper(currentNode.getRight(), currentNode, x); return value; }
public AVLNode<T> remove(T x, AVLNode<T> t) { if (t == null) { System.out.println("Sorry but you're mistaken, " + t + " doesn't exist in this tree :)\n"); return null; } System.out.println("Remove starts... " + t.data + " and " + x); if (x.compareTo(t.data) < 0) { t.left = remove(x, t.left); int le = t.left != null ? t.left.height : 0; if ((t.right != null) && (t.right.height - le >= 2)) { int rightHeight = t.right.right != null ? t.right.right.height : 0; int leftHeight = t.right.left != null ? t.right.left.height : 0; if (rightHeight >= leftHeight) t = rotateWithLeftChild(t); else t = doubleRotateWithRightChild(t); } } else if (x.compareTo(t.data) > 0) { t.right = remove(x, t.right); int ri = t.right != null ? t.right.height : 0; if ((t.left != null) && (t.left.height - ri >= 2)) { int leftHeight = t.left.left != null ? t.left.left.height : 0; int rightHeight = t.left.right != null ? t.left.right.height : 0; if (leftHeight >= rightHeight) t = rotateWithRightChild(t); else t = doubleRotateWithleftChild(t); } } else if (t.left != null) { t.data = findMax(t.left).data; remove(t.data, t.left); if ((t.right != null) && (t.right.height - t.left.height >= 2)) { int rightHeight = t.right.right != null ? t.right.right.height : 0; int leftHeight = t.right.left != null ? t.right.left.height : 0; if (rightHeight >= leftHeight) t = rotateWithLeftChild(t); else t = doubleRotateWithRightChild(t); } } else { t = (t.left != null) ? t.left : t.right; } if (t != null) { int leftHeight = (t.left != null) ? t.left.height : 0; int rightHeight = (t.right != null) ? t.right.height : 0; t.height = max(leftHeight, rightHeight) + 1; } return t; }
/** * Update the path from node down to the node containing element. Since it is guaranteed there is * a path between these two arguments, node should never become null. * * @param node the root of some subtree, originally the root of the subtree whose node was * removed. * @param element the element stored at the end of the path to be updated. This element was the * parent to the value t hat supplied the replacement value for a node during a remove() * operation. */ private AVLNode<E> updatePath(AVLNode<E> node, E element) { int compareResult = element.compareTo(node.getElement()); if (compareResult == 0) { // reached the end of the path node = fixSubtreeRootedAt(node); } else if (compareResult < 0) { node.leftChild = updatePath((AVLNode<E>) node.leftChild, element); node = fixSubtreeRootedAt(node); } else if (compareResult > 0) { node.rightChild = updatePath((AVLNode<E>) node.rightChild, element); node = fixSubtreeRootedAt(node); } return node; }
// https://www.hackerrank.com/challenges/self-balancing-tree public AVLNode insert(AVLNode root, int val) { if (root == null) { AVLNode node = new AVLNode(); node.val = val; node.ht = 0; return node; } if (root.val > val) { root.left = insert(root.left, val); } else { root.right = insert(root.right, val); } return rebalancing(root); }
/** * Perform a right (clockwise) rotation at <tt>x</tt>. * * @param x the lowest unbalanced node found in this tree. * @return The new root of the balanced subtree. */ private AVLNode<E> rightRotation(AVLNode<E> x) { AVLNode<E> newRoot = (AVLNode<E>) x.leftChild; newRoot.parent = x.parent; x.parent = newRoot; x.leftChild = newRoot.rightChild; // newRoot is guaranteed to have a left child, but // we can't be sure it has a right child if (newRoot.rightChild != null) { newRoot.rightChild.parent = x; } newRoot.rightChild = x; // lastly: do updates from the bottom up updateBalanceAndHeight(x); updateBalanceAndHeight(newRoot); return newRoot; }
public static void rotateRight(AVLNode origRoot) { // === Difference from rotateLeft === AVLNode newRoot = origRoot.left; // Original root's left (previously new root) becomes new root's right origRoot.left = newRoot.right; // New root's right becomes original root newRoot.right = origRoot; // If original root is not root of tree if (origRoot.parent != null) { // Update new root's parent's link to it based on // whether original root is left or right child if (origRoot.parent.left.key == origRoot.key) { origRoot.parent.left = newRoot; } else { origRoot.parent.right = newRoot; } } // Update new root's parent to be original root's parent newRoot.parent = origRoot.parent; // Update original root's parent to be new root origRoot.parent = newRoot; // Update heights of original and new root newRoot.height -= 1; origRoot.height += 1; }
static AVLNode rotate(AVLNode root, boolean isLeft) { if (isLeft) { AVLNode right = root.right; root.right = right.left; right.left = root; root.ht = Math.max(height(root.left), height(root.right)) + 1; root = right; root.ht = Math.max(height(root.left), height(root.right)) + 1; } else { AVLNode left = root.left; root.left = left.right; left.right = root; root.ht = Math.max(height(root.left), height(root.right)) + 1; root = left; root.ht = Math.max(height(root.left), height(root.right)) + 1; } return root; }
private AVLNode rotate(AVLNode T) { if (T == null) return null; if (Height(T.getLeft()) - Height(T.getRight()) == 2) { if (Height(T.getLeft().getLeft()) >= Height(T.getLeft().getRight())) return SingleRotateWithLeft(T); else return DoubleRotateWithLeft(T); } else if (Height(T.getRight()) - Height(T.getLeft()) == 2) { if (Height(T.getRight().getRight()) >= Height(T.getRight().getLeft())) return SingleRotateWithRight(T); else return DoubleRotateWithRight(T); } return T; }
@Override protected void balance(AVLNode<T> node) { /* Rotation cases (N = node, C = child) * Case 1: * N * / * C * / * O * * Case 2: * N * / * C * \ * O * * Case 3: * N * \ * C * \ * O * Case 4: * N * \ * C * / * O */ if (node == null) return; int bf = node.getBalanceFactor(); if (bf == 2) { AVLNode<T> child = node.getLeftChild(); if (child.getBalanceFactor() == -1) // Case 2 rotateLeft(child); rotateRight(node); // Case 1 } else if (bf == -2) { AVLNode<T> child = node.getRightChild(); if (child.getBalanceFactor() == 1) // Case 4 rotateRight(child); rotateLeft(node); // Case 3 } else balance(node.getParent()); // Recurrsively balance parent }
/** {@inheritDoc} */ @Override protected Node<T> addValue(T id) { Node<T> nodeToReturn = super.addValue(id); AVLNode<T> nodeAdded = (AVLNode<T>) nodeToReturn; nodeAdded.updateHeight(); balanceAfterInsert(nodeAdded); nodeAdded = (AVLNode<T>) nodeAdded.parent; while (nodeAdded != null) { int h1 = nodeAdded.height; nodeAdded.updateHeight(); balanceAfterInsert(nodeAdded); // If height before and after balance is the same, stop going up the tree int h2 = nodeAdded.height; if (h1 == h2) break; nodeAdded = (AVLNode<T>) nodeAdded.parent; } return nodeToReturn; }
/* * Return the parent tree */ public AVLNode<E> get_parent(AVLNode<E> x) { if (rootAbove.getLeft() == null) { return null; } else if (x == null) { return null; } else if (rootAbove.getLeft().getElement().equals(x.getElement())) { return null; } AVLNode<E> value = get_parent_helper(rootAbove.getLeft(), rootAbove.getLeft(), x); if (value == null) return get_parent_helper(rootAbove.getRight(), rootAbove.getLeft(), x); return value; }
/** * On entry, <tt>x</tt> is the root of a subtree that has violated the balance properties of an * AVL tree, so requires rebalancing. * * @param x the root of the tree to be rebalanced. * @return The new root of the balanced subtree. */ private AVLNode<E> rebalance(AVLNode<E> x) { AVLNode<E> newRoot = null; // new root of balanced subtree // LL case - new node inserted into left subtree of // last unbalanced node's left child if (x.balance == 2) { // left subtree is unbalanced // Check for LL CASE if (((AVLNode<E>) x.leftChild).balance == 1) { newRoot = rightRotation(x); } else { // LR CASE x.leftChild = leftRotation((AVLNode<E>) x.leftChild); newRoot = rightRotation(x); } } else if (x.balance == -2) { // right subtree is unbalanced // Check for RR CASE if (((AVLNode<E>) x.rightChild).balance == -1) { newRoot = leftRotation(x); } else { // LR case x.rightChild = rightRotation((AVLNode<E>) x.rightChild); newRoot = leftRotation(x); } } return newRoot; }
/** * @param element: The element to remove from the AVLTree * @param temp: The root node of the subtree * <p>This method recursively traverses the AVLTree based on the ordering of the element with * respect to the Tree's elements. If the element is not found, then nothing happens. * Otherwise, the element is removed, and either the far-right element on its left child or * the far left element on its right child replaces it. * */ private void remove(E element, AVLNode<E> temp) { if (temp == null) return; int compare = 0; if (temp != rootAbove) compare = element.compareTo(temp.getElement()); boolean direction = (compare > 0 && temp != rootAbove); AVLNode<E> child = direction ? temp.getRight() : temp.getLeft(); if (child == null) return; // if the root is perfectly balanced, slide the left Node up // and reinsert the left.right element if necessary if (temp == rootAbove && child.getBalance() == 0 && child.getElement().equals(element)) { AVLNode<E> newRoot = child.getLeft(); if (newRoot == null) { rootAbove.setLeftNode(null); return; } else { enactRemoval(temp, child, false); return; } } // if the element is found and the root is not // perfectly balanced, remove it using enactRemoval() else if (element.compareTo(child.getElement()) == 0) { enactRemoval(temp, child, direction); } // otherwise, recursively traverse the tree else { remove(element, child); } }
/** * @param element: The element to search for in the AVLTree * @return boolean: true if the element is found, false otherwise * <p>The contains method simply traverses the binary search tree based on element's relation * to the AVLNodes in the Tree until a match is found or it hits the bottom of the Tree. */ public boolean contains(E element) { AVLNode<E> temp = rootAbove.getLeft(); while (temp != null) { if (temp.getElement().equals(element)) return true; int balance = element.compareTo(temp.getElement()); temp = (balance < 0) ? temp.getLeft() : temp.getRight(); } return false; }
public AVLNode<E> find(E element) { AVLNode<E> temp = rootAbove.getLeft(); while (temp != null) { if (temp.getElement().equals(element)) return temp; int balance = element.compareTo(temp.getElement()); temp = (balance < 0) ? temp.getLeft() : temp.getRight(); } return null; }
private void addChildTree(DefaultMutableTreeNode root, AVLNode avlRoot) { if (avlRoot.getLeft() != null) { DefaultMutableTreeNode leftNode = new DefaultMutableTreeNode(new AVLTreeNode(avlRoot.getLeft(), "Left ")); addChildTree(leftNode, avlRoot.getLeft()); root.add(leftNode); } if (avlRoot.getRight() != null) { DefaultMutableTreeNode rightNode = new DefaultMutableTreeNode(new AVLTreeNode(avlRoot.getRight(), "Right ")); addChildTree(rightNode, avlRoot.getRight()); root.add(rightNode); } }
/** * Balance the tree according to the AVL post-delete algorithm. * * @param node Root of tree to balance. */ private void balanceAfterDelete(AVLNode<T> node) { int balanceFactor = node.getBalanceFactor(); if (balanceFactor == -2 || balanceFactor == 2) { if (balanceFactor == -2) { AVLNode<T> ll = (AVLNode<T>) node.lesser.lesser; int lesser = (ll != null) ? ll.height : 0; AVLNode<T> lr = (AVLNode<T>) node.lesser.greater; int greater = (lr != null) ? lr.height : 0; if (lesser >= greater) { rotateRight(node); node.updateHeight(); if (node.parent != null) ((AVLNode<T>) node.parent).updateHeight(); } else { rotateLeft(node.lesser); rotateRight(node); AVLNode<T> p = (AVLNode<T>) node.parent; if (p.lesser != null) ((AVLNode<T>) p.lesser).updateHeight(); if (p.greater != null) ((AVLNode<T>) p.greater).updateHeight(); p.updateHeight(); } } else if (balanceFactor == 2) { AVLNode<T> rr = (AVLNode<T>) node.greater.greater; int greater = (rr != null) ? rr.height : 0; AVLNode<T> rl = (AVLNode<T>) node.greater.lesser; int lesser = (rl != null) ? rl.height : 0; if (greater >= lesser) { rotateLeft(node); node.updateHeight(); if (node.parent != null) ((AVLNode<T>) node.parent).updateHeight(); } else { rotateRight(node.greater); rotateLeft(node); AVLNode<T> p = (AVLNode<T>) node.parent; if (p.lesser != null) ((AVLNode<T>) p.lesser).updateHeight(); if (p.greater != null) ((AVLNode<T>) p.greater).updateHeight(); p.updateHeight(); } } } }
public AVLNode<E> get_left_neighbor(AVLNode<E> x) { AVLNode<E> left_child = x.getLeft(); AVLNode<E> ret = left_child; if (left_child == null) { if (get_parent(x) != null && get_parent(x).getElement().compareTo(x.getElement()) == -1) { return get_parent(x); } else { return null; } } AVLNode<E> right = left_child.getRight(); while (right != null) { ret = right; right = right.getRight(); } return ret; }
/** * Balance the tree according to the AVL post-insert algorithm. * * @param node Root of tree to balance. */ private void balanceAfterInsert(AVLNode<T> node) { int balanceFactor = node.getBalanceFactor(); if (balanceFactor > 1 || balanceFactor < -1) { AVLNode<T> child = null; Balance balance = null; if (balanceFactor < 0) { child = (AVLNode<T>) node.lesser; balanceFactor = child.getBalanceFactor(); if (balanceFactor < 0) balance = Balance.LEFT_LEFT; else balance = Balance.LEFT_RIGHT; } else { child = (AVLNode<T>) node.greater; balanceFactor = child.getBalanceFactor(); if (balanceFactor < 0) balance = Balance.RIGHT_LEFT; else balance = Balance.RIGHT_RIGHT; } if (balance == Balance.LEFT_RIGHT) { // Left-Right (Left rotation, right rotation) rotateLeft(child); rotateRight(node); } else if (balance == Balance.RIGHT_LEFT) { // Right-Left (Right rotation, left rotation) rotateRight(child); rotateLeft(node); } else if (balance == Balance.LEFT_LEFT) { // Left-Left (Right rotation) rotateRight(node); } else { // Right-Right (Left rotation) rotateLeft(node); } child.updateHeight(); node.updateHeight(); } }
@Override protected void rotateRight(AVLNode<T> node) { super.rotateRight(node); node.resetHeights(); // Reset Height after rotation }
/** Update the balance and height properties of <tt>node</tt>. */ private void updateBalanceAndHeight(AVLNode<E> node) { int leftHeight = height((AVLNode<E>) node.leftChild); int rightHeight = height((AVLNode<E>) node.rightChild); node.height = (leftHeight > rightHeight ? leftHeight : rightHeight) + 1; node.balance = leftHeight - rightHeight; }
@Override public String toString() { return title + String.valueOf(node.getValue()) + "|" + node.getHeight(); }
AVLNode insert(int x, AVLNode T) { if (T == null) { T = new AVLNode(); T.setValue(x); T.setLeft(null); T.setRight(null); } else if (x < T.getValue()) { T.setLeft(insert(x, T.getLeft())); if (Height(T.getLeft()) - Height(T.getRight()) == 2) { if (x < T.getLeft().getValue()) T = SingleRotateWithLeft(T); else T = DoubleRotateWithLeft(T); } } else if (x > T.getValue()) { T.setRight(insert(x, T.getRight())); if (Height(T.getRight()) - Height(T.getLeft()) == 2) if (x > T.getRight().getValue()) T = SingleRotateWithRight(T); else T = DoubleRotateWithRight(T); } T.setHeight(Math.max(Height(T.getLeft()), Height(T.getRight())) + 1); return T; }
int Height(AVLNode avl) { if (avl == null) return -1; else return avl.getHeight(); }
AVLNode findMin(AVLNode tree) { if (tree != null) while (tree.getLeft() != null) tree = tree.getLeft(); return tree; }