Adds BST delete

master
Abhinav Sarkar 2019-06-29 18:52:15 +05:30
parent 9173f20491
commit 12edd9e409
1 changed files with 184 additions and 22 deletions

View File

@ -4,7 +4,7 @@ import java.util.Optional;
public class BinarySearchTree<K extends Comparable<K>,V> public class BinarySearchTree<K extends Comparable<K>,V>
{ {
private Node<K,V> root = (Node<K,V>) EmptyNode.INSTANCE; private Node<K,V> root = EmptyNode.instance();
public void insert(K key, V val) { public void insert(K key, V val) {
this.root = this.root.insert(key, val); this.root = this.root.insert(key, val);
@ -14,23 +14,31 @@ public class BinarySearchTree<K extends Comparable<K>,V>
return this.root.get(key); return this.root.get(key);
} }
public void delete(K key) {
this.root.delete(key);
}
public String toString() { public String toString() {
return this.root.toStringBuilder(0).toString(); return this.root.toStringBuilder(0).toString();
} }
public interface Node<K extends Comparable<K>, V> private interface Node<K extends Comparable<K>, V>
{ {
Node<K,V> insert(K key, V val); Node<K,V> insert(K key, V val);
Optional<V> get(K key); Optional<V> get(K key);
Node<K,V> delete(K key);
boolean isEmpty();
ValueNode<K,V> toValueNode();
StringBuilder toStringBuilder(int level); StringBuilder toStringBuilder(int level);
boolean checkIfBST();
} }
private static class ValueNode<K extends Comparable<K>,V> implements Node<K, V> private static class ValueNode<K extends Comparable<K>,V> implements Node<K, V>
{ {
private K key; private K key;
private V val; private V val;
private Node<K,V> left = (Node<K,V>) EmptyNode.INSTANCE; private Node<K,V> left = EmptyNode.instance();
private Node<K,V> right = (Node<K,V>) EmptyNode.INSTANCE; private Node<K,V> right = EmptyNode.instance();
ValueNode(K key, V val) { ValueNode(K key, V val) {
if (key == null) { if (key == null) {
@ -44,10 +52,22 @@ public class BinarySearchTree<K extends Comparable<K>,V>
this.val = val; this.val = val;
} }
@Override
public boolean isEmpty()
{
return false;
}
@Override
public ValueNode<K, V> toValueNode()
{
return this;
}
@Override @Override
public Node<K, V> insert(K key, V val) public Node<K, V> insert(K key, V val)
{ {
if (this.key == key) { if (this.key.equals(key)) {
this.val = val; this.val = val;
} else if (this.key.compareTo(key) > 0) { } else if (this.key.compareTo(key) > 0) {
this.left = this.left.insert(key, val); this.left = this.left.insert(key, val);
@ -60,7 +80,7 @@ public class BinarySearchTree<K extends Comparable<K>,V>
@Override @Override
public Optional<V> get(K key) public Optional<V> get(K key)
{ {
if (this.key == key) { if (this.key.equals(key)) {
return Optional.of(val); return Optional.of(val);
} else if (this.key.compareTo(key) > 0) { } else if (this.key.compareTo(key) > 0) {
return this.left.get(key); return this.left.get(key);
@ -69,62 +89,204 @@ public class BinarySearchTree<K extends Comparable<K>,V>
} }
} }
@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 boolean checkIfBST()
{
return this.left.checkIfBST() && this.right.checkIfBST()
&& isKeyMoreThanLeftKey() && isKeyLessThanRightKey();
}
private boolean isKeyLessThanRightKey()
{
return this.right.isEmpty() || this.key.compareTo(this.right.toValueNode().key) < 0;
}
private boolean isKeyMoreThanLeftKey()
{
return this.left.isEmpty() || this.key.compareTo(this.left.toValueNode().key) > 0;
}
@Override @Override
public StringBuilder toStringBuilder(int level) { public StringBuilder toStringBuilder(int level) {
return new StringBuilder() return new StringBuilder().append(gutter(level))
.append(gutter(level)) .append('<')
.append("<" + key + ':' + val + ">\n") .append(key)
.append(':')
.append(val)
.append(">\n")
.append(this.left.toStringBuilder(level + 1)) .append(this.left.toStringBuilder(level + 1))
.append(this.right.toStringBuilder(level + 1)); .append(this.right.toStringBuilder(level + 1));
} }
private static StringBuilder gutter(int times) { @Override
StringBuilder sb = new StringBuilder(); public String toString()
for (int i = 0; i < times; i++) {
{ return "{" + key + ':' + val + '}';
sb.append(' ');
}
return sb.append("|— ");
} }
} }
private static class EmptyNode<K extends Comparable<K>,V> implements Node<K,V> { private static class EmptyNode<K extends Comparable<K>,V> implements Node<K,V>
{
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
private static final EmptyNode INSTANCE = new EmptyNode(); private static final EmptyNode INSTANCE = new EmptyNode();
public static <K extends Comparable<K>,V> EmptyNode<K,V> instance() {
return INSTANCE;
}
@Override @Override
public Node<K, V> insert(K key, V val) public Node<K, V> insert(K key, V val)
{ {
return new ValueNode<>(key, val); return new ValueNode<>(key, val);
} }
@Override
public boolean isEmpty()
{
return true;
}
@Override
public ValueNode<K, V> toValueNode()
{
throw new UnsupportedOperationException();
}
@Override @Override
public Optional<V> get(K key) public Optional<V> get(K key)
{ {
return Optional.empty(); return Optional.empty();
} }
@Override
public Node<K, V> delete(K key) {
return this;
}
@Override
public boolean checkIfBST()
{
return true;
}
@Override @Override
public StringBuilder toStringBuilder(int level) public StringBuilder toStringBuilder(int level)
{ {
return new StringBuilder(0); 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 void main(String[] args) public static void main(String[] args)
{ {
BinarySearchTree<String, String> bst = new BinarySearchTree<>(); BinarySearchTree<String, String> bst = new BinarySearchTree<>();
bst.insert("b", "barista"); bst.insert("q", "barista");
bst.insert("a", "abhinav"); bst.insert("y", "duck");
bst.insert("k", "carpool");
bst.insert("p", "duck");
bst.insert("c", "carpool"); bst.insert("c", "carpool");
bst.insert("d", "carl"); 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);
System.out.println(bst.root.checkIfBST());
System.out.println(bst.get("a")); System.out.println(bst.get("a"));
System.out.println(bst.get("b")); System.out.println(bst.get("b"));
System.out.println(bst.get("c")); System.out.println(bst.get("c"));
System.out.println(bst.get("d")); System.out.println(bst.get("d"));
System.out.println(bst.get("z")); 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());
} }
} }