Print BST in pre order - python

rI am trying to print out my binary tree in pre order form however I am coming across these errors. I am still learning python so I am not quite sure what is going on. But I assume that my print function isn't working properly. Not quite sure why preorder_print is having a global name issue though =/
my expected output would be
pre order:
4
2
1
3
8
6
10
Output:
pre order:
<BST_tree.Node instance at 0x0000000002AA0988>
<BST_tree.Node instance at 0x0000000002AA0E08>
<BST_tree.Node instance at 0x0000000002AA0E88>
my code:
class Node:
def __init__(self,value):
self.right = None
self.left = None
self.value = value
def BST_Insert(root, node): # root --> root of tree or subtree!
if root.value is None:
root = node # beginning of tree
else:
if root.value > node.value: # go to left
if root.left is None:
root.left = node
else:
BST_Insert(root.left, node)
else:
if root.value < node.value: # go to right
root.right = node
else:
BST_Insert(root.right, node)
def preorder_print(root):
print root
if root.left is not None:
preorder_print(root.left)
else:
if root.right is not None:
preorder_print(root.right)
r = Node(4)
# left
a = Node(2)
b = Node(1)
c = Node(3)
# right
d = Node(8)
e = Node(6)
f = Node(10)
BST_Insert(r, a)
BST_Insert(r, b)
BST_Insert(r, c)
BST_Insert(r, d)
BST_Insert(r, e)
BST_Insert(r, f)
print "pre order:"
preorder_print(r)
* EDIT *
Thank you everyone and especially abarnert for your help!!! Here is the fixed version! or the preorder_print and BST_Inert
def BST_Insert(root, node): # root --> root of tree or subtree!
if root.value is None:
root = node # beginning of tree
else:
if root.value > node.value: # go to left
if root.left is None:
root.left = node
else:
BST_Insert(root.left, node)
if root.value < node.value: # go to right
if root.right is None:
root.right = node
else:
BST_Insert(root.right, node)
def preorder_print(root):
print root.value
if root.left is not None:
preorder_print(root.left)
if root.right is not None:
preorder_print(root.right)

Apologies for posting two answers, but I'm not sure which of two problems you're asking about here.
Your preorder traversal isn't covering the entire tree, because you ignore the entire right subtree whenever the left subtree isn't empty:
def preorder_print(root):
print root
if root.left is not None:
preoder_print(root.left)
else:
if root.right is not None:
preorder_print(root.right)
So, in your example, because the 4 node has the 2 node on its left, it won't look at 8 or anything underneath it. And then the same thing in the 2. So, you only get 3 nodes instead of all 7.
To fix this, just remove the else:
def preorder_print(root):
print root
if root.left is not None:
preoder_print(root.left)
if root.right is not None:
preorder_print(root.right)
You also have a problem in your BST_Insert function. You're setting root.right = node any time node.value > root.value, even if there's already something there. So, the first time you try to insert something that's on the left side of the right side of anything, it will erase the parent—the 6 erases the 8, then the 10 erases the 6, so you end up with just 4, 2, 1, 3, and 10.
I think what you wanted here is to change this:
else:
if root.value < node.value: # go to right
root.right = node
else:
BST_Insert(root.right, node)
… to:
elif root.value < node.value: # go to right
if root.right is None
root.right = node
else:
BST_Insert(root.right, node)

The print function is working just fine. When you print out an object that doesn't have a custom __repr__ or __str__ method, this is exactly what you're supposed to get.
There are two ways to solve this.
First, instead of printing the Node object itself, print the information you want to print. For example, change this:
print root
… to:
print 'node with value {}'.format(root.value)
… or:
print root.value
… or:
print 'I've got a node and he's got a value and it's ' + str(root.value)
Alternatively, if you always want nodes to print out the same way—e.g., Node(4)—you can give the class a __repr__ method:
def __repr__(self):
return 'Node({})'.format(self.value)
Sometimes you want to provide both a nice human-readable representation of a class that you might put into a report, and a different representation that's useful for, e.g., experimenting at the interactive interpreter. In that case, you define both __str__ and __repr__:
def __str__(self):
# Pick whatever you think looks nice here
return str(self.value)
# return 'Node: ' + str(self.value)
# return 'Node with value {}'.format(self.value)
def __repr__(self):
return 'Node({})'.format(self.value)
(Notice that Node(4) is a nice "experimenting at the interactive interpreter" representation, because it's exactly what you'd type into the interpreter to create an equivalent object.)

Use print root.value instead of print root.
Explanation:
root is an object, an instance of the Node class. root.value is the actual number the node holds.
Aside: the "proper" way to do this would be what #abarnert answered, via __repr__, but it's a little overkill for simple exercises focused around teaching about trees.

You want to print the value of root
print root.value

Related

Inserting a node in a complete binary tree with python

How to insert a node in a complete binary tree without using queue DS? I tried the following code:
class TreeNode:
def __init__(self, value=None) -> None:
self.left = None
self.value = value
self.right = None
class Tree:
def __init__(self, root=None) -> None:
self.__root = root if not root else TreeNode(root)
self.__len = 1 if root else 0
def append(self, data, root="_"):
if self.__root.value is None:
self.__root = TreeNode(data)
self.__len += 1
return
root = self.__root if root == "_" else root
if not root:
return False
if root.left is None and root.right is None:
root.left = TreeNode(data)
self.__len += 1
return True
elif root.left is not None and root.right is None:
root.right = TreeNode(data)
self.__len += 1
return True
elif root.left is not None and root.right is not None:
if self.append(data, root.left):
return
else:
self.append(data, root.right)
return
the recursive call of that function always add the new node on the left side of the tree, so what should I do to make it recursively checks the right side too?
First of all, the first line in your append code seems to give a special meaning to the value in the root node. When it is None it is not considered a real node, but to represent an empty tree. This is not a good approach. An empty tree is represented by a __root that is None -- nothing else. I would also suggest to remove the optional data argument from the constructor. Either the constructor should allow an arbitrary number of values or none at all. To allow one is odd and strengthens the idea that a tree could have a special None in its root node.
To the core of your question. There is nice attribute to complete binary trees. The paths from the root to a leaf can be represented by a bit pattern, where a 0 means "go left" and a 1 means "go right". And the path to the "slot" where a new node should be injected has a relationship with the size of the tree once that node has been added:
new size
binary representation
path to new node
1
1
[]
2
10
[left]
3
11
[right]
4
100
[left,left]
5
101
[left,right]
In general the path to the new node is defined by the bits in the binary representation of the new tree size, ignoring the leftmost 1.
This leads to the following code:
class Tree:
def __init__(self) -> None:
self.__root = None
self.__len = 0
def append(self, data):
self.__len += 1
if self.__len == 1: # First node
self.__root = TreeNode(data)
return
node = self.__root
# Iterate all the bits except the leftmost 1 and the final bit
for bit in bin(self.__len)[3:-1]:
node = [node.left, node.right][int(bit)] # Choose side
if self.__len & 1: # Use final bit to determine where child goes:
node.right = TreeNode(data)
else:
node.left = TreeNode(data)

how does the linked list goes to the second node

so I am learning linked lists in python, but I didn't understand how does the linked list goes to the second node as it assigns the next node as the root node, please explain it to me, thanks.
the code
class Node
def __init__(self,d,n=None,p=None):
self.data=d
self.next_node=n
self.previous_node=p
def __str__(self):
return ('(' + str(self.data) + ')')
class linked_list:
def __init__(self,r=None):
self.root=r
self.size=0
def add(self,d):
new_node=Node(d,self.root)#here i didn't understand how we assign the next node
self.root=new_node
self.size +=1
def find(self,d):
this_node=self.root
while this_node is not None:
if this_node.data==d:
print(this_node.next_node)
return this_node.data
else:
this_node = this_node.next_node
return None
def remove(self,d):
this_node=self.root
previouse_node=None
while this_node is not None:
if this_node.data==d:
if previouse_node is not None:
previouse_node.next_node=this_node.next_node
else:
self.root=this_node.next_node
self.size -=1
else:
previouse_node=this_node
this_node=this_node.next_node
return False
def print_list(self):
this_node = self.root
while this_node is not None:
print(this_node, end='->')
this_node = this_node.next_node
print('None')
l_list=linked_list()
l_list.add('4')
l_list.add('40')
l_list.add('5')
l_list.print_list()
#////////////////////////////////////////////////////////////////////////////////////
In the add function we create a new node that will become our new root aka our new first element. Therefore we first assign the current root as the next_node of our new node. Afterwards we make our new node the new root.
The linked_list.root attribute actually acts like a tail. When a new node is added, it becomes the next_node of the original root and the root is assigned with that new node (making its content a tail, not a root).
Also, the Node class suggests a doubly linked list but its previous_node value is not properly assigned by linked_list.add.
If that is not your code, it is not a good example to learn from. If it is, then it needs more work and you should probably draw on paper the links that should result from adding a node to the list.
For example:
linked_list.root
|
v
None <-- node1 --> None
linked_list.add(node2) ...
What should happen:
linked_list.root
|
v
None <-- node1 --+
^ |
| v
+--- node2 --> None
What actually happens:
linked_list.root # points to the last node added (i.e. tail)
|
v
None <-- node2 --> None # missing link to node1
^
|
None <-- node1 --+

What does the tmp variable do in this code? Leetcode #94

new to python, I am doing leetcode problem 94, Binary Tree Inorder Traversal. Given the root of a binary tree, return the inorder traversal of its nodes' values.
I have found this code from https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/dong-hua-yan-shi-94-er-cha-shu-de-zhong-xu-bian-li/
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
res = []
pre = None
while root:
if root.left:
pre = root.left
while pre.right:
pre = pre.right
pre.right = root
tmp = root
root = root.left
tmp.left = None
else:
res.append(root.val)
root = root.right
return res
However, I can't understand what tmp variable is doing here. It seems that the tmp variable is not used in any other places.
I tried to remove these 2 lines
tmp = root
tmp.left = None
But then I get a timeout error. Could anyone please explain what these 2 lines are doing here?
Go through the code step by step. The code wants to assign "move" root to the left, and then set the old root.left to None.
The two naive options fail:
root.left = None
root = root.left # root.left no longer is what it used to be because of the first line
or:
root = root.left
root.left = None # root no longer is what it used to be because of the first line
You can do without the tmp variable, however:
root.left, root = None, root.left
This works because Python evaluates the entire right hand side first, and then assigns the lhs from left to right.
tmp is necessary to remove the left child of root, otherwise it would keep looping.

How to fix NoneType error in Python Binary Search Tree?

I'm creating a basic binary search tree program where the nodes have to be strings however, I keep getting this error:
'builtins.AttributeError: 'NoneType' object has no attribute 'addNode'
I'm a bit confused because I thought you had to declare the children nodes as None. My code is below (please excuse the messiness and extra print statements):
class BinarySearchTree:
#constructor with insertion value & left/right nodes as None
def __init__(self, data):
self.data = data
self.left = None
self.right = None
#function to insert node
def addNode(root, data):
#when tree doesn't exist
if root == None:
return BinarySearchTree(data)
else:
#when node is already in tree
if root.data == data:
return root
#smaller values go left
elif data < root.data:
root.left.addNode(data)
#bigger values go right
else:
root.right.addNode(data)
return root
#function to find smallest node value (to help with deletion)
def smallestNode(root):
node = root
#loop goes to lowest left leaf
while(node.left is not None):
node = node.left
return node
#function to delete node
def removeNode(root, data):
if root == None:
return root
#when node to be deleted in smaller than root, go left
if data < root.data:
root.left = root.left.removeNode(data)
#when node to be deleted in bigger than root, go right
elif data > root.data:
root.right = root.right.removeNode(data)
##when node to be deleted in the same as root...
else:
#when node has only 1 or 0 children
if root.right == None:
move = root.left
root = None
return move
elif root.left == None:
move = root.right
root = None
return move
#when node has 2 children, copy then delete smallest node
move = root.right.smallestNode()
root.data = move.data
root.right = root.right.removeNode(move.data)
return root
def findNode(root, data):
#if current node is equal to data value then return the root
if root.data == data or root == None:
return root
#if current node is greater than the data value then, search to the left
elif data < root.data:
return root.left.findNode(data)
#if current node is less than the data value then, search to the right
else:
return root.right.findNode(data)
def createBST(keys):
root = BinarySearchTree(keys[0])
for i in range(1,len(keys)):
root.addNode(keys[i])
return root
print('Hi! Welcome to the Binary Search Tree Builder')
print('Here are your options below:')
print('1) Build new tree')
print('2) Add a node')
print('3) Find a node')
print('4) Delete a node')
choice = int(input('What would you like to do?: '))
if choice == 1:
nodes = list(input("Enter the strings you would like to build your tree from (separate by a space): ").split())
print(nodes)
tree = createBST(nodes)
print(tree)
I'm wondering where exactly is this error coming from and how can I fix it? Also, if you see any other problems occuring in my code, please let me know!
You have conflated the notion of "tree node" and "tree". What you have there is a mixture of the two. Remember, the first parameter to ALL member functions should be "self". Replacing "root" by "self" might make your problem more clear.
So, you might create a BinaryTree class, which has a single member called self.root that holds a BinaryTreeNode object, once you have a node. The nodes will hold the left and right values, each of which will either have None or a BinaryTreeNode object. The node class probably doesn't need much code -- just self.left and self.right.
The BinaryTree class will have an addNode member that knows how to traverse the tree to find the right spot, but when you find the spot, you just set self.left = BinaryTreeNode(...). A node does not know about the tree, so a node does not know how to add new nodes. That's a function of the tree itself.
Does that make your path forward more clear?

Verifying whether a tree is bst or not Python

I have a practice interview question which tells me to verify if a tree is a balanced search tree or not and give a verification method... I have the class as
Class Node:
def __init__(self, k, val):
self.key = k
self.value = val
self.left = None
self.right = None
and other function definitions for the tree max and min values as
def tree_max(node):
maxleft = float('-inf') if not node.left else tree_max(node.left)
maxright = float('-inf') if not node.right else tree_max(node.right)
return max(node.value, maxleft, maxright)
def tree_min(node):
minleft = float('-inf') if not node.right else tree_min(node.left)
minright = float('-inf') if not node.left else tree_min(node.right)
return min(node.value, minleft, minright)
My verification method as
def verify(node):
if tree_max(node.left) <= node.value and node.value <= tree_min(node.right):
if verify(node.left) and verify(node.right):
return True
else:
return False
else:
return False
My problem occurs when I try to implement the verification method I seem to always get false even when I try to make a BST tree. My implementation is as follows:
root= Node(10, "Hello")
root.left = Node(15, "Fifteen")
root.right= Node(30, "Thirty")
print verify(root)
root = Node(10, "Ten")
root.right = Node(20, "Twenty")
root.left = Node(5, "Five")
root.left.right = Node(15, "Fifteen")
print verify(root)
Both are giving me False...Is there a problem with my verification function or my min/max function...Any help would be appreciated.
I see four errors in your code.
First, your check for null children is backwards in tree_min. That is, you're checking if node.right exists before accessing node.left, and vise versa.
Second, tree.min returns negative infinity when called on a leaf node. You need to use positive infinity in the min calculation (negative infinity is correct in the max version).
Third, you have a logic error within verify, as it unconditionally calls tree_min or tree_max and itself on it's child nodes, even if one or both of them are None. I suggest making all the functions handle being passed None, rather than relying on the caller to do the right thing. This also simplifies the min and max code a bit!
Lastly, you're doing your comparisons on node.value, which is the string you're giving each node. I suspect you want to be comparing using node.key instead. Comparing a float (like float("-inf")) to a string (like "ten") is an error in Python 3, and even in Python 2 where it is legal, it probably doesn't work like you would expect.
With those issues fixed, I get expected results when I create valid and invalid trees. Your two examples are both invalid though, so if you were using them to test, you will always get a False result.
Finally, a couple of minor style issues (that aren't bugs, but still things that could be improved). Python supports chained comparisons, so you can simplify your first if statement in verify to tree_max(node.left) <= node.key <= tree_min(node.right). You can further simplify that part of the code by connecting the checks with and rather than nesting an additional if statement.
Here's a version of your code that works for me (using Python 3, though I think it is all backwards compatible to Python 2):
class Node:
def __init__(self, k, val):
self.key = k
self.value = val
self.left = None
self.right = None
def tree_max(node):
if not node:
return float("-inf")
maxleft = tree_max(node.left)
maxright = tree_max(node.right)
return max(node.key, maxleft, maxright)
def tree_min(node):
if not node:
return float("inf")
minleft = tree_min(node.left)
minright = tree_min(node.right)
return min(node.key, minleft, minright)
def verify(node):
if not node:
return True
if (tree_max(node.left) <= node.key <= tree_min(node.right) and
verify(node.left) and verify(node.right)):
return True
else:
return False
root= Node(10, "Hello")
root.left = Node(5, "Five")
root.right= Node(30, "Thirty")
print(verify(root)) # prints True, since this tree is valid
root = Node(10, "Ten")
root.right = Node(20, "Twenty")
root.left = Node(5, "Five")
root.left.right = Node(15, "Fifteen")
print(verify(root)) # prints False, since 15 is to the left of 10

Categories

Resources