Assume that your Binary tree is represented in the following manner:
public class BinaryTreeModel {
private Object value;
private BinaryTreeModel left;
private BinaryTreeModel right;
public BinaryTreeModel(Object value) {
this.value = value;
}
// standard getters and setters
}
Then the code for the pretty print the tree could be written like this:
For root node:
public String traversePreOrder(BinaryTreeModel root) {
if (root == null) {
return "";
}
StringBuilder sb = new StringBuilder();
sb.append(root.getValue());
String pointerRight = "└──";
String pointerLeft = (root.getRight() != null) ? "├──" : "└──";
traverseNodes(sb, "", pointerLeft, root.getLeft(), root.getRight() != null);
traverseNodes(sb, "", pointerRight, root.getRight(), false);
return sb.toString();
}
for child nodes:
public void traverseNodes(StringBuilder sb, String padding, String pointer, BinaryTreeModel node,
boolean hasRightSibling) {
if (node != null) {
sb.append("\n");
sb.append(padding);
sb.append(pointer);
sb.append(node.getValue());
StringBuilder paddingBuilder = new StringBuilder(padding);
if (hasRightSibling) {
paddingBuilder.append("│ ");
} else {
paddingBuilder.append(" ");
}
String paddingForBoth = paddingBuilder.toString();
String pointerRight = "└──";
String pointerLeft = (node.getRight() != null) ? "├──" : "└──";
traverseNodes(sb, paddingForBoth, pointerLeft, node.getLeft(), node.getRight() != null);
traverseNodes(sb, paddingForBoth, pointerRight, node.getRight(), false);
}
}
Then all you need to do is call the function for the root node like this:
System.out.println(traversePreOrder(root));
This article explains in detail the whole approach - https://www.baeldung.com/java-print-binary-tree-diagram. This idea could be extended to pretty print generic trees
, tries
and much more.
How to do the same for trie?
Assume the helper classes for the trie are Trie
and TrieNode
defined as follows:
public class TrieNode{
public HashMap<Character, TrieNode> children;
public boolean isWord;
public TrieNode() {
children = new HashMap<>();
isWord = false;
}
}
and
public class Trie{
public TrieNode root;
public Trie() {
root = new TrieNode();
}
// Insert method for trie, search method for trie, delete method for trie not shown as they are not relevant
}
Now, to implement pretty print methods, just insert the two methods in the Trie
class:
public String traversePreOrder() {
if (root == null) {
return "";
}
StringBuilder sb = new StringBuilder();
sb.append("○");
Set<Character> childNodeChars = root.children.keySet();
Iterator<Character> iterator = childNodeChars.iterator();
while (iterator.hasNext()) {
Character childC = iterator.next();
if (!iterator.hasNext())
traverseNodes(sb, "", "└──", root, childC, false);
else
traverseNodes(sb, "", "├──", root, childC, true);
}
return sb.toString();
}
private void traverseNodes(StringBuilder sb, String padding, String pointer, TrieNode node, Character c, boolean hasNextSibling) {
sb.append("\n");
sb.append(padding);
sb.append(pointer);
sb.append(c);
sb.append(node.children.get(c).isWord?"(1)":"");
StringBuilder paddingBuilder = new StringBuilder(padding);
paddingBuilder.append(hasNextSibling?"│ ":" ");
String paddingForBoth = paddingBuilder.toString();
TrieNode childNode = node.children.get(c);
if(childNode == null)
return;
Set<Character> childNodeChars = childNode.children.keySet();
Iterator<Character> iterator = childNodeChars.iterator();
while (iterator.hasNext()) {
Character childC = iterator.next();
if (!iterator.hasNext())
traverseNodes(sb, paddingForBoth, "└──", childNode, childC, false);
else
traverseNodes(sb, paddingForBoth, "├──", childNode, childC, true);
}
}