It's a pretty normal binary tree, except for the fact that one of the nodes may be empty.
I'd like to find a way to output it in a horizontal way (that is, the root node is on the left and expands to the right).
I've had some experience expanding trees vertically (root node at the top, expanding downwards), but I'm not sure where to start, in this case.
Preferably, it would follow these couple of rules:
- If a node has only one child, it can be skipped as redundant (an "end node", with no children, is always displayed)
- All nodes of the same depth must be aligned vertically; all nodes must be to the right of all less-deep nodes and to the left of all deeper nodes.
- Nodes have a string representation which includes their depth.
- Each "end node" has its own unique line; that is, the number of lines is the number of end nodes in the tree, and when an end node is on a line, there may be nothing else on that line after that end node.
- As a consequence of the last rule, the root node might be better off in either the top left or the bottom left corner; top left is preferred.
For example, this is a valid tree, with six end nodes (node is represented by a name, and its depth): EDIT: Please see bottom of question for an alternative, easier rendering
[a0]-----------[b3]------[c5]------[d8] \ \ \----------[e9] \ \----[f5] \-[g1]--------[h4]------[i6] \ \--------------------[j10] \-[k3]
Which represents the vertical, explicit binary tree:
0 a / \ 1 g * / \ \ 2 * * * / \ \ 3 k * b / / \ 4 h * * / \ \ \ 5 * * f c / \ / \ 6 * i * * / / \ 7 * * * / / \ 8 * * d / / 9 * e / 10 j
(branches folded for compactness; *
representing redundant, one-child nodes; note that *
's are actual nodes, storing one child each, just with names omitted here for presentation sake)
(also, to clarify, I'd like to generate the first, horizontal tree; not this vertical tree)
I say language-agnostic because I'm just looking for an algorithm; I say ruby because I'm eventually going to have to implement it in ruby anyway.
Assume that each Node
data structure stores only its id, a left node, and a right node.
A master Tree
class keeps tracks of all nodes and has adequate algorithms to find:
- A node's nth ancestor
- A node's nth descendant
- All end-node descendants of a node, and their count
- The generation of a node
- The lowest common ancestor of two given nodes
I already know:
- The number of end nodes
Anyone have any ideas of where I could start? Should I go for the recursive approach? Iterative? Some Psuedo-code would be pretty cool too, and much appreciated =)
progress
As per walkytalky's suggestion, I decided to see what it would look like to map each "relevant" or significant node to a grid, with the columns being the depth and the rows identifiable by their end nodes. Here is what happens (skipping column 7 because there are no significant nodes in depth 7):
depth: 0 1 2 3 4 5 6 8 9 10 a b c d e f g h i j k
It should be easy enough to generate this grid, with either breadth-first or depth-first searches. Perhaps most trivially by simply keeping a 2D array and placing every significant node found into it, inserting a row for every "second child".
Now, knowing these facts:
- The last node in a row must be an end node
- Children are always to the right, and on the same row or lower, of their parent node.
- All non-end nodes must have exactly two children
- Therefore, all non-end nodes have children that are the first to the right of their column, the first child being on the same row, the second child being n rows below them, where n is the number of nodes on the right side of it.
We can see that, given any valid grid, there is one unambiguous way to "connect the dots", so to speak; there is one unambiguous tree being represented.
Now, the "connecting the dots" is no longer a binary-tree-structure question...it's simply a decoration question. We just need to build an algorithm to properly place the right -
's and \
's where they can go, perhaps following only simple grid/lexicographical rules, instead of binary-tree-structure rules.
Basically, this means that the problem of rendering a tree is now the much simpler problem of rendering a grid, with fancy decorations.
Can anyone suggest any way of formulating these rules? Or maybe a completely different method altogether?
edit
I have conceived of a much, much easier final rendering:
--d0----d1----d3----d4----d5----d6----d8----d9----d10-- => guide line (not rendered) [a0 ]-------[b3 ]-------[c5 ]-------[d8 ] | | \---------------[e9 ] | \---------[f5 ] \---[g1 ]-------[h4 ]-------[i6 ] | \---------------------------[j10] \---[k3 ] --d0----d1----d3----d4----d5----d6----d8----d9----d10-- => guide line (not rendered)
It might be easier to try to create this one, instead of the one I had posted earlier. For one, it preserves a pretty grid shape, and you don't have to fickle with diagonal lines. The rows are all mapped along clearly visible column lines. Unfortunately, it is nowhere near as pretty as the first.