I want to write method mirror() which creates and return binary tree where all left subtrees become right subtrees and vice versa. I tried to do this with recursion:
def mirror(self):
if self.left == None and self.right == None:
return
elif self.left == None and self.right != None:
t = self.right
self.right = self.left
self.left = t
self.left.mirror()
elif self.left != None and self.right == None:
t = self.right
self.right = self.left
self.left = t
self.right.mirror()
else:
t = self.right
self.right = self.left
self.left = t
self.left.mirror()
self.right.mirror()
But I get output None. Why, and how to fix it?
Your current function swaps all the branches in-place; there's no particular need to return the tree, since you already have a reference to it if you managed to call the method in the first place. But if you want return such a reference anyway, you can:
def mirror(self):
if self.left == None and self.right == None:
pass
elif self.left == None and self.right != None:
t = self.right
self.right = self.left
self.left = t
self.left.mirror()
elif self.left != None and self.right == None:
t = self.right
self.right = self.left
self.left = t
self.right.mirror()
else:
t = self.right
self.right = self.left
self.left = t
self.left.mirror()
self.right.mirror()
return self
or more simply:
def mirror(self):
if self.left is not None:
self.left.mirror()
if self.right is not None:
self.right.mirror()
self.left, self.right = self.right, self.left
return self
If, on the other hand, you want a new tree independent of the original tree, you need to construct one to return.
def mirror(self):
new_tree = ... # Whatever you do to create a root node from the root of self
# If the child pointers aren't already None after creating the node
new_tree.left = None
new_tree.right = None
if self.right is not None:
new_tree.left = self.right.mirror()
if self.left is not None:
new_tree.right = self.left.mirror()
return new_tree
Related
I currently have my code set up so I have a class that creates the first node of a binary search tree. Then, using a create_node method, I can add whatever node. How can I return the children of each created note?
When I run the following, I get an output of "Left child: None Right Child: None" when it should be "Left child: 3 Right Child: 7"
I'd assume it has something to do with the dictionary not being updated? If this is the case, how can I continually update it? Thank you!
totaldict = {}
class TreeNode:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def search(self, value):
if value < self.data:
if self.left == None:
return False
else:
return self.left.search(value)
elif value > self.data:
if self.right == None:
return False
else:
return self.right.search(value)
else:
return True
def create_node(self, value):
if value < self.data:
if self.left == None:
self.left = TreeNode(value)
totaldict[value] = TreeNode(value)
else:
return self.left.create_node(value)
elif value > self.data:
if self.right == None:
self.right = TreeNode(value)
totaldict[value] = TreeNode(value)
else:
return self.right.create_node(value)
else:
print("Node already exists")
def pos_child(self, value):
if self.search(value):
if value in totaldict:
return "Left child: " + str(totaldict[value].left) + " Right Child: " + str(totaldict[value].right)
else:
print("Node does not exist, use create_node method")
root = TreeNode(10)
root.create_node(5)
root.create_node(15)
root.create_node(3)
root.create_node(7)
print(root.pos_child(5))
The problem is here:
if self.right == None:
self.right = TreeNode(value)
totaldict[value] = TreeNode(value) # HERE
You create new TreeNode but it's not connected at all to root so it never gets any children. Change it to:
if self.right == None:
self.right = TreeNode(value)
totaldict[value] = self.right
And do the same for left subtree.
How can I find the minimum node in this binary search tree. I can't make it work.
....................................................................
....................................................................
class BinarySearchTree:
def __init__(self, root):
self.root = root
self.left = None
self.right = None
def insert(self, node):
if node == self.root:
return
elif node < self.root:
if self.left:
self.left.insert(node)
else:
self.left = BinarySearchTree(node)
else:
if self.right:
self.right.insert(node)
else:
self.right = BinarySearchTree(node)
def search(self, target):
if target == self.root:
return True
else:
if target < self.root:
if self.left:
return self.left.search(target)
return False
if target > self.root:
if self.right:
return self.right.search(target)
return False
def find_min(self, root):
# traverse left subtree
while root is not None:
root = self.left
return root
def find_min(self):
# traverse left subtree
current = self
while self.left is not None:
current = self.left
return current.root
tree = BinarySearchTree("10")
tree.insert("20")
tree.insert("30")
print(tree.search("20")) # output: True
print(tree.search("40")) # output: False
print(tree.find_min()) # output: 10
By making a node to be deleted from the tree, the node (case 1) can be a node with a single arm (right or left), or a node with both branches. In case the node to be deleted is an intermediate node with two branches, there are 2 different methods.
Method 1: the largest knot on the left arm or the smallest knot on the right arm, and
Method 2: The node in the branch with more depth (or the number of elements) is fulfilled so that the right or left arm is balanced.
Both methods have to be coded with separate functions.
How can I do these two methods?
class Node:
def __init__(self, data):
self.left = None
self.right = None
self.parent = None # new
self.data = data
def insert(self, data):
if self.data: # add by comparison
if data < self.data: # left if small
if self.left is None: # add left if left is blank
self.left = Node(data)
self.left.parent = self # new
else:
self.left.insert(data) # if left is not empty add to left sub-tree
elif data > self.data: # right if greater
if self.right is None: # add right if right is blank
self.right = Node(data)
self.right.parent = self # new
else: # if right is not empty add to sub-tree right
self.right.insert(data)
else:
self.data = data # the first dream of the tree
# print Tree
def PrintTree(self):
print( self.data,end='-')
if self.left:
self.left.PrintTree()
if self.right:
self.right.PrintTree()
def sizeTree(self):
if self.left and self.right:
return 1 + self.left.sizeTree() + self.right.sizeTree()
elif self.left:
return 1 + self.left.sizeTree()
elif self.right:
return 1 + self.right.sizeTree()
else:
return 1
def depth(self):
if self.left and self.right:
l = self.left.depth()
r = self.right.depth()
return 1 + max(l,r)
elif self.left:
return 1 + self.left.depth()
elif self.right:
return 1 + self.right.depth()
else:
return 1
# Use the insert method to add nodes
root = Node(25)
root.insert(12)
root.insert(10)
root.insert(22)
root.insert(5)
root.insert(36)
root.insert(30)
root.insert(40)
root.insert(28)
root.insert(38)
root.insert(48)
root.PrintTree()
"""
# 25,36,20,10,5,22,40,48,38,30,22,12,28
root = Node(25)
root.insert(36)
root.insert(20)
root.insert(10)
root.insert(5)
root.insert(22)
root.insert(40)
root.insert(48)
root.insert(38)
root.insert(30)
root.insert(12)
root.insert(28)
print("\n",root.sizeTree(),root.depth())
"""
Some time ago I was playing with this and came up with this code:
def search(self, value):
"""
Recursively looks to the left and right of Tree depending on the provided value
and returns it if it is present within Tree.
Args:
value (int): value to be searched for within Tree
Returns:
value if value exists in Tree otherwise None
"""
if value < self.data:
if self.left is None:
return None
return self.left.search(value)
elif value > self.data:
if self.right is None:
return None
return self.right.search(value)
else:
return self.data
def _findNodeToDelete(self, value, previous=None):
"""
Recursively looks to the left and right of Tree depending on the provided value
and returns it if it is present within Tree.
Args:
value (int): value to be searched for within Tree
Returns:
value if value exists in Tree otherwise None
"""
if value < self.data:
if self.left is None:
return None
return self.left._findNodeToDelete(value, self)
elif value > self.data:
if self.right is None:
return None
return self.right._findNodeToDelete(value, self)
else:
return self, previous
def _mergeNodes(self, target):
self.data = target.data
self.left = target.left
self.right = target.right
def deleteNode(self, value, start=None):
if self.search(value):
to_delete, parent = self._findNodeToDelete(value, start)
if to_delete.right and to_delete.left:
new_value = to_delete.right.min
to_delete.data = new_value
to_delete.right.deleteNode(new_value, to_delete)
elif to_delete.left:
to_delete._mergeNodes(to_delete.left)
elif to_delete.right:
to_delete._mergeNodes(to_delete.right)
else:
if parent:
if parent.data > value:
parent.left = None
else:
parent.right = None
else:
self.data = None
Note, I don't use parent attribute, rather calculate it while deleting.
So, I am trying to define a function which would invert a binary tree, and when I run the below code, and then execute a_node.binInversion(), I get the error which says, "NameError: name 'binInversion' is not defined". Why is that error happening?
The code I'm executing is as below:
class BinaryTree:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def insert_left(self, value):
if self.left == None:
self.left = BinaryTree(value)
else:
new_node = BinaryTree(value)
new_node.left = self.left
self.left = new_node
def insert_right(self, value):
if self.right == None:
self.right = BinaryTree(value)
else:
new_node = BinaryTree(value)
new_node.right = self.right
self.right = new_node
def binInversion(self):
if self.left is None and self.right is None:
return 0
else:
binInversion(self.left)
binInversion(self.right)
self.left, self.right = self.right, self.left
a_node = BinaryTree('a')
a_node.insert_left('b')
a_node.insert_right('c')
b_node = a_node.left
b_node.insert_right('d')
c_node = a_node.right
c_node.insert_left('e')
c_node.insert_right('f')
d_node = b_node.right
e_node = c_node.left
f_node = c_node.right
a_node.binInversion()
Also, I know that there are high chances of binInversion() function not working as expected. Please DO NOT disclose the solution for inverting a binary tree, as I want to give it a shot on my own before looking at the solution.
a few bugs here:
binInversion is not a function, it is a class method, remember to call self.binInversion() instead of binInversion()
after the above fix, there will still be an error that says something along the lines of binInversion was given too many arguments. Your method of binInversion takes no arguments, try something like def binInversion(self, node) to pass in another argument or node.
I am trying to write AVL tree in python but rotation doesnt work becase I cannot swap "self" node with any other. Is there any way to fix it? I think that doing this in Java or C way is not correct...
class Sentinel(object):
value = left = right = None
height = -1
sentinel = Sentinel() #singleton of sentinel node
class Node:
def __init__(self, data, left=sentinel, right=sentinel, height=0):
self.data = data
self.left = left
self.right = right
self.height = height
def addNode(self, data):
if self.data == data:
#return when node duplicated
return
isLeft = self.data > data
child = self.left if isLeft else self.right
if child is sentinel:
if isLeft:
self.left = Node(data)
else:
self.right = Node(data)
else:
child.addNode(data)
if abs(child.right.height - child.left.height) == 2:
print("Rebalancing after inserting", data)
''' Then we need to balance a subtree'''
if data < child.data:
rotation = self.rotateLeft if isLeft else self.rotateRight
else:
rotation = self.doubleRotateLeft if isLeft else self.doubleRotateRight
rotation()
self.left.setHeight() if isLeft else self.right.setHeight()
self.setHeight()
def printNodes(self):
if self.left is not sentinel:
self.left.printNodes()
print(self)
if self.right is not sentinel:
self.right.printNodes()
def setHeight(self):
self.height = max(self.left.height, self.right.height) + 1
def rotateRight(self):
new_root = self.left
new_left_sub = new_root.right
old_root = self
self = new_root
old_root.left = new_left_sub
new_root.right = old_root
def rotateLeft(self):
new_root = self.right
new_left_sub = new_root.left
old_root = self
self = new_root
old_root.right = new_left_sub
new_root.left = old_root
def doubleRotateRight(self):
return
def doubleRotateLeft(self):
return
def __str__(self):
return str(self.data)
class binaryTree:
def __init__(self):
self.root = sentinel
def add(self, data):
print("Before adding", data)
self.printAll()
if self.root is sentinel:
self.root = Node(data)
else:
self.root.addNode(data)
def printAll(self):
if self.root is sentinel:
print("Empty tree")
else:
self.root.printNodes()
if __name__ == '__main__':
b = binaryTree()
b.add(1)
b.add(22)
b.add(4)
b.add(26)
b.add(13)
b.add(3)
b.add(14)
b.add(6)
b.add(13)
b.add(5)
b.add(36)
b.add(43)
b.add(5)
for i in range(1, 20):
b.add(i)
b.printAll()
I would suggest that your nodes contain a link to the parent (the root having itself as a parent). Then its easy:
def rotateLeft(self):
new_root = self.right
new_left_sub = new_root.left
old_root = self
self.parent.right = new_root #assuming self is a right child
old_root.right = new_left_sub
new_root.left = old_root
My code may not be correct, I can't test it right now, but the idea is: have the nodes keep a reference to the parent.
Some reference: http://interactivepython.org/runestone/static/pythonds/Trees/AVLTreeImplementation.html