I'm new to Python thus the question,this is the implementation of my my BST
class BST(object):
def __init__(self):
self.root = None
self.size = 0
def add(self, item):
return self.addHelper(item, self.root)
def addHelper(self, item, root):
if root is None:
root = Node(item)
return root
if item < root.data:
root.left = self.addHelper(item, root.left)
else:
root.right = self.addHelper(item, root.right)
This is the Node object
class Node(object):
def __init__(self, data):
self.data = data
self.left = None
self.right = None
This is my implmentation of str
def __str__(self):
self.levelByLevel(self.root)
return "Complete"
def levelByLevel(self, root):
delim = Node(sys.maxsize)
queue = deque()
queue.append(root)
queue.append(delim)
while queue:
temp = queue.popleft()
if temp == delim and len(queue) > 0:
queue.append(delim)
print()
else:
print(temp.data, " ")
if temp.left:
queue.append(temp.left)
if temp.right:
queue.append(temp.right)
This is my calling client,
def main():
bst = BST()
bst.root = bst.add(12)
bst.root = bst.add(15)
bst.root = bst.add(9)
bst.levelByLevel(bst.root)
if __name__ == '__main__':
main()
Instead of the expected output of printing the BST level by level I get the following output,
9
9223372036854775807
When I look in the debugger it seems that the every time the add method is called it starts with root as None and then returns the last number as root. I'm not sure why this is happening. Any help appreciated.
If the root
argument of your addHelper
is None
, you set it to a newly-created Node
object and return it. If it is not, then you modify the argument but return nothing, so you end up setting bst.root
to None
again. Try the following with your code above — it should help your understanding of what your code is doing.
bst = BST()
bst.root = bst.add(12)
try:
print(bst.root.data)
except AttributeError:
print('root is None')
# => 12
# `bst.addHelper(12, self.root)` returned `Node(12)`,
# which `bst.add` returned too, so now `bst.root`
# is `Node(12)`
bst.root = bst.add(15)
try:
print(bst.root.data)
except AttributeError:
print('root is None')
# => root is None
# `bst.addHelper(15, self.root)` returned `None`,
# which `bst.add` returned too, so now `bst.root`
# is `None`.
bst.root = bst.add(9)
try:
print(bst.root.data)
except AttributeError:
print('root is None')
# => 9
# `bst.addHelper(9, self.root)` returned `Node(9)`,
# which `bst.add` returned too, so now `bst.root`
# is `Node(9)`
So you should do two things:
addHelper
always return its last argument — after the appropriate modifications —, and add
function take care of assigning the result to self.root
(do not leave it for the class user to do). Here is the code:
def add(self, item):
self.root = self.addHelper(item, self.root)
self.size += 1 # Otherwise what good is `self.size`?
def addHelper(self, item, node):
if node is None:
node = Node(item)
elif item < node.data:
node.left = self.addHelper(item, node.left)
else:
node.right = self.addHelper(item, node.right)
return node
Notice that I changed the name of the last argument in addHelper
to node
for clarity (there already is something called root
: that of the tree!).
You can now write your main
function as follows:
def main():
bst = BST()
bst.add(12)
bst.add(15)
bst.add(9)
bst.levelByLevel(bst.root)
(which is exactly what @AaronTaggart suggests — but you need the modifications in add
and addHelper
). Its output is:
12
9
15
9223372036854775807
The above gets you to a working binary search tree. A few notes:
levelByLevel
to avoid printing that last value, as well as not taking any arguments (besides self
, of course) — it should always print from the root of the tree. bst.add(None)
will raise an error. You can guard against it by changing your add
method. One possibility is
def add(self, item): try: self.root = self.addHelper(item, self.root) self.size += 1 except TypeError: pass
Another option (faster, since it refuses to go on processing item
if it is None
) is
def add(self, item): if item is not None: self.root = self.addHelper(item, self.root) self.size += 1
From the point of view of design, I would expect selecting a node from a binary search tree would give me the subtree below it. In a way it does (the node contains references to all other nodes below), but still: Node
and BST
objects are different things. You may want to think about a way of unifying the two (this is the point in @YairTwito's answer).
add_helper
instead of addHelper
. I would further add an underscore at the beginning to signal that it is not meant for public use — so _add_helper
, or simply _add
. Based on the following, you can see that bst.root
in None
after the second call to add()
:
>>> bst.root = bst.add(12)
>>> bst.root
<__main__.Node object at 0x7f9aaa29cfd0>
>>> bst.root = bst.add(15)
>>> type(bst.root)
<type 'NoneType'>
Your addHelper
isn't returning the root
node. Try this:
def addHelper(self, item, root):
if root is None:
root = Node(item)
return root
if item < root.data:
root.left = self.addHelper(item, root.left)
else:
root.right = self.addHelper(item, root.right)
return root
And then it works as expected:
>>> bst.root = bst.add(12)
>>> bst.root = bst.add(15)
>>> bst.levelByLevel(bst.root)
(12, ' ')
()
(15, ' ')
(9223372036854775807, ' ')
>>> bst.root = bst.add(9)
>>> bst.levelByLevel(bst.root)
(12, ' ')
()
(9, ' ')
(15, ' ')
(9223372036854775807, ' ')
You're using the BST
object basically only to hold a root Node
and the add
function doesn't really operate on the BST
object so it's better to have only one class ( BtsNode
) and implement the add
there. Try that and you'll see that the add
function would be much simpler. And, in general, when a member function doesn't use self
it shouldn't be a member function (like addHelper
), ie, it shouldn't have self
as a parameter (if you'd like I can show you how to write the BtsNode
class).
I tried writing a class that uses your idea of how to implement the BST
.
class BstNode:
def __init__(self):
self.left = None
self.right = None
self.data = None
def add(self,item):
if not self.data:
self.data = item
elif item >= self.data:
if not self.right:
self.right = BstNode()
self.right.add(item)
else:
if not self.left:
self.left = BstNode()
self.left.add(item)
That way you can create a BST
the following way:
bst = BstNode()
bst.add(13)
bst.add(10)
bst.add(20)
The difference is that now the add
function actually operates on the object without any need for the user to do anything. The function changes the state of the object by itself.
In general a function should do only what it's expected to do. The add
function is expected to add an item to the tree so it shouldn't return the root. The fact that you had to write bst.root = bst.add()
each time should signal that there's some fault in your design.
Your add method probably shouldn't return a value. And you most certainly shouldn't assign the root of the tree to what the add method returns.
Try changing your main code to something like this:
def main():
bst = BST()
bst.add(12)
bst.add(15)
bst.add(9)
bst.levelByLevel(bst.root)
if __name__ == '__main__':
main()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.