I'm trying to implement a binary tree with insert and preorder methods.
After adding elements to the tree, only one element is displayed.
Can someone let me know where I'm wrong.
Below is code:
class Node(object):
def __init__(self, value, left=None, right=None):
self.value = value
self.left = None
self.right = None
def __repr__(self):
return '{}'.format(self.value)
class BinaryTree(object):
def __init__(self, root=None):
self.root = root
def add(self, value):
val = self.root
if not val:
self.root = value
val = value
elif not val.left:
val = value
elif not val.right:
val = value
else:
self.left = val.left.add(value)
return val
def preorder(self):
val = self.root
if not val: # this will handle the case when root node is None.
return
print(val)
if val.left:
val.left.preorder()
if val.right:
val.right.preorder()
def main():
binary_tree = BinaryTree()
print("Adding nodes to the tree")
for i in range(1, 11):
node = Node(i)
binary_tree.add(node)
print("Printing preorder...")
binary_tree.preorder()
if __name__ == '__main__':
main()
Output
Adding nodes to the tree
Printing preorder...
1
Your code has a few different errors. Some relate to how you modify self.root (or fail to), others have to do with attempts at recursion on the wrong types.
The first issue, which is why your code fails silently, has to do with your BinaryTree.add method, which does nothing when the tree is empty. The problem is that you initialize a local variable val to be equal to your root node (if you have one), and then later rebind it to some other value. But that never changes the root value at all, only the local val variable.
I suggest you get rid of val all together, and instead read and write self.root directly. Then you'll actually make some progress, and see the other issues.
Here's a start:
def add(self, value):
if self.root is None:
self.root = value
elif self.root.left.left is None:
self.root.left = value
...
The other issues I mention are both similar, though one occurs in BinaryTree.add and the other in BinaryTree.preorder. The issue is that you try to call the same method (add or preorder) on one of the children of your root node. But the nodes are Node instances, and don't have the methods that you've defined in the BinaryTree class.
This issue doesn't have as obvious a solution as the previous one. One idea might be to move the logic for the methods into the Node class (where you can recurse easily), and leave only the empty-tree handling code in the BinaryTree methods (everything else gets delegated to the root node).
Related
This is the code I came up with to insert a new value into a BST:
class BST(object):
def __init__(self, root):
self.root = Node(root)
def insert(self, new_val):
self.__internal_insert(self.root, new_val)
def __internal_insert(self, node, new_val):
if node is None:
node = Node(new_val)
elif new_val < node.value:
self.__internal_insert(node.left, new_val)
else:
self.__internal_insert(node.right, new_val)
# Set up the tree
tree = BST(4)
# Insert elements
tree.insert(2)
tree.insert(1)
tree.insert(3)
tree.insert(5)
however, while debugging I noticed that the self.root is never updated, eg.: as soon as the __internal_insert() method finishes and a new insert() is performed, its sibling nodes left and right are back to None instead to the previous value that was set.
Hope you help me spot where the bug is. I picked up Python recently, my apologizes if this is a trivial question.
You defined node = Node(new_val), but then where do you ever attach that node to it's parent?
Basically, you recurse, but never captured the results you're building
Try returning the node you created
def __internal_insert(self, node, new_val):
if node is None:
node = Node(new_val)
elif new_val < node.value:
node.left = self.__internal_insert(node.left, new_val)
else:
node.right = self.__internal_insert(node.right, new_val)
return node
I see two issues with the code.
First, when you reassign node, it is not assigning the value to the BST object. To do that, you need to reference it directly: self.left = Node(new_val).
Second, you're not checking the equals condition, so your code isn't going to work like a traditional BST. You'll end up with a lot of extraneous nodes.
I have the task to perform some basic operations on Binary Search Trees and I'm not sure what is the clever way to do it.
I know that the usual way would be to write a class for the nodes and one for the tree so that I can build up my tree from given values and perform certain tasks on it. The thing is, I'm already getting the tree as a list and since BSTs are not unique, there won't come any good from it if I take each value and build the tree myself.
So... I'm getting a list like this:
11 9 2 13 _, 4 18 2 14 _, 2 10 _ 11 4, 14 16 4 _ _, 13 0 11 _ _ | 10 | 7
which means:
key value parent left right, ... | value1 | value2
So as you see the BST is given explicitly. My tasks are to do a level-print of the tree, return the path from root to value1, do a rotate-right operation on the subtree that has value1, then delete value1 and then insert value2.
What would be an efficient way to tackle this problem?
Here is one possible way of implementing the tree. Hope it helps. Though this contains insertions and popular traversals, not rotations or deletions.
Reference: http://www.thelearningpoint.net/computer-science/learning-python-programming-and-data-structures/learning-python-programming-and-data-structures--tutorial-20--graphs-breadth-and-depth-first-search-bfsdfs-dijkstra-algorithm-topological-search
'''
Binary Search Tree is a binary tree(that is every node has two branches),
in which the values contained in the left subtree is always less than the
root of that subtree, and the values contained in the right subtree is
always greater than the value of the root of the right subtree.
For more information about binary search trees, refer to :
http://en.wikipedia.org/wiki/Binary_search_tree
'''
#Only for use in Python 2.6.0a2 and later
from __future__ import print_function
class Node:
# Constructor to initialize data
# If data is not given by user,its taken as None
def __init__(self, data=None, left=None, right=None):
self.data = data
self.left = left
self.right = right
# __str__ returns string equivalent of Object
def __str__(self):
return "Node[Data = %s]" % (self.data,)
class BinarySearchTree:
def __init__(self):
self.root = None
'''
While inserting values in a binary search tree, we first check
whether the value is greater than, lesser than or equal to the
root of the tree.
We initialize current node as the root.
If the value is greater than the current node value, then we know that
its right location will be in the right subtree. So we make the current
element as the right node.
If the value is lesser than the current node value, then we know that
its right location will be in the left subtree. So we make the current
element as the left node.
If the value is equal to the current node value, then we know that the
value is already contained in the tree and doesn't need to be reinserted.
So we break from the loop.
'''
def insert(self, val):
if (self.root == None):
self.root = Node(val)
else:
current = self.root
while 1:
if (current.data > val):
if (current.left == None):
current.left = Node(val)
break
else:
current = current.left
elif (current.data < val):
if (current.right == None):
current.right = Node(val)
break
else:
current = current.right
else:
break
'''
In preorder traversal, we first print the current element, then
move on to the left subtree and finally to the right subree.
'''
def preorder(self, node):
if (node == None):
return
else:
print(node.data, end=" ")
self.preorder(node.left)
self.preorder(node.right)
'''
In inorder traversal, we first move to the left subtree, then print
the current element and finally move to the right subtree.
'''
#Important : Inorder traversal returns the elements in sorted form.
def inorder(self, node):
if (node == None):
return
else:
self.inorder(node.left)
print(node.data, end=" ")
self.inorder(node.right)
'''
In postorder traversal, we first move to the left subtree, then to the
right subtree and finally print the current element.
'''
def postorder(self, node):
if (node == None):
return
else:
self.postorder(node.left)
self.postorder(node.right)
print(node.data, end=" ")
tree = BinarySearchTree()
tree.insert(1)
tree.insert(9)
tree.insert(4)
tree.insert(3)
tree.insert(5)
tree.insert(7)
tree.insert(10)
tree.insert(0)
print ("Preorder Printing")
tree.preorder(tree.root)
print("\n\nInorder Printing")
tree.inorder(tree.root)
print("\n\nPostOrder Printing")
tree.postorder(tree.root)
Here is the implementation of Binary Search Tree with it's basic operations like insert node, find node
class Node:
def __init__(self,data):
self.left = None
self.right = None
self.data = data
class BST:
def __init__(self):
self.root = None
def set_root(self,data):
self.root = Node(data)
def insert_node(self,data):
if self.root is None:
self.set_root(data)
else:
n = Node(data)
troot = self.root
while troot:
if data < troot.data:
if troot.left:
troot = troot.left
else:
troot.left = n
break
else:
if troot.right:
troot = troot.right
else:
troot.right = n
break
def search_node(self,data):
if self.root is None:
return "Not found"
else:
troot = self.root
while troot:
if data < troot.data:
if troot.left:
troot = troot.left
if troot.data == data:
return "Found"
else:
return "Not found"
elif data > troot.data:
if troot.right:
troot = troot.right
if troot.data == data:
return "Found"
else:
return "Not found"
else:
return "Found"
tree = BST()
tree.insert_node(10)
tree.insert_node(5)
tree.insert_node(20)
tree.insert_node(7)
print(tree.root.data)
print(tree.root.left.data)
print(tree.root.right.data)
print(tree.root.left.right.data)
print(tree.search_node(10))
print(tree.search_node(5))
print(tree.search_node(20))
print(tree.search_node(7))
print(tree.search_node(12))
print(tree.search_node(15))
Output:
10
5
20
7
Found
Found
Found
Found
Not found
Not found
In this specific case I had success using a dictionary as a datatype to store the graph. The key is the node_key and the value is a list with the attributes of the node. In this way it is rather fast to find the needed nodes and all its attributes.
I'm just not sure if there is a way to make it reasonably faster.
I'm fairly new to programming and I want to screw around with some Binary Search Trees. I want to make a function that counts the number of nodes in the tree recursively, however, when I run my function it doesn't seem to work and it keeps returning 'none' as if there is nothing in my tree. Could anyone help me find the problem here?
This is my TreeNode class:
class TreeNode(object):
def __init__(self, data = None, left=None, right=None):
self.item = data
self.left = left
self.right = right
def __str__(self):
return str(self.item)
This is my main function, I trimmed most of it down just so we can get to the problem referring to the counting of the nodes.
from TreeNode import TreeNode
class BST(object):
#------------------------------------------------------------
def __init__(self):
"""create empty binary search tree
post: empty tree created"""
self.root = None
def treeSize(self, root, size = 0):
if root is None:
return -1
if root is not None:
size += 1
if root.left is not None:
self.treeSize(root.left, size)
if root.right is not None:
self.treeSize(root.right, size)
This is the code I use to test out my function:
from BinarySearchTree import BST
from TreeNode import TreeNode
tree = TreeNode(4, TreeNode(2, TreeNode(1), TreeNode(3)), TreeNode (7, TreeNode(6),TreeNode(8)))
a = BST()
print(a.postOrder(tree))
print(a.treeSize(tree))
When I called the 'print(a.treeSize(tree))' It just returns 'none' and not '7' like it should.
You can also do it the good old recursive way:
def treeSize(self, root):
if root is None:
return 0
if root is not None:
return 1 + self.treeSize(root.left) + self.treeSize(root.right)
Jonathan's answer is nice as well.
I see. You think size is going to get updated in the called functions. It won't as it's local to each function. You could call global on it, but that's not optimal.
You could set it as a member variable (don't actually do it this way):
def __init__(self):
...
self.size = 0
def treeSize(self,...):
...
self.size += 1
...
return self.size
but the obvious bug is self.size will double every time treeSize is called. You can fix that too, but let's use patterns we know and love. Do it the good old recursive way like VHarisop wrote.
I am trying to build a binary tree, but stuck at adding two nodes to root.
What function should I write to enable adding node to these two nodes?
I have the following code:
class Btree:
def __init__(self, root):
self.key = root
self.lc = None
self.rc = None
def insert_lc(self, newNode):
if self.lc == None:
self.lc = Btree(newNode)
else:
t = Btree(newNode)
t.lc = self.lc
self.lc = t
def insert_rc(self, newNode):
if self.rc == None:
self.rc = Btree(newNode)
else:
t = Btree(newNode)
t.rc = self.rc
self.rc = t
def get_rc(self):
return self.rc
def get_lc(self):
return self.lc
def set_Root(self, val):
self.key = val
def get_Root(self):
return self.key
r = Btree(1)
r.insert_lc(2)
r.insert_rc(4)
I think I need a function so I can add left child and right child to nodes which have value 2 and 4
First of all, I do not quite understand why do you assign your new node's left (right) child to that new node itself. This will get you an infinite loop if you try to search the tree later.
t = Btree(newNode)
#The line below seems unnecessary
t.lc = self.lc
self.lc = t
Second of all, in the Btree constructor you have a parameter called root which seems like it's intended to be a reference to the root of the current node. However, you pass the node's key as that parameter, so there is no way to access node's root. I understand that is might be not even necessary in your case, still that parameter name is quite confusing. If you want to have a reference to the parent node you should add another parameter to your constructor:
def __init__(self, root, key):
self.root = root
self.key = key
self.lc = None
self.rc = None
This way you have both key and a parent node reference. You also will need to modify insert_rc and insert_lc methods:
def insert_rc(self, newNode):
if self.rc == None:
#Parent node is the one the insert_rc method is called on,
#so we pass self as the root parameter
self.rc = Btree(self, newNode)
else:
t = Btree(self, newNode)
self.rc = t
#Same with insert_lc
Finally,to answer your initial question: to add children to the added nodes you simply call get_rc or get_lc both of which will return you instances of Btree so you can add child nodes to them:
r = Btree(1)
r.insert_lc(2)
r.insert_rc(4)
#Insert left child to the node with key=2
r.get_lc().insert_lc(3)
#Insert right child to the node with key=4
r.get_rc().insert_rc(5)
Below code is a simple implementation of BFS in Python. I able to print the values level by level from a tree. However when I want to search a element and print it . I am not able to do it. Whts is the error?
def search_bfs(self,root,key):
q=QueueClass()
q.enqueue(root)
while q.size() > 0:
curr_node = q.dequeue()
#print curr_node
#print key
if curr_node == key:
print curr_node
break
if curr_node.left is not None:
q.enqueue(curr_node.left)
if curr_node.right is not None:
q.enqueue(curr_node.right)
from QueueClass import QueueClass
class Node:
def __init__(self,data):
self.data=data
self.left=None
self.right=None
def __str__(self):
return str(self.data)
class searchtree:
def __init__(self):
self.root = None
def create(self,val):
if self.root == None:
self.root=Node(val)
else:
current=self.root
while 1:
if val < current.data:
if current.left:
current=current.left
else:
current.left=Node(val)
break
if val > current.data:
if current.right:
current=current.right
else:
current.right=Node(val)
break
else:
break
tree=searchtree()
lst=[3,1,2,6,4,5,8,12]
for i in lst:
tree.create(i)
tree.search_bfs(tree.root, 3)
You really make it hard to reproduce your problem! So here's what I did:
class QueueClass(object):
def __init__(self):
self.l = []
def size(self): return len(self.l)
def enqueue(self, it): self.l.append(it)
def dequeue(self): return self.l.pop()
class Node:
def __init__(self, name, left=None, right=None):
self.name = name
self.left = left
self.right = right
def __str__(self):
return '{}:{}/{}'.format(self.name, self.left, self.right)
root = Node('root')
adding all the code you omitted (more than you supplied!-).
And now, adding your code exactly as reported, the call:
search_bfs(None, root, root)
emits
root:None/None
exactly as desired and contrary to your report.
It follows that your bug is in some of code you didn't show us, not in the coded you did show.
You either have a buggy queue-class, or are building a different tree than you thought, or searching for a node that is not actually in the tree.
Hard to debug code you're now showing, you know.
Added: so now I've integrated the extra code per your edit and at the end I have:
st = searchtree()
st.create('imtheroot')
st.search_bfs(st.root, st.root)
and of course it prints imtheroot as expected.
Is your bug perhaps STILL hiding in parts you're not yet showing, e.g instead of looking for a node you may be looking for something else?
E.g, if the final call was erroneously st.search_bfs(st.root, 'imtheroot') then obviously the search would fail -- you're checking equality of the key parameter with a node, so key clearly must be a node. not a string or other things (unless the Node class defines a very, very peculiar __eq__ method, which the one you've shown fortunately doesn't:-).
I think the issue is that when you do if curr_node == key, curr_node is a Node object, which has an integer .data attribute, but key is the integer value.
So I think you just need to use if curr_node.data == key.