diff --git a/src/main/java/net/abhinavsarkar/algorist/BinarySearchTree.java b/src/main/java/net/abhinavsarkar/algorist/BinarySearchTree.java index bcb00de..be6cf91 100644 --- a/src/main/java/net/abhinavsarkar/algorist/BinarySearchTree.java +++ b/src/main/java/net/abhinavsarkar/algorist/BinarySearchTree.java @@ -4,7 +4,7 @@ import java.util.Optional; public class BinarySearchTree,V> { - private Node root = (Node) EmptyNode.INSTANCE; + private Node root = EmptyNode.instance(); public void insert(K key, V val) { this.root = this.root.insert(key, val); @@ -14,23 +14,31 @@ public class BinarySearchTree,V> return this.root.get(key); } + public void delete(K key) { + this.root.delete(key); + } + public String toString() { return this.root.toStringBuilder(0).toString(); } - public interface Node, V> + private interface Node, V> { Node insert(K key, V val); Optional get(K key); + Node delete(K key); + boolean isEmpty(); + ValueNode toValueNode(); StringBuilder toStringBuilder(int level); + boolean checkIfBST(); } private static class ValueNode,V> implements Node { private K key; private V val; - private Node left = (Node) EmptyNode.INSTANCE; - private Node right = (Node) EmptyNode.INSTANCE; + private Node left = EmptyNode.instance(); + private Node right = EmptyNode.instance(); ValueNode(K key, V val) { if (key == null) { @@ -44,10 +52,22 @@ public class BinarySearchTree,V> this.val = val; } + @Override + public boolean isEmpty() + { + return false; + } + + @Override + public ValueNode toValueNode() + { + return this; + } + @Override public Node insert(K key, V val) { - if (this.key == key) { + if (this.key.equals(key)) { this.val = val; } else if (this.key.compareTo(key) > 0) { this.left = this.left.insert(key, val); @@ -60,7 +80,7 @@ public class BinarySearchTree,V> @Override public Optional get(K key) { - if (this.key == key) { + if (this.key.equals(key)) { return Optional.of(val); } else if (this.key.compareTo(key) > 0) { return this.left.get(key); @@ -69,62 +89,204 @@ public class BinarySearchTree,V> } } + @Override + public Node 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 doDelete() + { + if (this.left.isEmpty()) + { + return this.right.isEmpty() ? EmptyNode.instance() : this.right; + } + else if (this.right.isEmpty()) + { + return this.left; + } + else + { + ValueNode node = deleteSuccessor(); + this.key = node.key; + this.val = node.val; + return this; + } + } + + private ValueNode deleteSuccessor() + { + Node current = this.right; + ValueNode successor = this.right.toValueNode(); + ValueNode successorParent = this.right.toValueNode(); + do + { + ValueNode cur = current.toValueNode(); + Node 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 public StringBuilder toStringBuilder(int level) { - return new StringBuilder() - .append(gutter(level)) - .append("<" + key + ':' + val + ">\n") + 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)); } - private static StringBuilder gutter(int times) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < times; i++) - { - sb.append(' '); - } - return sb.append("|— "); + @Override + public String toString() + { + return "{" + key + ':' + val + '}'; } } - private static class EmptyNode,V> implements Node { + private static class EmptyNode,V> implements Node + { @SuppressWarnings("rawtypes") private static final EmptyNode INSTANCE = new EmptyNode(); + public static ,V> EmptyNode instance() { + return INSTANCE; + } + @Override public Node insert(K key, V val) { return new ValueNode<>(key, val); } + @Override + public boolean isEmpty() + { + return true; + } + + @Override + public ValueNode toValueNode() + { + throw new UnsupportedOperationException(); + } + @Override public Optional get(K key) { return Optional.empty(); } + @Override + public Node delete(K key) { + return this; + } + + @Override + public boolean checkIfBST() + { + return true; + } + @Override public StringBuilder toStringBuilder(int level) { - return new StringBuilder(0); + return new StringBuilder().append(gutter(level)).append("\n"); + } + + @Override + public String toString() + { + return ""; } } + 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) { BinarySearchTree bst = new BinarySearchTree<>(); - bst.insert("b", "barista"); - bst.insert("a", "abhinav"); + bst.insert("q", "barista"); + bst.insert("y", "duck"); + bst.insert("k", "carpool"); + bst.insert("p", "duck"); 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.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("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()); } }