All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrapht.util.AVLTree Maven / Gradle / Ivy

The newest version!
/*
 * (C) Copyright 2020-2023, by Timofey Chudakov and Contributors.
 *
 * JGraphT : a free Java graph-theory library
 *
 * See the CONTRIBUTORS.md file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0, or the
 * GNU Lesser General Public License v2.1 or later
 * which is available at
 * http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later
 */
package org.jgrapht.util;

import java.util.*;

/**
 * Implementation of the AVL tree data
 * structure. Note: this tree doesn't use key comparisons, so this tree can't be used as a
 * binary search tree. This implies that the same key can be added to this tree multiple times.
 * 

* AVL tree is a self-balancing binary tree data structure. In an AVL tree, the heights of two child * subtrees differ by at most one. This ensures that the height of the tree is $\mathcal{O}(\log n)$ * where $n$ is the number of elements in the tree. Also this tree doesn't support key comparisons, * it does define an element order. As a result, this tree can be used to query node * successor/predecessor. *

* Subtree query means that the result is being computed only on the subtree nodes. This tree * supports the following operations: *

    *
  • Min/max insertion and deletion in $\mathcal{O}(\log n)$ time
  • *
  • Subtree min/max queries in $\mathcal{O}(1)$ time
  • *
  • Node successor/predecessor queries in $\mathcal{O}(1)$ time
  • *
  • Tree split in $\mathcal{O}(\log n)$ time
  • *
  • Tree merge in $\mathcal{O}(\log n)$ time
  • *
*

* This implementation gives users access to the tree nodes which hold the inserted elements. The * user is able to store the tree nodes references but isn't able to modify them. * * @param the key data type * @author Timofey Chudakov */ public class AVLTree implements Iterable { /** * An auxiliary node which's always present in a tree and doesn't contain any data. */ private TreeNode virtualRoot = new TreeNode<>(null); /** * Modification tracker */ private int modCount = 0; /** * Constructs an empty tree */ public AVLTree() { } /** * Constructor for internal usage * * @param root the root of the newly create tree */ private AVLTree(TreeNode root) { makeRoot(root); } /** * Adds {@code value} as a maximum element to this tree. The running time of this method is * $\mathcal{O}(\log n)$ * * @param value a value to add as a tree max * @return a tree node holding the {@code value} */ public TreeNode addMax(T value) { TreeNode newMax = new TreeNode<>(value); addMaxNode(newMax); return newMax; } /** * Adds the {@code newMax} as a maximum node to this tree. * * @param newMax a node to add as a tree max */ public void addMaxNode(TreeNode newMax) { registerModification(); if (isEmpty()) { virtualRoot.left = newMax; newMax.parent = virtualRoot; } else { TreeNode max = getMax(); max.setRightChild(newMax); balance(max); } } /** * Adds the {@code value} as a minimum element to this tree * * @param value a value to add as a tree min * @return a tree node holding the {@code value} */ public TreeNode addMin(T value) { TreeNode newMin = new TreeNode<>(value); addMinNode(newMin); return newMin; } /** * Adds the {@code newMin} as a minimum node to this tree * * @param newMin a node to add as a tree min */ public void addMinNode(TreeNode newMin) { registerModification(); if (isEmpty()) { virtualRoot.left = newMin; newMin.parent = virtualRoot; } else { TreeNode min = getMin(); min.setLeftChild(newMin); balance(min); } } /** * Splits the tree into two parts. *

* The first part contains the nodes which are smaller than or equal to the {@code node}. The * first part stays in this tree. The second part contains the nodes which are strictly greater * than the {@code node}. The second part is returned as a tree. * * @param node a separating node * @return a tree containing the nodes which are strictly greater than the {@code node} */ public AVLTree splitAfter(TreeNode node) { registerModification(); TreeNode parent = node.parent; boolean nextMove = node.isLeftChild(); TreeNode left = node.left; TreeNode right = node.right; node.parent.substituteChild(node, null); node.reset(); if (left != null) { left.parent = null; } if (right != null) { right.parent = null; } if (left == null) { left = node; } else { // insert node as a left subtree max TreeNode t = left; while (t.right != null) { t = t.right; } t.setRightChild(node); while (t != left) { TreeNode p = t.parent; p.substituteChild(t, balanceNode(t)); t = p; } left = balanceNode(left); } return split(left, right, parent, nextMove); } /** * Splits the tree into two parts. *

* The first part contains the nodes which are smaller than the {@code node}. The first part * stays in this tree. The second part contains the nodes which are greater than or equal to the * {@code node}. The second part is returned as a tree. * * @param node a separating node * @return a tree containing the nodes which are greater than or equal to the {@code node} */ public AVLTree splitBefore(TreeNode node) { registerModification(); TreeNode predecessor = predecessor(node); if (predecessor == null) { // node is a minimum node AVLTree tree = new AVLTree<>(); swap(tree); return tree; } return splitAfter(predecessor); } /** * Append the nodes in the {@code tree} after the nodes in this tree. *

* The result of this operation is stored in this tree. * * @param tree a tree to append */ public void mergeAfter(AVLTree tree) { registerModification(); if (tree.isEmpty()) { return; } else if (tree.getSize() == 1) { addMaxNode(tree.removeMin()); return; } TreeNode junctionNode = tree.removeMin(); TreeNode treeRoot = tree.getRoot(); tree.clear(); makeRoot(merge(junctionNode, getRoot(), treeRoot)); } /** * Prepends the nodes in the {@code tree} before the nodes in this tree. *

* The result of this operation is stored in this tree. * * @param tree a tree to prepend */ public void mergeBefore(AVLTree tree) { registerModification(); tree.mergeAfter(this); swap(tree); } /** * Removes the minimum node in this tree. Returns {@code null} if this tree is empty * * @return the removed node or {@code null} if this tree is empty */ public TreeNode removeMin() { registerModification(); if (isEmpty()) { return null; } TreeNode min = getMin(); // min.parent != null if (min.parent == virtualRoot) { makeRoot(min.right); } else { min.parent.setLeftChild(min.right); } balance(min.parent); return min; } /** * Removes the maximum node in this tree. Returns {@code null} if this tree is empty * * @return the removed node or {@code null} if this tree is empty */ public TreeNode removeMax() { registerModification(); if (isEmpty()) { return null; } TreeNode max = getMax(); if (max.parent == virtualRoot) { makeRoot(max.left); } else { max.parent.setRightChild(max.left); } balance(max.parent); return max; } /** * Returns the root of this tree or null if this tree is empty. * * @return the root of this tree or null if this tree is empty. */ public TreeNode getRoot() { return virtualRoot.left; } /** * Returns the node following the {@code node} in the order defined by this tree. Returns null * if the {@code node} is the maximum node in the tree. * * @param node a node to compute successor of * @return the successor of the {@code node} */ public TreeNode successor(TreeNode node) { return node.successor; } /** * Returns the node, which is before the {@code node} in the order defined by this tree. Returns * null if the {@code node} is the minimum node in the tree. * * @param node a node to compute predecessor of * @return the predecessor of the {@code node} */ public TreeNode predecessor(TreeNode node) { return node.predecessor; } /** * Returns the minimum node in this tree or null if the tree is empty. * * @return the minimum node in this tree or null if the tree is empty. */ public TreeNode getMin() { return getRoot() == null ? null : getRoot().getSubtreeMin(); } /** * Returns the maximum node in this tree or null if the tree is empty. * * @return the maximum node in this tree or null if the tree is empty. */ public TreeNode getMax() { return getRoot() == null ? null : getRoot().getSubtreeMax(); } /** * Check if this tree is empty * * @return {@code true} if this tree is empty, {@code false otherwise} */ public boolean isEmpty() { return getRoot() == null; } /** * Removes all nodes from this tree. *

* Note: the memory allocated for the tree structure won't be deallocated until there are * active external referenced to the nodes of this tree. */ public void clear() { registerModification(); virtualRoot.left = null; } /** * Returns the size of this tree * * @return the size of this tree */ public int getSize() { return virtualRoot.left == null ? 0 : virtualRoot.left.subtreeSize; } /** * Makes the {@code node} the root of this tree * * @param node a new root of this tree */ private void makeRoot(TreeNode node) { virtualRoot.left = node; if (node != null) { node.subtreeMax.successor = null; node.subtreeMin.predecessor = null; node.parent = virtualRoot; } } /** * Traverses the tree up until the virtual root and splits it into two parts. *

* The algorithm is described in Donald E. Knuth. The art of computer programming. Second * Edition. Volume 3 / Sorting and Searching, p. 474. * * @param left a left subtree * @param right a right subtree * @param p next parent node * @param leftMove {@code true} if we're moving from the left child, {@code false} otherwise. * @return the resulting right tree */ private AVLTree split(TreeNode left, TreeNode right, TreeNode p, boolean leftMove) { while (p != virtualRoot) { boolean nextMove = p.isLeftChild(); TreeNode nextP = p.parent; p.parent.substituteChild(p, null); p.parent = null; if (leftMove) { right = merge(p, right, p.right); } else { left = merge(p, p.left, left); } p = nextP; leftMove = nextMove; } makeRoot(left); return new AVLTree<>(right); } /** * Merges the {@code left} and {@code right} subtrees using the {@code junctionNode}. *

* The algorithm is described in Donald E. Knuth. The art of computer programming. Second * Edition. Volume 3 / Sorting and Searching, p. 474. * * @param junctionNode a node between left and right subtrees * @param left a left subtree * @param right a right subtree * @return the root of the resulting tree */ private TreeNode merge(TreeNode junctionNode, TreeNode left, TreeNode right) { if (left == null && right == null) { junctionNode.reset(); return junctionNode; } else if (left == null) { right.setLeftChild(merge(junctionNode, left, right.left)); return balanceNode(right); } else if (right == null) { left.setRightChild(merge(junctionNode, left.right, right)); return balanceNode(left); } else if (left.getHeight() > right.getHeight() + 1) { left.setRightChild(merge(junctionNode, left.right, right)); return balanceNode(left); } else if (right.getHeight() > left.getHeight() + 1) { right.setLeftChild(merge(junctionNode, left, right.left)); return balanceNode(right); } else { junctionNode.setLeftChild(left); junctionNode.setRightChild(right); return balanceNode(junctionNode); } } /** * Swaps the contents of this tree and the {@code tree} * * @param tree a tree to swap content of */ private void swap(AVLTree tree) { TreeNode t = virtualRoot.left; makeRoot(tree.virtualRoot.left); tree.makeRoot(t); } /** * Performs a right node rotation. * * @param node a node to rotate * @return a new parent of the {@code node} */ private TreeNode rotateRight(TreeNode node) { TreeNode left = node.left; left.parent = null; node.setLeftChild(left.right); left.setRightChild(node); node.updateHeightAndSubtreeSize(); left.updateHeightAndSubtreeSize(); return left; } /** * Performs a left node rotation. * * @param node a node to rotate * @return a new parent of the {@code node} */ private TreeNode rotateLeft(TreeNode node) { TreeNode right = node.right; right.parent = null; node.setRightChild(right.left); right.setLeftChild(node); node.updateHeightAndSubtreeSize(); right.updateHeightAndSubtreeSize(); return right; } /** * Performs a node balancing on the path from {@code node} up until the root * * @param node a node to start tree balancing from */ private void balance(TreeNode node) { balance(node, virtualRoot); } /** * Performs a node balancing on the path from {@code node} up until the {@code stop} node * * @param node a node to start tree balancing from * @param stop a node to stop balancing at (this node is not being balanced) */ private void balance(TreeNode node, TreeNode stop) { if (node == stop) { return; } TreeNode p = node.parent; if (p == virtualRoot) { makeRoot(balanceNode(node)); } else { p.substituteChild(node, balanceNode(node)); } balance(p, stop); } /** * Checks whether the {@code node} is unbalanced. If so, balances the {@code node} * * @param node a node to balance * @return a new parent of {@code node} if the balancing occurs, {@code node} otherwise */ private TreeNode balanceNode(TreeNode node) { node.updateHeightAndSubtreeSize(); if (node.isLeftDoubleHeavy()) { if (node.left.isRightHeavy()) { node.setLeftChild(rotateLeft(node.left)); } rotateRight(node); return node.parent; } else if (node.isRightDoubleHeavy()) { if (node.right.isLeftHeavy()) { node.setRightChild(rotateRight(node.right)); } rotateLeft(node); return node.parent; } return node; } /** * Registers a modifying operation */ private void registerModification() { ++modCount; } /** * {@inheritDoc} */ @Override public String toString() { StringBuilder builder = new StringBuilder(); for (Iterator> i = nodeIterator(); i.hasNext();) { TreeNode node = i.next(); builder.append(node.toString()).append("\n"); } return builder.toString(); } /** * {@inheritDoc} */ @Override public Iterator iterator() { return new TreeValuesIterator(); } /** * Returns an iterator over the tree nodes rather than the node values. The tree are returned in * the same order as the tree values. * * @return an iterator over the tree nodes */ public Iterator> nodeIterator() { return new TreeNodeIterator(); } /** * Iterator over the values stored in this tree. This implementation uses the * {@code TreeNodeIterator} to iterator over the values. */ private class TreeValuesIterator implements Iterator { /** * Internally used {@code TreeNodeIterator} */ private TreeNodeIterator iterator; /** * Constructs a new {@code TreeValuesIterator} */ public TreeValuesIterator() { iterator = new TreeNodeIterator(); } /** * {@inheritDoc} */ @Override public boolean hasNext() { return iterator.hasNext(); } /** * {@inheritDoc} */ @Override public T next() { return iterator.next().getValue(); } } /** * Iterator over the tree nodes. The nodes are returned according to the in order tree * traversal. */ private class TreeNodeIterator implements Iterator> { /** * A node that is returned next or {@code null} if all nodes are traversed */ private TreeNode nextNode; /** * Number of modifications of the tree at the time this iterator is created. */ private final int expectedModCount; /** * Constructs a new {@code TreeNodeIterator} */ public TreeNodeIterator() { nextNode = getMin(); expectedModCount = modCount; } /** * {@inheritDoc} */ @Override public boolean hasNext() { checkForComodification(); return nextNode != null; } /** * {@inheritDoc} */ @Override public TreeNode next() { if (!hasNext()) { throw new NoSuchElementException(); } TreeNode result = nextNode; nextNode = successor(nextNode); return result; } /** * Checks if the tree has been modified during the iteration process */ private void checkForComodification() { if (expectedModCount != modCount) { throw new ConcurrentModificationException(); } } } /** * Container holding the values stored in the tree. * * @param a tree node value type */ public static class TreeNode { /** * A value stored in this tree node */ T value; /** * Parent of this node */ TreeNode parent; /** * Left child of this node */ TreeNode left; /** * Right child of this node */ TreeNode right; /** * Next node in the tree according to the in order traversal */ TreeNode successor; /** * Previous node in the tree according to the in order traversal */ TreeNode predecessor; /** * A minimum node in the subtree rooted at this node */ TreeNode subtreeMin; /** * A maximum node in the subtree rooted at this node */ TreeNode subtreeMax; /** * Height of the node */ int height; /** * Size of the subtree rooted at this node */ int subtreeSize; /** * Constructs a new node with the {@code value} stored in it * * @param value a value to store in this node */ TreeNode(T value) { this.value = value; reset(); } /** * Returns a value stored in this node * * @return a value stored in this node */ public T getValue() { return value; } /** * Returns a root of the tree this node is stored in * * @return a root of the tree this node is stored in */ public TreeNode getRoot() { TreeNode current = this; while (current.parent != null) { current = current.parent; } return current.left; } /** * Returns a minimum node stored in the subtree rooted at this node * * @return a minimum node stored in the subtree rooted at this node */ public TreeNode getSubtreeMin() { return subtreeMin; } /** * Returns a maximum node stored in the subtree rooted at this node * * @return a maximum node stored in the subtree rooted at this node */ public TreeNode getSubtreeMax() { return subtreeMax; } /** * Returns a minimum node stored in the tree * * @return a minimum node stored in the tree */ public TreeNode getTreeMin() { return getRoot().getSubtreeMin(); } /** * Returns a maximum node stored in the tree * * @return a maximum node stored in the tree */ public TreeNode getTreeMax() { return getRoot().getSubtreeMax(); } /** * Returns a parent of this node * * @return a parent of this node */ public TreeNode getParent() { return parent; } /** * Returns a left child of this node * * @return a left child of this node */ public TreeNode getLeft() { return left; } /** * Returns a right child of this node * * @return a right child of this node */ public TreeNode getRight() { return right; } /** * Returns a height of this node * * @return a height of this node */ int getHeight() { return height; } /** * Returns a subtree size of the tree rooted at this node * * @return a subtree size of the tree rooted at this node */ int getSubtreeSize() { return subtreeSize; } /** * Resets this node to the default state */ void reset() { this.height = 1; this.subtreeSize = 1; this.subtreeMin = this; this.subtreeMax = this; this.left = this.right = this.parent = this.predecessor = this.successor = null; } /** * Returns a height of the right subtree * * @return a height of the right subtree */ int getRightHeight() { return right == null ? 0 : right.height; } /** * Returns a height of the left subtree * * @return a height of the right subtree */ int getLeftHeight() { return left == null ? 0 : left.height; } /** * Returns a size of the left subtree * * @return a size of the left subtree */ int getLeftSubtreeSize() { return left == null ? 0 : left.subtreeSize; } /** * Returns a size of the right subtree * * @return a size of the right subtree */ int getRightSubtreeSize() { return right == null ? 0 : right.subtreeSize; } /** * Updates the height and subtree size of this node according to the values of the left and * right children */ void updateHeightAndSubtreeSize() { height = Math.max(getLeftHeight(), getRightHeight()) + 1; subtreeSize = getLeftSubtreeSize() + getRightSubtreeSize() + 1; } /** * Returns {@code true} if this node is unbalanced and the left child's height is greater, * {@code false otherwise} * * @return {@code true} if this node is unbalanced and the left child's height is greater, * {@code false otherwise} */ boolean isLeftDoubleHeavy() { return getLeftHeight() > getRightHeight() + 1; } /** * Returns {@code true} if this node is unbalanced and the right child's height is greater, * {@code false otherwise} * * @return {@code true} if this node is unbalanced and the right child's height is greater, * {@code false otherwise} */ boolean isRightDoubleHeavy() { return getRightHeight() > getLeftHeight() + 1; } /** * Returns {@code true} if the height of the left child is greater than the height of the * right child * * @return {@code true} if the height of the left child is greater than the height of the * right child */ boolean isLeftHeavy() { return getLeftHeight() > getRightHeight(); } /** * Returns {@code true} if the height of the right child is greater than the height of the * left child * * @return {@code true} if the height of the right child is greater than the height of the * left child */ boolean isRightHeavy() { return getRightHeight() > getLeftHeight(); } /** * Returns {@code true} if this node is a left child of its parent, {@code false} otherwise * * @return {@code true} if this node is a left child of its parent, {@code false} otherwise */ boolean isLeftChild() { return this == parent.left; } /** * Returns {@code true} if this node is a right child of its parent, {@code false} otherwise * * @return {@code true} if this node is a right child of its parent, {@code false} otherwise */ boolean isRightChild() { return this == parent.right; } /** * Returns a successor of this node according to the tree in order traversal, or * {@code null} if this node is a maximum node in the tree * * @return successor of this node, or {@code} null if this node in a maximum node in the * tree */ public TreeNode getSuccessor() { return successor; } /** * Returns a predecessor of this node according to the tree in order traversal, or * {@code null} if this node is a minimum node in the tree * * @return predecessor of this node, or {@code} null if this node in a minimum node in the * tree */ public TreeNode getPredecessor() { return predecessor; } /** * Updates the successor reference of this node. If the {@code node} is not {@code null}, * updates its predecessor reference as well * * @param node new successor */ void setSuccessor(TreeNode node) { successor = node; if (node != null) { node.predecessor = this; } } /** * Updates the predecessor reference of this node. If the {@code node} is not {@code null}, * updates its successor reference as well * * @param node new predecessor */ void setPredecessor(TreeNode node) { predecessor = node; if (node != null) { node.successor = this; } } /** * Sets the left child reference of this node to {@code node}. If the {@code node} is not * {@code null}, updates its parent reference as well. * * @param node a new left child */ void setLeftChild(TreeNode node) { left = node; if (node != null) { node.parent = this; setPredecessor(node.subtreeMax); subtreeMin = node.subtreeMin; } else { subtreeMin = this; predecessor = null; } } /** * Sets the right child reference of this node to {@code node}. If the {@code node} is not * {@code null}, updates its parent reference as well. * * @param node a new right child */ void setRightChild(TreeNode node) { right = node; if (node != null) { node.parent = this; setSuccessor(node.subtreeMin); subtreeMax = node.subtreeMax; } else { successor = null; subtreeMax = this; } } /** * Substitutes the {@code prevChild} with the {@code newChild}. If the {@code newChild} is * not {@code null}, updates its parent reference as well * * @param prevChild either left or right child of this node * @param newChild a new child of this node */ void substituteChild(TreeNode prevChild, TreeNode newChild) { assert left == prevChild || right == prevChild; assert !(left == prevChild && right == prevChild); if (left == prevChild) { setLeftChild(newChild); } else { setRightChild(newChild); } } /** * {@inheritDoc} */ @Override public String toString() { return String.format( "{%s}: [parent = %s, left = %s, right = %s], [subtreeMin = %s, subtreeMax = %s], [predecessor = %s, successor = %s], [height = %d, subtreeSize = %d]", value, parent == null ? "null" : parent.value, left == null ? "null" : left.value, right == null ? "null" : right.value, subtreeMin == null ? "null" : subtreeMin.value, subtreeMax == null ? "null" : subtreeMax.value, predecessor == null ? "null" : predecessor.value, successor == null ? "null" : successor.value, height, subtreeSize); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy