AVL Tree in python - python

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.

Related

Binary Search Tree inorder not working (python)

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()

Binary Search trees implementation using python

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

How can I run this Height of a BST tree function

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.

Binary seach tree, remove node, need help here (reposting)

My code is looking like this:
class Treenode:
def __init__(self,data,left=None,right=None):
self.data=data
self.left=left
self.right=right
def __str__(self):
return str(self.data)
def delete(self):
child=self.left
grandchild=child.right
print(grandchild)
if self.left == self.right==None:
return None
if self.left==None:
return self.right
if self.right==None:
return self.left
if grandchild:
while grandchild.right:
child = grandchild
grandchild = child.right
self.data = grandchild.data
child.right = grandchild.left
else:
self.left = child.left
self.data = child.data
return self
class Bintree:
def __init__(self):
self.root = None
def put(self,data):
if self.root == None:
self.root = Treenode(data)
return
p = self.root
while True:
if data < p.data:
if p.left == None:
p.left = Treenode(data)
return
else:
p = p.left
elif data > p.data:
if p.right == None:
p.right = Treenode(data)
return
else:
p = p.right
elif data == p.data:
return False
else:
return
def exists(self, data):
return finns(self.root, data)
def isempty(self):
return self.root == None
def height(self):
def hp(tree):
if tree is None:
return 0
else:
return 1 + max(hp(tree.left), hp(tree.right))
return hp(self.root)
def printTree(self):
skriv(self.root)
def remove(self, data):
if self.root and self.root.data == data: #self.root kanske inte behövs, undersök
self.root = self.root.delete()
return
else:
parent = self.root
while parent:
if data < parent.data:
child = parent.left
if child and child.data== data:
parent.left = child.delete()
return
parent = child
else:
child = parent.right
if child and child.data == data:
parent.right = child.delete()
return
parent = child
def skriv(tree):
if tree == None:
return
skriv(tree.left)
print(tree.data)
skriv(tree.right)
def finns(roten, key):
if roten == None:
return False
if key == roten.data:
return True
elif key < roten.data:
return finns(roten.left, key)
else:
return finns(roten.right, key)
Everything about my code is working, and I've simply added (see copied) the delete method and the remove method. Im desperately trying to understand the delete-method but I cannot understand it. I use this code to run the thing and see how the tree is implemented:
from labb8test import Bintree
from labb8test import Treenode
tree = Bintree()
tree.put(8)
tree.put(3)
tree.put(1)
tree.put(6)
tree.put(4)
tree.put(7)
tree.put(10)
tree.put(14)
tree.put(13)
tree.remove(6)
tree.printTree()
I'm trying to draw it on a paper and see, especially how the while-loop is working. According to my above code, I would think it is like this:
child = self.left (child=3) grandchild= child.right=self,left.right=6. If grandchild (yes, 6) while grandchild.right (yes, 7) child = grandchild, 3-->6 grandchild = child.right (is this even needed, 6--->6?) self.data=grandchild.data (8--->6) child.right = grandchild.left (6---->4) ??
But it cannot be like this, because then the while-loop would never end. Is there anyone who can help me understanding where I lose myself?
I recommend you this material from algorithm Princeton:
http://algs4.cs.princeton.edu/32bst/
The delete method is using this approach to delete a node from a bst.
Delete. We can proceed in a similar manner to delete any node that has
one child (or no children), but what can we do to delete a node that
has two children? We are left with two links, but have a place in the
parent node for only one of them. An answer to this dilemma, first
proposed by T. Hibbard in 1962, is to delete a node x by replacing it
with its successor. Because x has a right child, its successor is the
node with the smallest key in its right subtree. The replacement
preserves order in the tree because there are no keys between x.key
and the successor's key. We accomplish the task of replacing x by its
successor
in four (!) easy steps:
Save a link to the node to be deleted in t
Set x to point to its successor min(t.right)
Set the right link of x (which is supposed to point to the BST containing all the keys larger than x.key) to deleteMin(t.right), the
link to the BST containing all the keys that are larger than x.key
after the deletion.
Set the left link of x (which was null) to t.left (all the keys that are less than both the deleted key and its successor).

Binary Search Tree operations

I am trying to implement Binary Search Tree operations in python. As of now, I have written some code to add nodes to this search tree (sorted).
Here's what I've in my code:
class TreeNode:
def __init__(self, data):
self.data = data
self.lLink = None
self.rLink = None
class BinaryTree:
def __init__(self):
self.root = None
def AddNode(self, data):
if self.root is None:
self.root = TreeNode(data)
else:
if data < self.root.data:
if self.root.lLink is None:
self.root.lLink = TreeNode(data)
else:
AddNode(self.root.lLink, data)
else:
if self.root.rLink is None:
self.root.rLink = TreeNode(data)
else:
AddNode(self.root.rLink, data)
def InOrder(self, head):
if self.root.lLink is not None:
InOrder(self.root.lLink)
print self.root.data,
if self.root.rLink is not None:
InOrder(self.root.rLink)
myTree = BinaryTree()
myTree.AddNode(15)
myTree.AddNode(18)
myTree.AddNode(14)
How do I test if my AddNode() method is correct? I know the algorithm but just to be sure.
What I was thinking of is to create an InOrder() method and try to print elements through this InOrder traversal. As a result, my data added to the tree should be displayed in sorted order. If it is displayed in sorted order, I'll be sure that both my AddNode() and InOrder() methods are correct.
Your BinaryTree class is faulty, changing the order of insertions to
myTree.AddNode(14)
myTree.AddNode(18)
myTree.AddNode(15)
raises an error - NameError: global name 'AddNode' is not defined.
This is because in the lines, AddNode(self.root.rLink, data) and AddNode(self.root.lLink, data) you seem to be calling the AddNode function on instances of TreeNode which is not possible. I fixed up some of the errors in your code and it should work great now.
class TreeNode:
def __init__(self, data):
self.data = data
self.lLink = None
self.rLink = None
class BinaryTree:
def __init__(self):
self.root = None
def AddNode(self, data):
if self.root is None:
self.root = TreeNode(data)
else:
self.AddHelper(data, self.root)
def AddHelper(self, data, startingPoint):
if data < startingPoint.data:
if startingPoint.lLink is None:
startingPoint.lLink = TreeNode(data)
else:
self.AddHelper(data, startingPoint.lLink)
else:
if startingPoint.rLink is None:
startingPoint.rLink = TreeNode(data)
else:
self.AddHelper(data, startingPoint.rLink)
def InOrder(self):
self.InOrderHelper(self.root)
def InOrderHelper(self, startingPoint):
if startingPoint is None:
return
self.InOrderHelper(startingPoint.lLink)
print startingPoint.data,
self.InOrderHelper(startingPoint.rLink)
Output Test :
>>> myTree = BinaryTree()
>>> myTree.AddNode(14)
>>> myTree.AddNode(18)
>>> myTree.AddNode(15)
>>> myTree.InOrder()
14 15 18
Inserting can be a little tricky, especially because the function is a part of the tree itself. So, you call the insert function on the tree, but specifying a starting point. This defaults to root, so you can leave the argument when you call the function.
Also, I think you are a little unclear about how self works in a function. You cannot pass it as an argument to the function, which is what it seems you have done.
class TreeNode:
def __init__(self, data):
self.data = data
self.rLink = None
self.lLink = None
class BinaryTree:
def __init__(self):
self.root = None
def AddNode(self, data, node=None):
if not node :
node = self.root
if self.root is None:
self.root = TreeNode(data)
else:
if data < node.data:
if node.lLink is None:
node.lLink = TreeNode(data)
else:
self.AddNode(data, self.root.lLink)
else:
if node.rLink is None:
node.rLink = TreeNode(data)
else:
self.AddNode(data, self.root.rLink)
def InOrder(self, head):
if head.lLink is not None:
self.InOrder(head.lLink)
print head.data,
if head.rLink is not None:
self.InOrder(head.rLink)
myTree = BinaryTree()
myTree.AddNode(14)
myTree.AddNode(15)
myTree.AddNode(18)
myTree.InOrder(myTree.root)
Testing the insert function with an in-order traversal is the best approach.
This should work. You are not going down the tree if you use self.root.lLink every time.
Optionally, you could write one more line of code to check if the output is indeed in ascending order.

Categories

Resources