algorist/src/main/java/net/abhinavsarkar/algorist/BinarySearchTree.java

504 lines
13 KiB
Java

package net.abhinavsarkar.algorist;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Stack;
public class BinarySearchTree<K extends Comparable<K>,V> implements Iterable<BinarySearchTree.Entry<K,V>>
{
private Node<K,V> root = EmptyNode.instance();
public void insert(K key, V val) {
this.root = this.root.insert(key, val);
}
public Optional<V> get(K key) {
return this.root.get(key);
}
public void delete(K key) {
this.root.delete(key);
}
public Optional<K> minimum() {
return this.root.minimum();
}
public Optional<K> maximum() {
return this.root.maximum();
}
public Optional<K> successor(K key) {
return this.root.successor(key);
}
public Optional<K> predecessor(K key) {
return this.root.predecessor(key);
}
public String toString() {
return this.root.toStringBuilder(0).toString();
}
@Override
public Iterator<Entry<K, V>> iterator()
{
return new PreOrderIterator<>(this.root);
}
private interface Node<K extends Comparable<K>, V>
{
Node<K,V> insert(K key, V val);
Optional<V> get(K key);
Node<K,V> delete(K key);
Optional<K> minimum();
Optional<K> maximum();
Optional<K> successor(K key);
Optional<K> predecessor(K key);
boolean isEmpty();
StringBuilder toStringBuilder(int level);
boolean checkIfBST();
default ValueNode<K,V> toValueNode() {
if (this.isEmpty()) {
throw new UnsupportedOperationException();
} else {
return (ValueNode<K, V>) this;
}
}
}
private static class ValueNode<K extends Comparable<K>,V> implements Node<K, V>
{
private K key;
private V val;
private Node<K,V> left = EmptyNode.instance();
private Node<K,V> right = EmptyNode.instance();
ValueNode(K key, V val) {
if (key == null) {
throw new IllegalArgumentException("Key cannot be null");
}
if (val == null) {
throw new IllegalArgumentException("Value cannot be null");
}
this.key = key;
this.val = val;
}
@Override
public boolean isEmpty()
{
return false;
}
@Override
public Node<K, V> insert(K key, V val)
{
if (this.key.equals(key)) {
this.val = val;
} else if (this.key.compareTo(key) > 0) {
this.left = this.left.insert(key, val);
} else {
this.right = this.right.insert(key, val);
}
return this;
}
@Override
public Optional<V> get(K key)
{
if (this.key.equals(key)) {
return Optional.of(val);
} else if (this.key.compareTo(key) > 0) {
return this.left.get(key);
} else {
return this.right.get(key);
}
}
@Override
public Node<K,V> delete(K key)
{
if (this.key.equals(key)) {
return doDelete();
} else if (this.key.compareTo(key) > 0) {
this.left = this.left.delete(key);
} else {
this.right = this.right.delete(key);
}
return this;
}
private Node<K, V> doDelete()
{
if (this.left.isEmpty())
{
return this.right.isEmpty() ? EmptyNode.instance() : this.right;
}
else if (this.right.isEmpty())
{
return this.left;
}
else
{
ValueNode<K, V> node = deleteSuccessor();
this.key = node.key;
this.val = node.val;
return this;
}
}
private ValueNode<K, V> deleteSuccessor()
{
Node<K,V> current = this.right;
ValueNode<K,V> successor = this.right.toValueNode();
ValueNode<K,V> successorParent = this.right.toValueNode();
do
{
ValueNode<K, V> cur = current.toValueNode();
Node<K, V> curLeft = cur.left;
if (!curLeft.isEmpty()) {
successor = curLeft.toValueNode();
successorParent = cur;
}
current = curLeft;
} while (!current.isEmpty());
successorParent.left = EmptyNode.instance();
return successor;
}
@Override
public Optional<K> minimum()
{
return Optional.of(this.left.minimum().orElse(this.key));
}
@Override
public Optional<K> maximum()
{
return Optional.of(this.right.maximum().orElse(this.key));
}
@Override
public Optional<K> successor(K key)
{
if (this.key.compareTo(key) > 0) {
return Optional.of(this.left.successor(key).orElse(this.key));
} else {
return this.right.successor(key);
}
}
@Override
public Optional<K> predecessor(K key)
{
if (this.key.compareTo(key) < 0) {
return Optional.of(this.right.predecessor(key).orElse(this.key));
} else {
return this.left.predecessor(key);
}
}
@Override
public boolean checkIfBST()
{
return this.left.checkIfBST() && this.right.checkIfBST()
&& isKeyMoreThanLeftKey() && isKeyLessThanRightKey();
}
private boolean isKeyMoreThanLeftKey()
{
return this.left.isEmpty() || this.key.compareTo(this.left.toValueNode().key) > 0;
}
private boolean isKeyLessThanRightKey()
{
return this.right.isEmpty() || this.key.compareTo(this.right.toValueNode().key) < 0;
}
@Override
public StringBuilder toStringBuilder(int level) {
return new StringBuilder().append(gutter(level))
.append('<')
.append(key)
.append(':')
.append(val)
.append(">\n")
.append(this.left.toStringBuilder(level + 1))
.append(this.right.toStringBuilder(level + 1));
}
@Override
public String toString()
{
return "{" + key + ':' + val + '}';
}
}
private static class EmptyNode<K extends Comparable<K>,V> implements Node<K,V>
{
@SuppressWarnings("rawtypes")
private static final EmptyNode INSTANCE = new EmptyNode();
public static <K extends Comparable<K>,V> EmptyNode<K,V> instance() {
return INSTANCE;
}
@Override
public Node<K, V> insert(K key, V val)
{
return new ValueNode<>(key, val);
}
@Override
public boolean isEmpty()
{
return true;
}
@Override
public Optional<V> get(K key)
{
return Optional.empty();
}
@Override
public Node<K, V> delete(K key) {
return this;
}
@Override
public Optional<K> minimum()
{
return Optional.empty();
}
@Override
public Optional<K> maximum()
{
return Optional.empty();
}
public Optional<K> successor(K key) {
return Optional.empty();
}
public Optional<K> predecessor(K key) {
return Optional.empty();
}
@Override
public boolean checkIfBST()
{
return true;
}
@Override
public StringBuilder toStringBuilder(int level)
{
return new StringBuilder().append(gutter(level)).append("<NULL>\n");
}
@Override
public String toString()
{
return "<NULL>";
}
}
private static StringBuilder gutter(int times) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < times; i++)
{
sb.append('│');
}
return sb.append("├ ");
}
public static class Entry<K, V> {
private K key;
private V val;
public Entry(K key, V val) {
this.key = key;
this.val = val;
}
public K getKey()
{
return key;
}
public V getVal()
{
return val;
}
public String toString() {
return "<" + key + "," + val + ">";
}
}
private static class InOrderIterator<K extends Comparable<K>, V> implements Iterator<Entry<K, V>>
{
private final Stack<Node<K, V>> stack = new Stack<>();
public InOrderIterator(Node<K, V> node)
{
pushToStack(node);
}
@Override
public boolean hasNext()
{
return !(this.stack.isEmpty() || this.stack.peek().isEmpty());
}
/*
inorder(a):
if a.left != null:
yield inorder(a.left)
yield a.val
if a.right != null:
yield inorder(a.right)
*/
@Override
public Entry<K, V> next()
{
if (!hasNext()) {
throw new NoSuchElementException();
}
ValueNode<K, V> vNode = this.stack.pop().toValueNode();
pushToStack(vNode.right);
return new Entry<>(vNode.key, vNode.val);
}
private void pushToStack(Node<K, V> node)
{
Node<K, V> current = node;
while (!current.isEmpty())
{
this.stack.push(current);
current = current.toValueNode().left;
}
}
}
private static class PreOrderIterator<K extends Comparable<K>, V> implements Iterator<Entry<K, V>>
{
private final Stack<Node<K, V>> stack = new Stack<>();
private Node<K, V> current;
public PreOrderIterator(Node<K, V> node)
{
current = node;
}
@Override
public boolean hasNext()
{
return !this.current.isEmpty();
}
/*
preorder(a):
yield a.val
if a.left != null:
yield preorder(a.left)
if a.right != null:
yield preorder(a.right)
*/
@Override
public Entry<K, V> next()
{
if (!hasNext()) {
throw new NoSuchElementException();
}
ValueNode<K, V> vNode = current.toValueNode();
if (!vNode.left.isEmpty()) {
stack.push(current);
current = vNode.left;
} else if (!vNode.right.isEmpty()) {
current = vNode.right;
} else if (stack.isEmpty()){
current = EmptyNode.instance();
} else {
do {
Node<K, V> node = stack.pop();
current = node.toValueNode().right;
} while (current.isEmpty());
}
return new Entry<>(vNode.key, vNode.val);
}
}
public static void main(String[] args)
{
BinarySearchTree<String, String> bst = new BinarySearchTree<>();
bst.insert("q", "barista");
bst.insert("y", "duck");
bst.insert("k", "carpool");
bst.insert("p", "duck");
bst.insert("c", "carpool");
bst.insert("e", "barista");
bst.insert("d", "duck");
bst.insert("f", "abhinav");
bst.insert("j", "abhinav");
bst.insert("t", "duck");
bst.insert("s", "carpool");
bst.insert("g", "carpool");
bst.insert("v", "abhinav");
bst.insert("h", "duck");
bst.insert("r", "abhinav");
bst.insert("n", "abhinav");
bst.insert("w", "carpool");
bst.insert("u", "barista");
bst.insert("z", "duck");
bst.insert("b", "barista");
bst.insert("o", "carpool");
bst.insert("a", "abhinav");
bst.insert("l", "duck");
bst.insert("m", "barista");
bst.insert("i", "barista");
bst.insert("x", "duck");
System.out.println(bst);
System.out.println(bst.root.checkIfBST());
System.out.println(bst.get("a"));
System.out.println(bst.get("b"));
System.out.println(bst.get("c"));
System.out.println(bst.get("d"));
System.out.println(bst.get("A"));
bst.delete("q");
bst.delete("r");
bst.delete("c");
System.out.println(bst);
System.out.println(bst.root.checkIfBST());
System.out.println(bst.minimum());
System.out.println(bst.maximum());
System.out.println(bst.successor("a"));
System.out.println(bst.successor("z"));
System.out.println(bst.successor("q"));
System.out.println(bst.predecessor("a"));
System.out.println(bst.predecessor("z"));
System.out.println(bst.predecessor("q"));
for (Entry<String,String> entry: bst) {
System.out.println(entry.key);
}
}
}