-
Notifications
You must be signed in to change notification settings - Fork 0
/
binarytree.py
154 lines (147 loc) · 4.9 KB
/
binarytree.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
class Node(object):
"""Tree node: left and right child + data which can be any object
"""
def __init__(self, data):
"""Node constructor
@param data node data object
"""
self.left = None
self.right = None
self.data = data
def insert(self, data):
"""Insert new node with data
@param data node data object to insert
"""
if self.data:
if data < self.data:
if self.left is None:
self.left = Node(data)
else:
self.left.insert(data)
elif data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.data = data
def lookup(self, data, parent=None):
"""Lookup node containing data
@param data node data object to look up
@param parent node's parent
@returns node and node's parent if found or None, None
"""
if data < self.data:
if self.left is None:
return None, None
return self.left.lookup(data, self)
elif data > self.data:
if self.right is None:
return None, None
return self.right.lookup(data, self)
else:
return self, parent
def delete(self, data):
"""Delete node containing data
@param data node's content to delete
"""
# get node containing data
node, parent = self.lookup(data)
if node is not None:
children_count = node.children_count()
if children_count == 0:
# if node has no children, just remove it
if parent:
if parent.left is node:
parent.left = None
else:
parent.right = None
else:
self.data = None
elif children_count == 1:
# if node has 1 child
# replace node by its child
if node.left:
n = node.left
else:
n = node.right
if parent:
if parent.left is node:
parent.left = n
else:
parent.right = n
else:
self.left = n.left
self.right = n.right
self.data = n.data
else:
# if node has 2 children
# find its successor
parent = node
successor = node.right
while successor.left:
parent = successor
successor = successor.left
# replace node data by its successor data
node.data = successor.data
# fix successor's parent node child
if parent.left == successor:
parent.left = successor.right
else:
parent.right = successor.right
def compare_trees(self, node):
"""Compare 2 trees
@param node tree to compare
@returns True if the tree passed is identical to this tree
"""
if node is None:
return False
if self.data != node.data:
return False
res = True
if self.left is None:
if node.left:
return False
else:
res = self.left.compare_trees(node.left)
if res is False:
return False
if self.right is None:
if node.right:
return False
else:
res = self.right.compare_trees(node.right)
return res
def print_tree(self):
"""Print tree content inorder
"""
if self.left:
self.left.print_tree()
print(self.data, end=" ")
if self.right:
self.right.print_tree()
def tree_data(self):
"""Generator to get the tree nodes data
"""
# we use a stack to traverse the tree in a non-recursive way
stack = []
node = self
while stack or node:
if node:
stack.append(node)
node = node.left
else:
# we are returning so we pop the node and we yield it
node = stack.pop()
yield node.data
node = node.right
def children_count(self):
"""Return the number of children
@returns number of children: 0, 1, 2
"""
cnt = 0
if self.left:
cnt += 1
if self.right:
cnt += 1
return cnt