I am trying to implement tree data structure but I am stuck and having trouble understanding how to create a recursive function for inorder traversal for my binary tree.
This is what i have done so far:
class Node:
def __init__(self, node):
self.node = node
self.left = None
self.right= None
def inorder_traversal(self):
if self.node != None:
return inorder_traversal(self.node.left)
return self.node
return inorder_traversal(self.node.right)
I don't seem to understand what's wrong.
Test inputs:
root = Node(1)
root.left = Node(3)
root.right = Node(4)
Error:
File "trees-implementation.py", line 23, in inorder_traversal
return inorder_traversal(self.node.left)
NameError: name 'inorder_traversal' is not defined
It looks like you've defined your traversal functions with respect to the Node. Does this make sense to you?
You should define a traversal with respect to the Tree, not the Node. The Node does not know it belongs to the tree, it's a dumb object.
Define the node.
class Node:
def __init__(self, value):
self.value = value
self.left = None
self.right= None
Define the tree. Also define your traversal methods here.
class Tree:
def __init__(self, root=None):
self.root = root
def inorder_traversal(self):
def _inorder(root):
if root != None:
yield from _inorder(root.left)
yield root.value
yield from _inorder(root.right)
return list(_inorder(self.root))
Initialise the tree with a root, and then traverse it.
tree = Tree(root)
tree.inorder_traversal()
[3, 1, 4]
First, could you check if when you have your object, you don't put a parameter in
root = Node()
Then are you sure you can have several returns in your inorder_traversal() function ?
Finally, the function is in the class Node() so if you call it try to add self.yourfunction
Related
Why the binary tree is not getting inverted in this class?
class Node:
def __init__(self, data):
self.left = None
self.right= None
self.data = data
def show_tree (self):
if self.left:
self.left.show_tree()
print(self.data)
if self.right:
self.right.show_tree()
class Operation:
def invertTree(self,root):
if root:
root.left, root.right==root.right, root.left
self.invertTree(root.left)
self.invertTree(root.right)
return root
root = Node(10)
b=Node(15)
c=Node(19)
d=Node(5)
e=Node(59)
d.left=e
d.right=c
root.left=b
root.right=d
root.show_tree()
oper=Operation()
inver =oper.invertTree(root)
inver.show_tree()
The other class is returning the inverted root so finally it should return the inverted root to inver but when I display it, it shows same tree
root.left, root.right==root.right, root.left compares the values and returns a boolean, if you want to assign you need to use a single = operator
I am trying to learn Python better, and I know one can easily find the solution for adding items into BTS, but I do not understand why my implementation of add method does not work? Can someone please help?
class Node:
def __init__(self, data, left = None, right = None):
self.data = data
self.left = left
self.right = right
class Tree:
def __init__(self):
self.root = None
def add(self, data):
self.root = self._add(data,self.root)
# if I change this line with just "self._add(data,self.root)" it would not iterate tree at all..
def _add(self,data,root):
if root is None:
root = Node(data)
return root
elif data <= root.data:
root.left = self._add(data, root.left)
else:
root.right = self._add(data,root.right)
def in_order(self):
if self.root is not None:
self._in_order(self.root)
def _in_order(self, root):
if root is not None:
self._in_order(root.left)
print(str(root.data) + ' ')
self._in_order(root.right)
I am printing in classical in-order fashion. My question is after inserting a few numbers, why do I still get the result for a root node to be None ?
This kind of implementation worked for me before in C or in Java, but in Python it does not work.
EDIT: I added my in-order method.
I have also tried this but it also does not work:
def add(self,data):
if self.root == None:
self.root = Node(data)
elif data <= self.root.data:
self.root.left = self.add(self.root.left,data)
else:
self.root.right = self.add(self.root.right,data)
I get a TypeError: add() takes 2 positional arguments but 3 were given
My question is after inserting a few numbers, why do I still get the result for a root node to be None ?
With this following line, you're setting self.root to be the return value of the method _add. Since this method has no return statement, it returns None by default.
self.root = self._add(data,self.root)
I get a TypeError: add() takes 2 positional arguments but 3 were given
In this case, you're calling self.add(self.root.left,data) with three parameters: the implicit self reference, self.root.left and data.
However, the method declaration receives only the parameters self and data.
I am given a class that creates a binary tree filled with nodes.each node is given a parent and a pointer to its left or right child.
Binary tree node class:
class BTNode():
''' a class that represents a binary tree node'''
def __init__(self, data, parent=None, left_child=None, right_child=None):
'''(BTNode, obj, BTNode, BTNode, BTNode) -> NoneType
Constructs a binary tree nodes with the given data'''
self._parent = parent
self._left = left_child
self._data = data
self._right = right_child
def set_parent(self, parent):
'''(BTNode, BTNode) -> NoneType
set the parent to the given node'''
self._parent = parent
def set_left(self, left_child):
'''(BTNode, BTNode) -> NoneType
set the left child to the given node'''
self._left = left_child
def set_right(self, right_child):
'''(BTNode, BTNode) -> NoneType
set the right child to the given node'''
self._right = right_child
def set_data(self, data):
'''(BTNode, obj) -> NoneType
set the data at this node to the given data'''
self._data = data
def get_parent(self):
'''(BTNode) -> BTNode
return the pointer to the parent of this node'''
return self._parent
def get_left(self):
'''(BTNode) -> BTNode
return the pointer to the left child'''
return self._left
def get_right(self):
'''(BTNode) -> BTNode
return the pointer to the right child'''
return self._right
def get_data(self):
'''(BTNode) -> obj
return the data stored in this node'''
return self._data
def has_left(self):
'''(BTNode) -> bool
returns true if this node has a left child'''
return (self.get_left() is not None)
def has_right(self):
'''(BTNode) -> bool
returns true if this node has a right child'''
return (self.get_right() is not None)
def is_left(self):
'''(BTNode) -> bool
returns true if this node is a left child of its parent'''
# you need to take care of exception here, if the given node has not parent
return (self.get_parent().get_left() is self)
def is_right(self):
'''(BTNode) -> bool
returns true if the given node is a right child of its parent'''
# you need to take care of exception here, if the given node has not parent
return (self.get_parent().get_right() is self)
def is_root(self):
'''(BTNode) -> bool
returns true if the given node has not parent i.e. a root '''
return (self.get_parent() is None)
code example of how to create a tree:
''' create this BT using BTNode
A
/ \
B C
/\ \
D E F
/
G
'''
node_G = BTNode("G")
node_F = BTNode("F", None,node_G)
node_G.set_parent(node_F)
node_C = BTNode("C", None, None, node_F)
node_F.set_parent(node_C)
node_D = BTNode("D")
node_E = BTNode("E")
node_B = BTNode("B",None, node_D, node_E)
node_D.set_parent(node_B)
node_E.set_parent(node_B)
node_A = BTNode("A",None, node_B, node_C)
node_B.set_parent(node_A)
I dont know how to traverse this tree. I was suggested using recursion but Im not sure how. For example, I need to return True if the tree differs in height by at most 1 level,so the tree above would return true. How do I do this? Thanks!
Try to think recursively. Let's start off with a few definitions.
A tree is balanced if its left and right trees have the same height and each of it's subtrees is balanced. Also we will define an empty tree as being balanced.
The height of a tree, h(t) = 1 + max(h(t.left), h(t.right)). In English, the height of a tree is 1 + the height of its taller child tree. Also we will assume that an empty tree has a height of 0.
So for every node in the tree we can check the height of both of its children and compare them. If they aren't equal we know the tree is not balanced and we return false.
Let's start by defining the code to check if a tree is balanced.
def is_balanced(node):
if node is None:
return True
left_height = get_height(node.get_left())
right_height = get_height(node.get_right())
return left_height == right_height and is_balanced(node.get_left()) and is_balanced(node.get_right())
Now let's define the function get_height that we used above. Since the height of a tree is a function of a height of it's subtrees we can use recursion. Since recursion requires a base case so we do not recurse infinitely we can use the fact that an empty tree has a height of 0.
def get_height(node):
if node is None:
return 0 # Assuming empty tree has a height of 0
return 1 + max(get_height(node.get_left()), get_height(node.get_right()))
Now to put it all together we can recursively iterate through the tree and check that every node is balanced by calling is_balanced on the root.
is_balanced(node_A)
BONUS Exercise:
The code I gave you will work but it won't scale well. If the tree gets very large it will run much slower. Why is it slow and what can you do to make it faster?
You can traverse the left and right sides of the tree to find the maximum path length to a leaf:
class Tree:
def __init__(self, **kwargs):
self.__dict__ = {i:kwargs.get(i) for i in ['value', 'left', 'right']}
def get_length(self, current=[]):
yield current+[1]
yield from getattr(self.left, 'get_length', lambda _:[])(current+[1])
yield from getattr(self.right, 'get_length', lambda _:[])(current+[1])
def right_length(self):
return len(max(getattr(self.right, 'get_length', lambda :[[]])(), key=len))
def left_length(self):
return len(max(getattr(self.left, 'get_length', lambda :[[]])(), key=len))
t = Tree(value = 'A', left=Tree(value='B', left=Tree(value='D'), right=Tree(value='E')), right = Tree(value='C', left = Tree(value='F', left=Tree(value='G'))))
print(t.right_length() - t.left_length())
Output:
1
I understand how to insert using recursion. I also understand why this code doesn't work as expected because while I'm updating the variable "current" in the "insert" method, I'm only attaching the name label "current" to some node, copy that node to "current" and modify "current", but not the actual node in the binary search tree.
So how can I actually modify the node in the binary search tree using the iterative concept here? And more generally speaking, how can I make a "shallow copy" to any object I created and actually modify that object? A "list" object in Python is an example that has the desired property. What code in "list" makes it behave this way? Thanks in advance.
class Node:
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right
class BinarySearchTree:
def __init__(self, root=None):
self.root = root
def insert(self, data):
if self.root:
current = self.root
while current:
if data < current.data:
current = current.left
elif data > current.data:
current = current.right
current = Node(data)
else:
self.root = Node(data)
bst = BinarySearchTree()
bst.insert(2)
bst.insert(1)
bst.insert(3)
I hope someone can help me, I'm not a programming professional, but am using Python to learn and experiment with binary trees.
Below is the code I have, and have attempted to try and store a reference to a node's parent in it's node, the storing of it's parent node, won't work for leaf nodes though. Is there a way of doing this during the process of building the tree?
I'd also like to know for a given node, whether is's a 'Left or 'Right' node. I thought seeing as the node is stored in an instance of TreeNode.left or TreeNode.right, I might be able to get a reference to this in Python, as in n._name_ or something like that. Could you tell me the correct way to find whether a node is left or right?
My ultimate goal will be to visualise my tree through a level order traversal.
class TreeNode:
left, right, data = None, None, 0
def __init__(self,nodeData, left = None, right = None, parent = None):
self.nodeData = nodeData
self.left = left
self.right = right
self.parent = self
class Tree:
def __init__(self):
self.root = None
def addNode(self, inputData):
return TreeNode(inputData)
def insertNode(self, parent, root, inputData):
if root == None:
return self.addNode(inputData)
else:
root.parent = parent
if inputData <= root.nodeData:
root.left = self.insertNode(root, root.left, inputData)
else:
root.right = self.insertNode(root, root.right, inputData)
return root
There are many, many things wrong with this. Since it's homework, I'll supply one hint.
def __init__(self,nodeData, left = None, right = None, parent = None):
self.nodeData = nodeData
self.left = left
self.right = right
self.parent = self
Why isn't self.parent set to parent?