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

net.anwiba.commons.lang.tree.Tree Maven / Gradle / Ivy

There is a newer version: 1.2.50
Show newest version
/*
 * #%L
 * anwiba commons core
 * %%
 * Copyright (C) 2007 - 2016 Andreas Bartels
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 2.1 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */
package net.anwiba.commons.lang.tree;

import net.anwiba.commons.lang.collection.IObjectIteratorFactory;
import net.anwiba.commons.lang.exception.UnreachableCodeReachedException;
import net.anwiba.commons.lang.tree.distance.IObjectDistanceCalculator;
import net.anwiba.commons.lang.tree.iterator.BreadthFirstSearchValueIteratorFactory;
import net.anwiba.commons.lang.tree.iterator.DeepFirstSearchValueIteratorFactory;
import net.anwiba.commons.lang.tree.iterator.SortedKeyIteratorFactory;
import net.anwiba.commons.lang.tree.iterator.SortedValueIteratorFactory;
import net.anwiba.commons.lang.tree.iterator.TreeIterable;
import net.anwiba.commons.lang.tree.walker.ITreeWalker;
import net.anwiba.commons.lang.tree.walker.TreeWalker;

import java.util.Comparator;

public class Tree implements ITree {

  private TreeItem first = null;
  private TreeItem last = null;
  private TreeItem root = null;

  private int numberOfItems = 0;
  private final int maximumOfItems;
  private Comparator comparator;
  private ITreeItemChooser treeItemChooser;

  public Tree(final Comparator comparator) {
    this(comparator, Integer.MAX_VALUE, new TreeItemChooser(new IObjectDistanceCalculator() {

      @Override
      public double calculate(final K object, final K other) {
        return Double.NaN;
      }
    }));
  }

  public Tree(final Comparator comparator, final int maximumOfItems, final ITreeItemChooser treeItemChooser) {
    this.comparator = comparator;
    this.maximumOfItems = maximumOfItems;
    this.treeItemChooser = treeItemChooser;
  }

  @Override
  public void insert(final K key, final V element) {
    if (key == null) {
      throw new NullPointerException();
    }
    if (element == null) {
      throw new NullPointerException();
    }
    if (this.root == null) {
      this.root = new TreeItem<>(key, element);
      this.first = this.root;
      this.last = this.root;
      this.numberOfItems++;
    } else {
      insert(this.root, key, element);
    }
  }

  private boolean insert(final TreeItem item, final K key, final V element) {
    if (item == null) {
      throw new NullPointerException();
    }
    if (element == null) {
      throw new NullPointerException();
    }
    if (this.comparator.compare(key, item.getKey()) < 0) {
      if (item.left == null) {
        if (this.numberOfItems >= this.maximumOfItems) {
          changeItemIfNecesary(item, key, element);
          return false;
        }
        item.left = new TreeItem<>(key, element);
        item.left.parent = item;
        item.balanced--;
        item.left.next = item;
        item.left.prev = item.prev;
        item.prev = item.left;
        if (item.left.prev != null) {
          item.left.prev.next = item.left;
        } else {
          this.first = item.left;
        }
        this.numberOfItems++;
        return item.right == null;
      }
      if (insert(item.left, key, element)) {
        switch (item.balanced) {
          case TreeItem.BALANCED: {
            item.balanced = TreeItem.LEFT;
            return true;
          }
          case TreeItem.RIGHT: {
            item.balanced = TreeItem.BALANCED;
            return false;
          }
          case TreeItem.LEFT: {
            if (item.left.balanced == TreeItem.RIGHT) {
              leftRightRotation(item);
            } else {
              rightRotation(item);
            }
            item.balanced = TreeItem.BALANCED;
            return false;
          }
        }
        throw new UnreachableCodeReachedException();
      }
      return false;
    } else if (this.comparator.compare(key, item.getKey()) > 0) {
      if (item.right == null) {
        if (this.numberOfItems >= this.maximumOfItems) {
          changeItemIfNecesary(item, key, element);
          return false;
        }
        item.right = new TreeItem<>(key, element);
        item.right.parent = item;
        item.balanced++;
        item.right.prev = item;
        item.right.next = item.next;
        item.next = item.right;
        if (item.right.next != null) {
          item.right.next.prev = item.right;
        } else {
          this.last = item.right;
        }
        this.numberOfItems++;
        return item.left == null;
      }
      if (insert(item.right, key, element)) {
        switch (item.balanced) {
          case TreeItem.BALANCED: {
            item.balanced = TreeItem.RIGHT;
            return true;
          }
          case TreeItem.LEFT: {
            item.balanced = TreeItem.BALANCED;
            return false;
          }
          case TreeItem.RIGHT: {
            if (item.right.balanced == TreeItem.LEFT) {
              rightLeftRotation(item);
            } else {
              leftRotation(item);
            }
            item.balanced = TreeItem.BALANCED;
            return false;
          }
        }
        throw new UnreachableCodeReachedException();
      }
      return false;
    } else {
      item.setElement(element);
      return false;
    }
  }

  private void changeItemIfNecesary(final TreeItem item, final K key, final V element) {
    final TreeItem choosed = choose(item, key, element);
    if (choosed == null) {
      this.treeItemChooser.removed(key);
      return;
    }
    replace(choosed, new TreeItem<>(key, element));
    return;
  }

  private final TreeItem choose(final TreeItem item, final K key, final V element) {
    final K itemKey = item.getKey();
    final int compareResult = this.comparator.compare(itemKey, key);
    if (compareResult == 0) {
      return null;
    }
    if (item.getPrevious() == null) {
      if (compareResult > 0) {
        return item;
      }
      final K choosed = this.treeItemChooser.choose(this.comparator, item.next, key, element);
      if (choosed == key) {
        return item.next;
      }
      return null;
    }
    if (item.getNext() == null) {
      if (compareResult < 0) {
        return item;
      }
      final K choosed = this.treeItemChooser.choose(this.comparator, item.prev, key, element);
      if (choosed == key) {
        return item.prev;
      }
      return null;
    }
    K choosed = this.treeItemChooser.choose(this.comparator, item, key, element);
    if (choosed == key) {
      return item;
    }
    if (compareResult < 0) {
      if (item.next.next != null) {
        choosed = this.treeItemChooser.choose(this.comparator, item.next, key, element);
        if (choosed == key) {
          return item.next;
        }
      }
      return null;
    }
    if (compareResult > 0) {
      if (item.prev.prev != null) {
        choosed = this.treeItemChooser.choose(this.comparator, item.prev, key, element);
        if (choosed == key) {
          return item.prev;
        }
      }
      return null;
    }
    return null;
  }

  private void replace(final TreeItem item, final TreeItem with) {
    this.treeItemChooser.removed(item.getKey());
    with.balanced = item.balanced;
    with.left = item.left;
    if (with.left != null) {
      with.left.parent = with;
    }
    with.right = item.right;
    if (with.right != null) {
      with.right.parent = with;
    }
    with.parent = item.parent;
    if (with.parent != null) {
      if (with.parent.left == item) {
        with.parent.left = with;
      }
      if (with.parent.right == item) {
        with.parent.right = with;
      }
    }
    with.next = item.next;
    if (with.next != null) {
      with.next.prev = with;
    }
    with.prev = item.prev;
    if (with.prev != null) {
      with.prev.next = with;
    }
    if (this.root == item) {
      this.root = with;
    }
    if (this.last == item) {
      this.last = with;
    }
    if (this.first == item) {
      this.first = with;
    }
  }

  @Override
  public void removeAll() {
    TreeItem item = this.first;
    TreeItem next = null;
    while (item != null) {
      this.treeItemChooser.removed(item.getKey());
      next = item.next;
      item.prev = null;
      item.next = null;
      item.right = null;
      item.left = null;
      item.parent = null;
      item = next;
    }
    this.first = null;
    this.last = null;
    this.root = null;
    this.numberOfItems = 0;
  }

  @Override
  public V get(final K element) {
    if (element == null) {
      return null;
    }
    return get(this.root, element);
  }

  private V get(final TreeItem item, final K key) {
    if (item == null) {
      return null;
    }
    if (this.comparator.compare(key, item.getKey()) < 0) {
      return get(item.left, key);
    } else if (this.comparator.compare(key, item.getKey()) > 0) {
      return get(item.right, key);
    } else {
      return item.getElement();
    }
  }

  @Override
  public void remove(final K key) {
    remove(this.root, key);
  }

  public boolean remove(final TreeItem item, final K key) {
    if (item == null) {
      return false;
    }
    if (this.comparator.compare(key, item.getKey()) < 0) {
      if (remove(item.left, key)) {
        return rebalanceLeft(item);
      }
      return false;
    } else if (this.comparator.compare(key, item.getKey()) > 0) {
      if (remove(item.right, key)) {
        return rebalanceRight(item);
      }
      return false;
    } else {
      boolean shorted = false;
      this.treeItemChooser.removed(key);
      if (item.left == null && item.right == null) {
        shorted = removeChildLessItem(item);
      } else if (item.left == null) {
        shorted = removeRightChild(item);
      } else if (item.right == null) {
        shorted = removeLeftChild(item);
      } else {
        shorted = removeItemWithBothChildren(item);
      }
      if (item.next != null && item.prev != null) {
        item.next.prev = item.prev;
        item.prev.next = item.next;
      } else if (item.next != null) {
        item.next.prev = null;
      } else if (item.prev != null) {
        item.prev.next = null;
      }
      return shorted;
    }
  }

  private boolean removeItemWithBothChildren(final TreeItem item) {
    boolean shorted;
    final TreeItem rightLeastItem = getMinItem(item.right);
    shorted = remove(item, rightLeastItem.getKey());
    rightLeastItem.left = item.left;
    if (item.left != null) {
      rightLeastItem.left.parent = rightLeastItem;
    }
    rightLeastItem.right = item.right;
    if (item.right != null) {
      rightLeastItem.right.parent = rightLeastItem;
    }
    rightLeastItem.parent = item.parent;
    if (rightLeastItem.next != null) {
      rightLeastItem.next.prev = rightLeastItem;
    }
    if (rightLeastItem.prev != null) {
      rightLeastItem.prev.next = rightLeastItem;
    }
    if (item.parent != null) {
      if (item.parent.left == item) {
        item.parent.left = rightLeastItem;
      } else {
        item.parent.right = rightLeastItem;
      }
    }
    if (this.first == item) {
      this.first = rightLeastItem;
    }
    if (this.last == item) {
      this.last = rightLeastItem;
    }
    if (this.root == item) {
      this.root = rightLeastItem;
    }
    if (shorted) {
      shorted = rebalanceRight(item);
    }
    return shorted;
  }

  private boolean removeLeftChild(final TreeItem item) {
    item.left.parent = item.parent;
    if (item.parent != null) {
      if (item.parent.left == item) {
        item.parent.left = item.left;
      } else {
        item.parent.right = item.left;
      }
    }
    this.numberOfItems--;
    if (this.first == item) {
      this.first = item.next;
    }
    if (this.root == item) {
      this.root = item.left;
    }
    return true;
  }

  private boolean removeRightChild(final TreeItem item) {
    item.right.parent = item.parent;
    if (item.parent != null) {
      if (item.parent.left == item) {
        item.parent.left = item.right;
      } else {
        item.parent.right = item.right;
      }
    }
    this.numberOfItems--;
    if (this.last == item) {
      this.last = item.prev;
    }
    if (this.root == item) {
      this.root = item.right;
    }
    return true;
  }

  private boolean removeChildLessItem(final TreeItem item) {
    if (item.parent != null) {
      if (item.parent.left == item) {
        item.parent.left = null;
      } else {
        item.parent.right = null;
      }
    }
    this.numberOfItems--;
    if (this.first == item) {
      this.first = item.next;
    }
    if (this.last == item) {
      this.last = item.prev;
    }
    if (this.root == item) {
      this.root = null;
    }
    return true;
  }

  private TreeItem getMinItem(final TreeItem item) {
    if (item.left == null) {
      return item;
    }
    return getMinItem(item.left);
  }

  @Override
  public int size() {
    return this.numberOfItems;
  }

  @Override
  public boolean isEmpty() {
    return this.root == null;
  }

  private boolean rebalanceRight(final TreeItem item) {
    final int balanced = item.left != null
        ? item.left.balanced
        : TreeItem.BALANCED;
    switch (item.balanced) {
      case TreeItem.RIGHT: {
        item.balanced = TreeItem.BALANCED;
        return true;
      }
      case TreeItem.BALANCED: {
        item.balanced = TreeItem.LEFT;
        return false;
      }
      case TreeItem.LEFT: {
        switch (balanced) {
          case TreeItem.RIGHT: {
            leftRightRotation(item);
            return true;
          }
          case TreeItem.BALANCED: {
            final TreeItem dummy = rightRotation(item);
            dummy.right.balanced = TreeItem.LEFT;
            dummy.balanced = TreeItem.RIGHT;
            return false;
          }
          case TreeItem.LEFT: {
            final TreeItem dummy = rightRotation(item);
            dummy.right.balanced = TreeItem.BALANCED;
            dummy.balanced = TreeItem.BALANCED;
            return true;
          }
          default: {
            throw new UnreachableCodeReachedException();
          }
        }
      }
      default: {
        throw new UnreachableCodeReachedException();
      }
    }
  }

  private boolean rebalanceLeft(final TreeItem item) {
    final int balanced = item.right != null
        ? item.right.balanced
        : TreeItem.BALANCED;
    switch (item.balanced) {
      case TreeItem.LEFT: {
        item.balanced = TreeItem.BALANCED;
        return true;
      }
      case TreeItem.BALANCED: {
        item.balanced = TreeItem.RIGHT;
        return false;
      }
      case TreeItem.RIGHT: {
        switch (balanced) {
          case TreeItem.LEFT: {
            rightLeftRotation(item);
            return true;
          }
          case TreeItem.BALANCED: {
            final TreeItem dummy = leftRotation(item);
            dummy.left.balanced = TreeItem.RIGHT;
            dummy.balanced = TreeItem.LEFT;
            return false;
          }
          case TreeItem.RIGHT: {
            final TreeItem dummy = leftRotation(item);
            dummy.left.balanced = TreeItem.BALANCED;
            dummy.balanced = TreeItem.BALANCED;
            return true;
          }
          default: {
            throw new UnreachableCodeReachedException();
          }
        }
      }
      default: {
        throw new UnreachableCodeReachedException();
      }
    }
  }

  private TreeItem leftRotation(final TreeItem item) {
    final TreeItem parent = item.parent;
    final TreeItem result = item.right;
    result.parent = parent;
    if (parent != null) {
      if (parent.left == item) {
        parent.left = result;
      } else {
        parent.right = result;
      }
    }
    item.right = result.left;
    if (item.right != null) {
      item.right.parent = item;
      item.balanced = item.left == null
          ? TreeItem.RIGHT
          : TreeItem.BALANCED;
    } else {
      item.balanced = item.left == null
          ? TreeItem.BALANCED
          : TreeItem.LEFT;
    }
    result.balanced = TreeItem.BALANCED;
    result.left = item;
    result.left.parent = result;
    if (item == this.root) {
      this.root = result;
    }
    return result;
  }

  private TreeItem rightRotation(final TreeItem item) {
    final TreeItem parent = item.parent;
    final TreeItem result = item.left;
    result.parent = parent;
    if (parent != null) {
      if (parent.left == item) {
        parent.left = result;
      } else {
        parent.right = result;
      }
    }
    item.left = result.right;
    if (item.left != null) {
      item.left.parent = item;
      item.balanced = item.right == null
          ? TreeItem.LEFT
          : TreeItem.BALANCED;
    } else {
      item.balanced = item.right == null
          ? TreeItem.BALANCED
          : TreeItem.RIGHT;
    }
    result.balanced = TreeItem.BALANCED;
    result.right = item;
    result.right.parent = result;
    if (item == this.root) {
      this.root = result;
    }
    return result;
  }

  private void leftRightRotation(final TreeItem item) {
    leftRotation(item.left);
    rightRotation(item);
  }

  private void rightLeftRotation(final TreeItem item) {
    rightRotation(item.right);
    leftRotation(item);
  }

  @Override
  public Iterable getValues() {
    return createIterable(new SortedValueIteratorFactory());
  }

  @Override
  public Iterable getDeepSearchFirstValues() {
    return createIterable(new DeepFirstSearchValueIteratorFactory(), this.root);
  }

  @Override
  public Iterable getBreadthSearchFirstValues() {
    return createIterable(new BreadthFirstSearchValueIteratorFactory(), this.root);
  }

  private  TreeIterable createIterable(
      final IObjectIteratorFactory, O> factory,
      final TreeItem item) {
    return new TreeIterable<>(factory, item);
  }

  private  TreeIterable createIterable(final IObjectIteratorFactory, O> factory) {
    return createIterable(factory, this.first);
  }

  @Override
  public Iterable getKeys() {
    return createIterable(new SortedKeyIteratorFactory());
  }

  @Override
  public ITreeWalker getTreeWalker() {
    return new TreeWalker<>(this.first, this.root);
  }

  public ITreeItem getRoot() {
    return this.root;
  }

  public ITreeItem getFirst() {
    return this.first;
  }

  public ITreeItem getLast() {
    return this.last;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy