can someone help me out with this? I implemented a binary search tree data structure in python and I wrote a BST_height() function to calculate the height of the tree. But when I ran my code, It gave me an error saying 'self is not defined'. I know why the error is showing up but can you suggest some other way to run the BST_height function with the root node
class Node:
def __init__(self, data=None):
self.data = data
self.left = None
self.right = None
class BinarySearchTree:
def __init__(self):
self.root = Node()
def display(self):
print('''
{}
/ \\
{} {}
/ \\ / \\
{} {} {} {}
BINARY TREE
'''.format(tree.root.data, tree.root.left.data, tree.root.right.data, tree.root.left.left.data, tree.root.right.right.data, tree.root.left.right.data, tree.root.right.left.data))
def checkRoot(self):
if self.root.data != None:
return 'Root node exists'
else:
return 'Root node doesn\'t exists'
def insert(self, data):
newNode = Node(data)
if self.root.data == None:
# creating the root node
self.root = newNode
else:
self.insertNode(data, self.root)
def insertNode(self, data, curNode):
if data < curNode.data:
if curNode.left == None:
curNode.left = Node(data)
else:
self.insertNode(data, curNode.left)
elif data > curNode.data:
if curNode.right == None:
curNode.right = Node(data)
else:
self.insertNode(data, curNode.right)
else:
print('The value already exists ha ha')# funny
def BST_height(self, node):
if node == None:
return -1
leftHeight = height(node.left)
rightHeight = height(node.right)
return max(leftHeight, rightHeight) + 1
tree = BinarySearchTree()
tree.insert(30)# root node
tree.insert(24)
tree.insert(45)
tree.insert(90)
tree.insert(18)
tree.insert(28)
tree.insert(40)
tree.display()
# getting an error here
# I know self.root can\'t be used outside the class but can you suggest some other way tree.BST_height(self.root)
There are 2 problems with the code:
Self is something you use inside of class functions. Outside you can simply use the object variable. like so:
tree.BST_height(tree.root)
BST_height function has a small error in it. It calls height instead of self.BST_height:
def BST_height(self, node):
if node == None:
return -1
leftHeight = self.BST_height(node.left)
rightHeight = self.BST_height(node.right)
return max(leftHeight, rightHeight) + 1
You might want to read this for clarity on the whole self topic.
Related
I've been messing around learning about objects and classes, and as I finally felt that I managed to wrap my head around how to construct a Binary Search Tree in python, I ran into an issue. Here's my code:
class node:
def __init__(self,value):
self.value = value
self.left = None
self.right = None
class BST:
def __init__(self):
self.root = None
def add(self,current,value):
if self.root == None:
self.root = node(value)
else:
if value < current.value:
if current.left == None:
current.left = node(value)
else:
self.add(current.left,value)
if value > current.value:
if current.right == None:
current.right = node(value)
else:
self.add(current.right,value)
def visit(self,node):
print(node.value)
def inorder(self,current):
self.inorder(current.left)
self.visit(current)
self.inorder(current.right)
Tree = BST()
root = node(2)
Tree.root = root
Tree.add(Tree.root,7)
Tree.inorder(Tree.root)
after running the code, I got an error: AttributeError: 'NoneType' object has no attribute 'left'.
The error comes out of the inorder function, as apparently the value I'm inserting into the function is an object without a type.
as you can see, the root of the tree is a node object, so it should have the attribute "left" as per coded in the class. I would really appreciate if someone could help me with what I'm getting wrong.
Thanks in advance!
EDIT: I should note that I checked whether the root is a node with the isinstance(), function, and indeed it returned True.
I think you sould check current is not None before access its left and right.
def inorder(self, current):
if current:
self.inorder(current.left)
self.visit(current)
self.inorder(current.right)
Your design has some problems. The Tree should be the only object that knows about the root. You shouldn't have to pass the root in. Notice how this is simpler to use:
class node:
def __init__(self,value):
self.value = value
self.left = None
self.right = None
class BST:
def __init__(self):
self.root = None
def add(self,value,current=None):
if not self.root:
self.root = node(value)
return
if not current:
current = self.root
if value < current.value:
if not current.left:
current.left = node(value)
else:
self.add(value,current.left)
else:
if not current.right:
current.right = node(value)
else:
self.add(value, current.right)
def visit(self,node):
print(node.value)
def inorder(self,current=-1):
if current == -1:
current = self.root
if not current:
return
self.inorder(current.left)
self.visit(current)
self.inorder(current.right)
Tree = BST()
Tree.add(2)
Tree.add(7)
Tree.inorder()
class Node:
def __init__(self, data, parent):
self.leftChild = None
self.rightChild = None
self.parent = parent
self.data = data
class BST:
def __init__(self):
self.root = None
self.count = 0
def insert(self, data):
self.count +=1
if self.root is None:
self.root = Node(data, None)
else:
self.insertNode(data,self.root)
def insertNode(self, data, parentNode):
if data < parentNode.data:
if parentNode.leftChild is not None:
self.insertNode(data, parentNode.leftChild)
else:
parentNode.leftChild = Node(data, parentNode)
else:
if parentNode.rightChild is not None:
self.insertNode(data, parentNode.rightChild)
else:
parentNode.rightChild = Node(data, parentNode)
def get_max(self, node):
if node.rightChild:
self.get_max(node.rightChild)
else:
print(node.data)
# return node.data
# return node.data
def traverse(self):
if(self.root is not None):
self.traverse_InOrder(self.root)
def traverse_InOrder(self, node):
if node.leftChild is not None:
self.traverse_InOrder(node.leftChild)
print(node.data, end=" ")
if node.rightChild is not None:
self.traverse_InOrder(node.rightChild)
bst = BST()
bst.insert(22)
bst.insert(2)
bst.insert(21)
bst.insert(23)
bst.insert(45)
bst.insert(43)
bst.insert(20)
bst.traverse()
print()
bst.get_max(bst.root)
print(bst.get_max(bst.root))
In the get_max function when I'm printing node.data it's working fine, but as soon as I'm returning the data and trying to print it as shown in last line of code, it's returning none.
I don't understand the underlying concept behind it.
Maybe it is something that I'm doing wrong.
Please explain.
Change the get_max function so it returns the rightmost node:
def get_max(self, node):
if node.rightChild:
return self.get_max(node.rightChild)
else:
return node.data
I am currently having trouble with a AVL tree in Python 3. I have wrote out the source code that I am following which is on a video, but it is acting strange and I have no idea why.
Here is the code:
class Node(object):
def __init__(self, data, parentNode):
self.data = data
self.parentNode = parentNode
self.rightChild = None
self.leftChild = None
self.balance = 0
def insert(self, data, parentNode):
if data < self.data:
if not self.leftChild:
self.leftChild = Node(data, parentNode)
else:
self.leftChild.insert(data, parentNode)
else:
if not self.rightChild:
self.rightChild = Node(data, parentNode)
else:
self.rightChild.insert(data, parentNode)
return parentNode
def traverseInOrder(self):
if self.leftChild:
self.leftChild.traverseInOrder()
print(self.data)
if self.rightChild:
self.rightChild.traverseInOrder()
def getMax(self):
if not self.rightChild:
return self.data
else:
return self.rightChild.getMax()
def getMin(self):
if not self.leftChild:
return self.data
else:
return self.leftChild.getMin()
class BalancedTree(object):
def __init__(self):
self.rootNode = None
def insert(self, data):
parentNode = self.rootNode
if self.rootNode == None:
parentNode = Node(data, None)
self.rootNode = parentNode
else:
parentNode = self.rootNode.insert(data, self.rootNode)
self.rebalanceTree(parentNode)
def rebalanceTree(self, parentNode):
self.setBalance(parentNode)
if parentNode.balance < -1:
if self.height(parentNode.leftChild.leftChild) >= self.height(parentNode.leftChild.rightChild):
parentNode = self.rotateRight(parentNode)
else:
parentNode = self.rotateLeftRight(parentNode)
elif parentNode.balance > 1:
if self.height(parentNode.rightChild.rightChild) >= self.height(parentNode.rightChild.leftChild):
parentNode = self.rotateLeft(parentNode)
else:
parentNode = self.rotateRightLeft(parentNode)
if parentNode.parentNode is not None:
self.rebalanceTree(parentNode.parentNode)
else:
self.rootNode = parentNode
def rotateLeftRight(self, node):
print("Rotation left right....")
node.leftChild = self.rotateLeft(node.leftChild)
return self.rotateRight(node)
def rotateRightLeft(self, node):
print("Rotation right left....")
node.rightChild = self.rotateRight(node.rightchild)
return self.rotateLeft(node)
def rotateLeft(self, node):
print("Rotate left....")
b = node.rightChild
b.parentNode = node.parentNode
node.rightChild = b.leftChild
if node.rightChild is not None:
node.rightChild.parentNode = node
b.leftChild = node
node.parentNode = b
if b.parentNode is not None:
if b.parentNode.rightChild == node:
b.parentNode.rightChild = b
else:
b.parentNode.leftChild = b
self.setBalance(node)
self.setBalance(b)
return b
def rotateRight(self, node):
print("Rotation right....")
b = node.leftChild
b.parentNode = node.parentNode
node.leftChild = b.rightChild
if node.leftChild is not None:
node.leftChild.parentNode = node
b.rightChild = node
node.parentNode = b
if b.parentNode is not None:
if b.parentNode.rightChild == node:
b.parentNode.rightChild = b
else:
b.parentNode.leftChild = b
self.setBalance(node)
self.setBalance(b)
return b
def setBalance(self, node):
node.balance = (self.height(node.rightChild) - self.height(node.leftChild))
def height(self, node):
if node == None:
return -1
else:
return 1 + max(self.height(node.leftChild), self.height(node.rightChild))
As I test this, this is what happens.
I create a tree:
tree = BalancedTree()
I then try to insert 3 intergers.
tree.insert(4)
tree.insert(2)
Now when I enter the third interger.
tree.insert(3)
I get this output without calling any functions.
Rotation left right....
Rotate left....
Rotation right....
That is what happens. I try to traverse the tree. I receive this error.
Traceback (most recent call last): File "", line 1, in
tree.traverseInOrder() AttributeError: 'BalancedTree' object has no attribute 'traverseInOrder'
Yet the video I am following his code works fine. I am lost as I have relooked over the code to see if I made a mistake somewhere and doesn't seem like I have. What am I missing? In his code there is no traverseInOrder function for the tree itself. Yet he is able to call it and run it just fine. Can someone explain why this is happening? Please and thank you.
The immediate problem is that your indentation is incorrect for the usage you give. As posted, class node consists of only this:
class Node(object):
def __init__(self, data, parentNode):
self.data = data
self.parentNode = parentNode
self.rightChild = None
self.leftChild = None
self.balance = 0
Then you have a few independent functions, followed by your trivial balancedTree class, and a few other independent functions.
However, this wouldn't allow you to insert a value the way you've done it, so it appears that the posted code is not what produced the output you give.
UPDATE
I fixed the indentation. The code appears to properly insert and balance the tree of 3 nodes. However, there is no error. The line of code you cite,
tree.traverseInOrder()
does not appear in your posted code. Without accurate code and the full error message, including the full traceback, we can't debug your problem.
I also tried adding that line at the bottom of your code, and finally got the error message you cite. The run-time system is correct (no surprise): there is no traverseInOrder method for class BalancedTree. That name does exist for class Node, but that's not what you called. You've confused your two classes. Sort this out, and the code may well work.
I am implementing BST in python and having some trouble on insertion function.
class Node:
def __init__(self, val):
self.data = val
self.Leftchild = self.Rightchild = None
class Tree:
def __init__(self):
self.root = None
def insert(self, val):
if self.root is None:
self.root = Node(val)
return self.root
else:
if self.root.data <= val:
self.root.Rightchild = self.insert(self.root.Rightchild, val)
else:
self.root.Leftchild = self.insert(self.root.Leftchild, val)
return self.root
if __name__ == '__main__':
tree = Tree()
for i in range(10):
tree.insert(random.randint(0,100))
I got TypeError on recursive.
TypeError: insert() takes 2 positional arguments but 3 were given
Isn't self.root.Rightchild or self.root.Leftchild considered same as self?
If my thought is wrong, how can I implement recursive insertion function in this case?
Thanks in advance!
You should have insert take another argument, root, and do your operations on that. You'll need to modify the recursive logic too. Have insert work exclusively with the Node data.
You should handle cases where an item already exists. You don't want duplicates put into the tree.
In the recursive case, you are calling insert on the wrong object.
Also, the two are not the same. self refers to the current Tree object, and self.root refers to the current Tree's Node object, and so on.
This is how you'd modify your function:
def insert(self, root, val):
if root is None:
return Node(val)
else:
if root.data <= val:
root.Rightchild = self.insert(root.Rightchild, val)
else:
root.Leftchild = self.insert(root.Leftchild, val)
return root
Try this one if you need class and its instance
import random
class Node:
def __init__(self, val):
self.data = val
self.Leftchild = self.Rightchild = None
class Tree:
def insert(self,root, val):
if root is None:
root = Node(val)
return root
else:
if root.data <= val:
root.Rightchild = self.insert(root.Rightchild, val)
else:
root.Leftchild = self.insert(root.Leftchild, val)
return root
def inorder(self, root):
if root:
self.inorder(root.Leftchild)
print root.data,
self.inorder(root.Rightchild)
if __name__ == '__main__':
tree = Tree()
root = None
for i in range(10):
root = tree.insert(root, random.randint(0,100))
tree.inorder(root)
Try this..
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def inorder(root):
if root:
inorder(root.left)
arr.append(root.data)
print root.data,
inorder(root.right)
def insert(root, data):
node = Node(data)
if root is None:
root = node
elif root.data >= data:
if root.left is None:
root.left = node
else:
insert(root.left, data)
else:
if root.right is None:
root.right = node
else:
insert(root.right, data)
if __name__ == '__main__':
root = Node(50)
insert(root, 30)
insert(root, 20)
insert(root, 40)
insert(root, 70)
insert(root, 60)
insert(root, 80)
inorder(root)
I'm trying to implement a BST, and am working on insert. I want to be able to call something simple, like tree.insert(Node(1)). But the issue is that this binaryInsert doesn't persist. What's the best way to achieve this functionality?
class Node:
def __init__(self, data):
self.value = data
self.rightChild = None
self.leftChild = None
class Tree:
def __init__(self):
self.root = None
def binaryInsert(self, root, node):
if root == None:
root = node
else:
if root.value > node.value:
if root.leftChild == None:
root.leftChild = node
else:
self.binaryInsert(root.leftChild, node)
else:
if root.rightChild == None:
root.rightChild = node
else:
self.binaryInsert(root.rightChild, node)
def insert(self, node):
self.binaryInsert(self.root, node)
consider these lines from your code:
def binaryInsert(self, root, node):
if root == None:
root = node
here you are just overriding a local root variable (scoped to the method), I've corrected your code, feel free to ask any question:
class Node:
def __init__(self, data):
self.value = data
self.rightChild = None
self.leftChild = None
class Tree:
def __init__(self):
self.root = None
def binaryInsert(self, tree, node):
if tree.root == None:
tree.root = node
else:
if tree.root.value > node.value:
if tree.root.leftChild == None:
tree.root.leftChild = node
else:
self.binaryInsert(tree.root.leftChild, node)
else:
if tree.root.rightChild == None:
tree.root.rightChild = node
else:
self.binaryInsert(tree.root.rightChild, node)
def insert(self, node):
self.binaryInsert(self, node)