package com.jujutsu.tsne.barneshut; import java.util.ArrayList; import java.util.Collections; import java.util.List; import com.jujutsu.tsne.barneshut.VpTree.Node; @SuppressWarnings("rawtypes") public class TreePrinter { public interface AdditionalInfoProvider { public String provideInfo(Node node); } AdditionalInfoProvider provider; public TreePrinter() { } public TreePrinter(AdditionalInfoProvider additionalInfoProvider) { this.provider = additionalInfoProvider; } public <T extends Comparable<?>> void printNode(Node root) { int maxLevel = maxLevel(root); printNodeInternal(Collections.singletonList(root), 1, maxLevel); } private <T extends Comparable<?>> void printNodeInternal(List<Node> nodes, int level, int maxLevel) { if (nodes.isEmpty() || isAllElementsNull(nodes)) return; int floor = maxLevel - level; int endgeLines = (int) Math.pow(2, (Math.max(floor - 1, 0))); int firstSpaces = (int) Math.pow(2, (floor)) - 1; int betweenSpaces = (int) Math.pow(2, (floor + 1)) - 1; printWhitespaces(firstSpaces); List<Node> newNodes = new ArrayList<Node>(); for (Node node : nodes) { if (node != null) { System.out.print(node.index); if(provider!=null) { System.out.print("(" +provider.provideInfo(node) +")"); } newNodes.add(node.getLeft()); newNodes.add(node.getRight()); } else { newNodes.add(null); newNodes.add(null); System.out.print(" "); } printWhitespaces(betweenSpaces); } System.out.println(""); for (int i = 1; i <= endgeLines; i++) { for (int j = 0; j < nodes.size(); j++) { printWhitespaces(firstSpaces - i); if (nodes.get(j) == null) { printWhitespaces(endgeLines + endgeLines + i + 1); continue; } if (nodes.get(j).getLeft() != null) System.out.print("/"); else printWhitespaces(1); printWhitespaces(i + i - 1); if (nodes.get(j).getRight() != null) System.out.print("\\"); else printWhitespaces(1); printWhitespaces(endgeLines + endgeLines - i); } System.out.println(""); } printNodeInternal(newNodes, level + 1, maxLevel); } private void printWhitespaces(int count) { for (int i = 0; i < count; i++) System.out.print(" "); } private <T extends Comparable<?>> int maxLevel(Node node) { if (node == null) return 0; return Math.max(maxLevel(node.getLeft()), maxLevel(node.getRight())) + 1; } private <T> boolean isAllElementsNull(List<T> list) { for (Object object : list) { if (object != null) return false; } return true; } public void printTreeHorizontal(Node node) { if (node.getRight() != null) { printTree(node.getRight(), true, ""); } printNodeValue(node); if (node.getLeft() != null) { printTree(node.getLeft(), false, ""); } } private void printNodeValue(Node node) { if (node == null) { System.out.print("<null>"); } else { System.out.print(node.index); if(provider!=null) { System.out.print("(" +provider.provideInfo(node) +")"); } } System.out.print('\n'); } // use string and not stringbuffer on purpose as we need to change the indent at each recursion private void printTree(Node node, boolean isRight, String indent) { if (node.getRight() != null) { printTree(node.getRight(), true, indent + (isRight ? " " : " | ")); } System.out.print(indent); if (isRight) { System.out.print(" /"); } else { System.out.print(" \\"); } System.out.print("----- "); printNodeValue(node); if (node.getLeft() != null) { printTree(node.getLeft(), false, indent + (isRight ? " | " : " ")); } } }