-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBinaryTreePrinter.java
201 lines (174 loc) · 8.25 KB
/
BinaryTreePrinter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
A class to print a text representation of a Binary Tree.
Inspired by: https://github.com/billvanyo/tree_printer
@author: Aonghus Lawlor aonghus.lawlor@ucd.ie
*/
public class BinaryTreePrinter< N > {
private boolean squareBranches = true;
private boolean lrAgnostic = false;
private int hspace = 2;
//private int tspace = 1;
private BinaryTree<N> tree;
public BinaryTreePrinter(BinaryTree<N> tree) {
this.tree = tree;
}
public String print() {
List<TreeLine> treeLines = buildTreeLines(tree.root());
return printTreeLines(treeLines);
//return tree.toString();
}
private static class TreeLine {
String line;
int leftOffset;
int rightOffset;
TreeLine(String line, int leftOffset, int rightOffset) {
this.line = line;
this.leftOffset = leftOffset;
this.rightOffset = rightOffset;
}
}
private String printTreeLines(List<TreeLine> treeLines) {
StringBuilder sb = new StringBuilder();
if (treeLines.size() > 0) {
int minLeftOffset = minLeftOffset(treeLines);
int maxRightOffset = maxRightOffset(treeLines);
for (TreeLine treeLine : treeLines) {
int leftSpaces = -(minLeftOffset - treeLine.leftOffset);
int rightSpaces = maxRightOffset - treeLine.rightOffset;
sb.append(spaces(leftSpaces)).append(treeLine.line).append(spaces(rightSpaces));
sb.append("\n");
}
}
return sb.toString();
}
private static int minLeftOffset(List<TreeLine> treeLines) {
return treeLines.stream().mapToInt(l -> l.leftOffset).min().orElse(0);
}
private static int maxRightOffset(List<TreeLine> treeLines) {
return treeLines.stream().mapToInt(l -> l.rightOffset).max().orElse(0);
}
private List<TreeLine> buildTreeLines(Position<N> root) {
if (root == null)
return Collections.emptyList();
else {
String rootLabel = root.toString();//getLabel.apply(root);
//List<TreeLine> leftTreeLines = buildTreeLines(getLeft.apply(root));
//List<TreeLine> rightTreeLines = buildTreeLines(getRight.apply(root));
List<TreeLine> leftTreeLines = buildTreeLines(tree.left(root));
List<TreeLine> rightTreeLines = buildTreeLines(tree.right(root));
int leftCount = leftTreeLines.size();
int rightCount = rightTreeLines.size();
int minCount = Math.min(leftCount, rightCount);
int maxCount = Math.max(leftCount, rightCount);
// The left and right subtree print representations have jagged edges, and we
// essentially we have to
// figure out how close together we can bring the left and right roots so that
// the edges just meet on
// some line. Then we add hspace, and round up to next odd number.
int maxRootSpacing = 0;
for (int i = 0; i < minCount; i++) {
int spacing = leftTreeLines.get(i).rightOffset - rightTreeLines.get(i).leftOffset;
if (spacing > maxRootSpacing)
maxRootSpacing = spacing;
}
int rootSpacing = maxRootSpacing + hspace;
if (rootSpacing % 2 == 0)
rootSpacing++;
// rootSpacing is now the number of spaces between the roots of the two subtrees
List<TreeLine> allTreeLines = new ArrayList<>();
// add the root and the two branches leading to the subtrees
allTreeLines.add(new TreeLine(rootLabel, -(rootLabel.length() - 1) / 2, rootLabel.length() / 2));
// also calculate offset adjustments for left and right subtrees
int leftTreeAdjust = 0;
int rightTreeAdjust = 0;
if (leftTreeLines.isEmpty()) {
if (!rightTreeLines.isEmpty()) {
// there's a right subtree only
if (squareBranches) {
if (lrAgnostic) {
allTreeLines.add(new TreeLine("\u2502", 0, 0));
} else {
allTreeLines.add(new TreeLine("\u2514\u2510", 0, 1));
rightTreeAdjust = 1;
}
} else {
allTreeLines.add(new TreeLine("\\", 1, 1));
rightTreeAdjust = 2;
}
}
} else if (rightTreeLines.isEmpty()) {
// there's a left subtree only
if (squareBranches) {
if (lrAgnostic) {
allTreeLines.add(new TreeLine("\u2502", 0, 0));
} else {
allTreeLines.add(new TreeLine("\u250C\u2518", -1, 0));
leftTreeAdjust = -1;
}
} else {
allTreeLines.add(new TreeLine("/", -1, -1));
leftTreeAdjust = -2;
}
} else {
// there's a left and right subtree
if (squareBranches) {
int adjust = (rootSpacing / 2) + 1;
String horizontal = String.join("", Collections.nCopies(rootSpacing / 2, "\u2500"));
String branch = "\u250C" + horizontal + "\u2534" + horizontal + "\u2510";
allTreeLines.add(new TreeLine(branch, -adjust, adjust));
rightTreeAdjust = adjust;
leftTreeAdjust = -adjust;
} else {
if (rootSpacing == 1) {
allTreeLines.add(new TreeLine("/ \\", -1, 1));
rightTreeAdjust = 2;
leftTreeAdjust = -2;
} else {
for (int i = 1; i < rootSpacing; i += 2) {
String branches = "/" + spaces(i) + "\\";
allTreeLines.add(new TreeLine(branches, -((i + 1) / 2), (i + 1) / 2));
}
rightTreeAdjust = (rootSpacing / 2) + 1;
leftTreeAdjust = -((rootSpacing / 2) + 1);
}
}
}
// now add joined lines of subtrees, with appropriate number of separating
// spaces, and adjusting offsets
for (int i = 0; i < maxCount; i++) {
TreeLine leftLine, rightLine;
if (i >= leftTreeLines.size()) {
// nothing remaining on left subtree
rightLine = rightTreeLines.get(i);
rightLine.leftOffset += rightTreeAdjust;
rightLine.rightOffset += rightTreeAdjust;
allTreeLines.add(rightLine);
} else if (i >= rightTreeLines.size()) {
// nothing remaining on right subtree
leftLine = leftTreeLines.get(i);
leftLine.leftOffset += leftTreeAdjust;
leftLine.rightOffset += leftTreeAdjust;
allTreeLines.add(leftLine);
} else {
leftLine = leftTreeLines.get(i);
rightLine = rightTreeLines.get(i);
int adjustedRootSpacing = (rootSpacing == 1 ? (squareBranches ? 1 : 3) : rootSpacing);
TreeLine combined = new TreeLine(
leftLine.line + spaces(adjustedRootSpacing - leftLine.rightOffset + rightLine.leftOffset)
+ rightLine.line,
leftLine.leftOffset + leftTreeAdjust, rightLine.rightOffset + rightTreeAdjust);
allTreeLines.add(combined);
}
}
return allTreeLines;
}
}
private static String spaces(int n) {
return String.join("", Collections.nCopies(n, " "));
}
public static void main(String[] args) {
}
}