Adds AVL tree rendering

master
Abhinav Sarkar 2019-07-05 11:25:07 +05:30
parent 6f0227e188
commit 511950f24e
2 changed files with 100 additions and 34 deletions

View File

@ -20,5 +20,11 @@
</plugins>
</build>
<dependencies>
<dependency>
<groupId>guru.nidi</groupId>
<artifactId>graphviz-java</artifactId>
<version>0.8.8</version>
</dependency>
</dependencies>
</project>

View File

@ -1,13 +1,24 @@
package net.abhinavsarkar.algorist;
import guru.nidi.graphviz.engine.Format;
import guru.nidi.graphviz.engine.Graphviz;
import guru.nidi.graphviz.model.MutableGraph;
import guru.nidi.graphviz.model.MutableNode;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Stack;
import static guru.nidi.graphviz.model.Factory.*;
public class AVLTree<K extends Comparable<K>,V> implements Iterable<AVLTree.Entry<K,V>>
{
private Node<K,V> root = EmptyNode.instance();
private Node<K,V> root;
public AVLTree(boolean rebalance) {
root = EmptyNode.instance(rebalance);
}
public void insert(K key, V val) {
this.root = this.root.insert(key, val);
@ -41,6 +52,13 @@ public class AVLTree<K extends Comparable<K>,V> implements Iterable<AVLTree.Entr
return this.root.toStringBuilder(0).toString();
}
public void renderToPNG(String fileName) throws IOException
{
MutableGraph graph = mutGraph("AVLTree").setDirected(true);
this.root.addToGraph(graph);
Graphviz.fromGraph(graph).height(1000).render(Format.PNG).toFile(new File(fileName));
}
@Override
public Iterator<Entry<K, V>> iterator()
{
@ -59,6 +77,7 @@ public class AVLTree<K extends Comparable<K>,V> implements Iterable<AVLTree.Entr
Optional<K> predecessor(K key);
boolean isEmpty();
StringBuilder toStringBuilder(int level);
Optional<String> addToGraph(MutableGraph graph);
boolean checkIfBST();
boolean checkIfAVLT();
@ -73,13 +92,15 @@ public class AVLTree<K extends Comparable<K>,V> implements Iterable<AVLTree.Entr
private static class ValueNode<K extends Comparable<K>,V> implements Node<K, V>
{
private final boolean rebalance;
private K key;
private V val;
private int height;
private Node<K,V> left = EmptyNode.instance();
private Node<K,V> right = EmptyNode.instance();
private Node<K,V> left;
private Node<K,V> right;
ValueNode(K key, V val) {
ValueNode(K key, V val, boolean rebalance) {
this.rebalance = rebalance;
if (key == null) {
throw new IllegalArgumentException("Key cannot be null");
}
@ -90,6 +111,8 @@ public class AVLTree<K extends Comparable<K>,V> implements Iterable<AVLTree.Entr
this.key = key;
this.val = val;
this.height = 1;
left = EmptyNode.instance(rebalance);
right = EmptyNode.instance(rebalance);
}
@Override
@ -158,7 +181,7 @@ public class AVLTree<K extends Comparable<K>,V> implements Iterable<AVLTree.Entr
{
if (this.left.isEmpty())
{
return this.right.isEmpty() ? EmptyNode.instance() : this.right;
return this.right.isEmpty() ? EmptyNode.instance(rebalance) : this.right;
}
else if (this.right.isEmpty())
{
@ -196,6 +219,10 @@ public class AVLTree<K extends Comparable<K>,V> implements Iterable<AVLTree.Entr
private ValueNode<K, V> rebalance()
{
this.resetHeight();
if (!rebalance) {
return this;
}
int balance = this.balance();
if (balance > 1) {
ValueNode<K, V> l = this.left.toValueNode();
@ -320,15 +347,42 @@ public class AVLTree<K extends Comparable<K>,V> implements Iterable<AVLTree.Entr
{
return "{" + key + ':' + val + '}';
}
@Override
public Optional<String> addToGraph(MutableGraph graph)
{
String name = getGraphNodeName();
MutableNode node = mutNode(name);
graph.add(node);
left.addToGraph(graph).ifPresent(n -> graph.add(node.addLink(mutNode(n))));
right.addToGraph(graph).ifPresent(n -> graph.add(node.addLink(mutNode(n))));
return Optional.of(name);
}
private String getGraphNodeName()
{
return this.height + ":" + this.key;
}
}
private static class EmptyNode<K extends Comparable<K>,V> implements Node<K,V>
{
@SuppressWarnings("rawtypes")
private static final EmptyNode INSTANCE = new EmptyNode();
private static final EmptyNode TRUE_INSTANCE = new EmptyNode(true);
public static <K extends Comparable<K>,V> EmptyNode<K,V> instance() {
return INSTANCE;
@SuppressWarnings("rawtypes")
private static final EmptyNode FALSE_INSTANCE = new EmptyNode(false);
private final boolean rebalance;
private EmptyNode(boolean rebalance)
{
this.rebalance = rebalance;
}
@SuppressWarnings("unchecked")
public static <K extends Comparable<K>,V> EmptyNode<K,V> instance(boolean rebalance) {
return rebalance ? TRUE_INSTANCE : FALSE_INSTANCE;
}
@Override
@ -340,7 +394,7 @@ public class AVLTree<K extends Comparable<K>,V> implements Iterable<AVLTree.Entr
@Override
public Node<K, V> insert(K key, V val)
{
return new ValueNode<>(key, val);
return new ValueNode<>(key, val, rebalance);
}
@Override
@ -403,6 +457,11 @@ public class AVLTree<K extends Comparable<K>,V> implements Iterable<AVLTree.Entr
{
return "<NULL>";
}
@Override
public Optional<String> addToGraph(MutableGraph graph) {
return Optional.empty();
}
}
private static StringBuilder gutter(int times) {
@ -485,39 +544,40 @@ public class AVLTree<K extends Comparable<K>,V> implements Iterable<AVLTree.Entr
}
}
public static void main(String[] args)
public static void main(String[] args) throws IOException
{
AVLTree<String, String> bst = new AVLTree<>();
bst.insert("q", "barista");
bst.insert("y", "duck");
bst.insert("k", "carpool");
bst.insert("p", "duck");
AVLTree<String, String> bst = new AVLTree<>(true);
bst.insert("a", "barista");
bst.insert("b", "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("e", "carpool");
bst.insert("f", "barista");
bst.insert("g", "duck");
bst.insert("h", "abhinav");
bst.insert("i", "abhinav");
bst.insert("j", "duck");
bst.insert("k", "carpool");
bst.insert("l", "carpool");
bst.insert("m", "abhinav");
bst.insert("n", "duck");
bst.insert("o", "abhinav");
bst.insert("p", "abhinav");
bst.insert("q", "carpool");
bst.insert("r", "barista");
bst.insert("s", "duck");
bst.insert("t", "barista");
bst.insert("u", "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("w", "duck");
bst.insert("x", "barista");
bst.insert("y", "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.root.checkIfAVLT());
bst.renderToPNG("AVLTree.png");
System.out.println(bst.get("a"));
System.out.println(bst.get("b"));