-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathreingold_thread.py
128 lines (91 loc) · 3.03 KB
/
reingold_thread.py
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
from sys import stdout
class DrawTree:
def __init__(self, tree, depth=-1):
self.x = -1
self.y = depth
self.tree = tree
self.children = []
self.thread = None
def left(self):
return self.thread or len(self.children) and self.children[0]
def right(self):
return self.thread or len(self.children) and self.children[-1]
# traverse to the bottom of the tree, and place the leaves at an arbitrary
# x coordinate
# if the node is a parent, draw its subtrees, then shift the right one as close
# to the left as possible
# place the parent in the middle of the two trees.
def reingold_tilford(tree, depth=0):
dt = DrawTree(tree, depth)
if len(tree) == 0:
dt.x = 0
return dt
if len(tree) == 1:
dt.children = [reingold_tilford(tree[0], depth + 1)]
dt.x = dt.children[0].x
return dt
left = reingold_tilford(tree[0], depth + 1)
right = reingold_tilford(tree[1], depth + 1)
dt.children = [left, right]
dt.x = fix_subtrees(left, right)
return dt
# place the right subtree as close to the left subtree as possible
def fix_subtrees(left, right):
wl = contour(left, "right")
wr = contour(right, "left")
if len(wl) != len(wr):
fix_threads(left, right, len(wl), len(wr))
diff = max(x - y for x, y in zip(wl, wr)) + 1
diff += (right.x + diff + left.x) % 2 # stick to the integers
addtotree(right, diff)
return (left.x + right.x) / 2
def fix_threads(left, right, ldepth, rdepth):
if ldepth > rdepth:
rattach(left, right, rdepth)
else:
lattach(left, right, ldepth)
# when the left tree is deeper than the right tree, descend rdepth levels
# down the right side of both trees and attach the last node on the right
# to the rightmost node on the left
def rattach(left, right, depth):
if depth > 1:
return rattach(left.right(), right.right(), depth - 1)
right.thread = left.right()
def lattach(left, right, depth):
if depth > 1:
return lattach(left.left(), right.left(), depth - 1)
left.thread = right.left()
def addtotree(tree, val):
tree.x += val
if len(tree.children):
for child in tree.children[:2]:
addtotree(child, val)
def contour(tree, next):
next_node = getattr(tree, next)()
if not next_node:
return [tree.x]
else:
return [tree.x] + contour(next_node, next)
# given an array of nodes, print them out reasonably on one line
def printrow(level):
x = dict((t.x, t.tree) for t in level)
for i in range(max(x.keys()) + 1):
try:
stdout.write(str(x[i])[:4])
except:
stdout.write(" ")
def p(tree):
level = [tree]
while 1:
newlevel = []
printrow(level)
for t in level:
newlevel.extend(t.children[:2])
print
if not newlevel:
break
level = newlevel
# root = gentree("/Users/llimllib/Movies")
# root.children.reverse()
# drawtree = reingold_tilford(root)
# p(drawtree)