-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTree.py
313 lines (248 loc) · 9.03 KB
/
Tree.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
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
'''
pyTree: A list-derived TREE data structure in Python
Created on Aug 21, 2012
@author: yoyzhou
'''
import collections
(S,T) = range(2)
class Tree(object):
'''
A Python implementation of Tree data structure
'''
def __init__(self, data = None, children = None):
'''
@param data: content of this node
@param children: sub node(s) of Tree, could be None, child (single) or children (multiple)
'''
self.data = data
self.__children = []
self.__parent=None #private parent attribute
if children: #construct a Tree with child or children
if isinstance(children, Tree):
self.__children.append(children)
children.__parent = self
elif isinstance(children, collections.Iterable):
for child in children:
if isinstance(child, Tree):
self.__children.append(child)
child.__parent = self
else:
raise TypeError('Child of Tree should be a Tree type.')
else:
raise TypeError('Child of Tree should be a Tree type')
def __str__(self, *args, **kwargs):
return self.data.__str__(*args, **kwargs)
def addChild(self, child):
"""
Add one single child node to current node
"""
if isinstance(child, Tree):
self.__children.append(child)
child.__parent = self
else:
raise TypeError('Child of Tree should be a Tree type')
def addChildren(self, children):
"""
Add multiple child nodes to current node
"""
if isinstance(children, list):
for child in children:
if isinstance(child, Tree):
self.__children.append(child)
child.__parent = self
else:
raise TypeError('Child of Tree should be a Tree type.')
def getParent(self):
"""
Get node's parent node.
"""
return self.__parent
def getChild(self, index):
"""
Get node's No. index child node.
@param index: Which child node to get in children list, starts with 0 to number of children - 1
@return: A Tree node presenting the number index child
@raise IndexError: if the index is out of range
"""
try:
return self.__children[index]
except IndexError:
raise IndexError("Index starts with 0 to number of children - 1")
def getChildren(self):
"""
Get node's all child nodes.
"""
return self.__children
def getNode(self, content, includeself = True):
"""
Get the first matching item(including self) whose data is equal to content.
Method uses data == content to determine whether a node's data equals to content, note if your node's data is
self defined class, overriding object's __eq__ might be required.
Implement Tree travel (level first) algorithm using queue
@param content: node's content to be searched
@return: Return node which contains the same data as parameter content, return None if no such node
"""
nodesQ = []
if includeself:
nodesQ.append(self)
else:
nodesQ.extend(self.getChildren())
while nodesQ:
child = nodesQ[0]
if child.data == content:
return child
else:
nodesQ.extend(child.getChildren())
del nodesQ[0]
def delChild(self, index):
"""
Delete node's No. index child node.
@param index: Which child node to delete in children list, starts with 0 to number of children - 1
@raise IndexError: if the index is out of range
"""
try:
del self.__children[index]
except IndexError:
raise IndexError("Index starts with 0 to number of children - 1")
def delNode(self, content):
"""
Delete the first matching item(including self) whose data is equal to content.
Method uses data == content to determine whether a node's data equals to content, note if your node's data is
self defined class, overriding object's __eq__ might be required.
Implement Tree travel (level first) algorithm using queue
@param content: node's content to be searched
"""
nodesQ = [self]
while nodesQ:
child = nodesQ[0]
if child.data == content:
if child.isRoot():
del self
return
else:
parent = child.getParent()
parent.delChild(parent.getChildren().index(child))
return
else:
nodesQ.extend(child.getChildren())
del nodesQ[0]
def getRoot(self):
"""
Get root of the current node.
"""
if self.isRoot():
return self
else:
return self.getParent().getRoot()
def isRoot(self):
"""
Determine whether node is a root node or not.
"""
if self.__parent is None:
return True
else:
return False
def isBranch(self):
"""
Determine whether node is a branch node or not.
"""
if self.__children == []:
return True
else:
return False
def prettyTree(self):
""""
Another implementation of printing tree using Stack
Print tree structure in hierarchy style.
For example:
Root
|___ C01
| |___ C11
| |___ C111
| |___ C112
|___ C02
|___ C03
| |___ C31
A more elegant way to achieve this function using Stack structure,
for constructing the Nodes Stack push and pop nodes with additional level info.
"""
level = 0
NodesS = [self, level] #init Nodes Stack
while NodesS:
head = NodesS.pop() #head pointer points to the first item of stack, can be a level identifier or tree node
if isinstance(head, int):
level = head
else:
self.__printLabel__(head, NodesS, level)
children = head.getChildren()
children.reverse()
if NodesS:
NodesS.append(level) #push level info if stack is not empty
if children: #add children if has children nodes
NodesS.extend(children)
level += 1
NodesS.append(level)
def nestedTree(self):
""""
Print tree structure in nested-list style.
For example:
[0] nested-list style
[Root[C01[C11[C111,C112]],C02,C03[C31]]]
"""
NestedT = ''
delimiter_o = '['
delimiter_c = ']'
NodesS = [delimiter_c, self, delimiter_o]
while NodesS:
head = NodesS.pop()
if isinstance(head, str):
NestedT += head
else:
NestedT += str(head.data)
children = head.getChildren()
if children: #add children if has children nodes
NodesS.append(delimiter_c)
for child in children:
NodesS.append(child)
NodesS.append(',')
NodesS.pop()
NodesS.append(delimiter_o)
print(NestedT)
def __printLabel__(self, head, NodesS, level):
"""
Print each node
"""
leading = ''
lasting = '|___ '
label = str(head.data)
if level == 0:
print(str(head))
else:
for l in range(0, level - 1):
sibling = False
parentT = head.__getParent__(level - l)
for c in parentT.getChildren():
if c in NodesS:
sibling = True
break
if sibling:
leading += '| '
else:
leading += ' '
if label.strip() != '':
print('{0}{1}{2}'.format( leading, lasting, label))
def __getParent__(self, up):
parent = self;
while up:
parent = parent.getParent()
up -= 1
return parent
def setCargo(self, cargo):
self.data = cargo
def getCargo(self):
return self.data
def getAllCargoes(self):
if self.isRoot():
return [self.getCargo()]
else:
return self.getParent().getAllCargoes() + [self.getCargo()]