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

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

Related

Delete a branch in Binary tree( Linked List implementation)

I am trying to create a binary tree using a linked list. I want to delete a node in a binary tree, the way I implemented is to set the address(pointer) to the branch that I want to delete as None, but when I run the traversal methods, the branch still shows up.
here is my code
class tree:
def __init__(self,val):
self.val=val
self.left=None
self.right=None
def preorder(root):
if root is None:
return
print(root.val)
tree.preorder(root.left)
tree.preorder(root.right)
def inorder(root):
if root is None:
return
tree.inorder(root.left)
print(root.val)
tree.inorder(root.right)
def postorder(root):
if root is None:
return
tree.postorder(root.left)
tree.postorder(root.right)
print(root.val)
def levelorder(root):
if root is None:
return
Q=[]
Q.append(root)
while Q!=[]:
l=len(Q)
for i in range(l):
print(Q[i].val)
temp=[]
for i in Q:
if i.left is not None:
temp.append(i.left)
if i.right is not None:
temp.append(i.right)
Q.clear()
Q=temp.copy()
def search(root,value):
o=[]
o.append(tree.levelorder(root))
if value in o:
return "Found"
else:
return "Not Found"
def insert(root,value,where):
if root is None:
return
Q=[]
Q.append(root)
value=tree(value)
while Q!=[]:
for i in Q:
if i.val==where:
if i.left is not None:
i.right=value
else:
i.left=value
return
temp=[]
for i in Q:
if i.left is not None:
temp.append(i.left)
if i.right is not None:
temp.append(i.right)
Q.clear()
Q=temp.copy()
def delete(root,value):
if root is None:
return
Q=[]
Q.append(root)
value=tree(value)
while Q!=[]:
for i in Q:
if i.left is not None and i.left.val==value:
i.left.val=None
i.left=None
if i.right is not None and i.right.val==value:
i.right.val=None
i.right=None
return
temp=[]
for i in Q:
if i.left is not None:
temp.append(i.left)
if i.right is not None:
temp.append(i.right)
Q.clear()
Q=temp.copy()
and here is how I created the tree
base=tree("drinks")
L=tree("hot")
R=tree("cold")
LL=tree("coffe")
LR=tree("tea")
LRL=tree("w milk")
LRR=tree("wo milk")
base.left=L
base.right=R
L.left=LL
L.right=LR
LR.left=LRL
LR.right=LRR
Now when I run the delete method, the object that is supposed to be deleted still shows up.
tree.delete(base,"w milk")
tree.levelorder(base)
drinks
hot
cold
coffe
tea
ice cream
w milk
wo milk <=== the node i am trying to delete
The main issues:
delete method's while loop will exit immediately, because of the return statement
The value to compare with should not be turned into a node with value=tree(value)
Some remarks on your code:
You'll not be able to ever delete the root node of the tree, since you only check the values of child nodes. In order to allow the root to be deleted, and to represent an empty tree, you should really consider creating a second class. The current class could then be renamed to Node and the new class could become Tree.
It is a common habit to use a capital first letter for class names, while for variable names you would always start with a lower case letter. So not Q, but q.
It is not such good practice to print inside methods of such classes: these methods should just provide tools to iterate over nodes, but they should not print them. Use yield instead.
For instance, search should return the node when it is found and None otherwise. Don't print the result.
The insert method may actually delete node(s) when both the left and right child of the where node are already occupied. It would be better to reject such an insert.
In the OOP pattern, it is widely accepted to call the first argument of instance methods self. In OOP, you would call these methods with the dot notation: so instead of tree.postorder(root.left) you would do root.left.postorder().
You have quite some code repetition: mainly for traversals, and where you use the queue algorithm twice. Try to avoid that.
Here is how you could modify your code to align to these suggestions:
class Node:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
def traverse(self, kind=0, parent=None):
if kind == 0: # pre-order
yield (self, parent) # don't print in methods
if self.left:
yield from self.left.traverse(kind, self)
if kind == 1: # in-order
yield (self, parent)
if self.right:
yield from self.right.traverse(kind, self)
if kind == 2: # post-order
yield (self, parent)
class Tree:
def __init__(self):
self.root = None # Representing an empty tree
def traversevalues(self, kind=0):
if self.root:
for node, parent in self.root.traverse(kind):
yield node.val
def preorder(self):
yield from self.traversevalues(0)
def inorder(self):
yield from self.traversevalues(1)
def postorder(self):
yield from self.traversevalues(2)
def levelorder(self):
if self.root:
q = [self.root]
while q:
temp = []
for node in q:
yield node.val
if node.left:
temp.append(node.left)
if node.right:
temp.append(node.right)
q = temp
def search(self, value):
if self.root:
return next((edge for edge in self.root.traverse() if edge[0].val == value), None)
def insert(self, value, where=None):
if not where:
if self.root:
raise ValueError("Must call insert with second argument")
else:
self.root = Node(value)
else:
edge = self.search(where)
if edge:
parent = edge[0]
if not parent.left:
parent.left = Node(value)
elif not parent.right:
parent.right = Node(value)
else:
raise ValueError(f"Node {where} already has 2 children")
else:
raise ValueError(f"Node {where} not found")
def deletesubtree(self, value):
edge = self.search(value)
if edge:
node, parent = edge
if parent.left == node:
parent.left = None
else:
parent.right = None
else:
raise ValueError(f"Node {value} not found")
tree = Tree()
tree.insert("drinks")
tree.insert("hot", "drinks")
tree.insert("cold", "drinks")
tree.insert("coffee", "hot")
tree.insert("tea", "hot")
tree.insert("with milk", "tea")
tree.insert("without milk", "tea")
print(*tree.levelorder())
tree.deletesubtree("without milk")
print(*tree.levelorder())

Binary search tree not inserting/printing actual largest value unless it is implemented as root

I'm learning binary search trees right now and made one myself. The problem with my tree is that the traverse() method doesn't print the largest value ('15' in the code pasted below), unless it is the first value to be inserted.
I've also tried getMaxValue() function and it also doesn't return the expected value, instead gives the second largest value.
This lead to me thinking that the problem must be in insert() function somewhere, but it's been an hour and i can't find a fix or what I did wrong.
class Node(object):
def __init__(self,data):
self.data = data
self.leftChild = None
self.rightChild = None
class BinarySearchTree(object):
def __init__(self):
self.root = None
#Parent function of insert
def insert(self,data):
if not self.root:
self.root = Node(data)
else:
self.insertNode(data,self.root)
# O(log n) if the tree is balanced!!!!
# thats why AVL and RBT are needed!
#Child function of insert
def insertNode(self,data,node):
if data < node.data:
# check if there is already a left child, if it is not null then we call insertNode recursively and insert a node as its child
if node.leftChild:
self.insertNode(data,node.leftChild)
# if there is no left child then we instantiate it, and make a left child, same stuff happening for right child
else:
node.leftChild = Node(data)
else:
if node.rightChild:
self.insertNode(data, node.rightChild)
else:
self.rightChild = Node(data)
#Parent function of getminvalue
def getMinValue(self):
if self.root:
return self.getMin(self.root)
#Child function of getminvalue
def getMin(self,node):
#if there is a left child
if node.leftChild:
#go to left child recursively
return self.getMin(node.leftChild)
return node.data
#Parent function of getMaxValue
def getMaxValue(self):
if self.root:
return self.getMax(self.root)
#Child function of getmaxValue
def getMax(self, node):
if node.rightChild:
return self.getMax(node.rightChild)
return node.data
#Parent function of traverse
def traverse(self):
if self.root:
self.traverseInOrder(self.root)
#Child function of traverseinOrder
def traverseInOrder(self,node):
if node.leftChild:
self.traverseInOrder(node.leftChild)
print("%s " % node.data)
if node.rightChild:
self.traverseInOrder(node.rightChild)
#Inputs
bst = BinarySearchTree()
bst.insert(10)
bst.insert(15)
bst.insert(5)
bst.insert(4)
bst.insert(3)
print(bst.traverse())
The expected result is
3
4
5
10
15
but I'm getting
3
4
5
10
None
fixed:
will soon edit with details
class Node(object):
def __init__(self,data):
self.data = data
self.leftChild = None
self.rightChild = None
class BinarySearchTree(object):
def __init__(self):
self.root = None
#Parent function of insert
def insert(self,data):
if not self.root:
self.root = Node(data)
else:
self.insertNode(data,self.root)
# O(log n) if the tree is balanced!!!!
# thats why AVL and RBT are needed!
#Child function of insert
def insertNode(self,data,node):
if data < node.data:
# check if there is already a left child, if it is not null then we call insertNode recursively and insert a node as its child
if node.leftChild:
self.insertNode(data,node.leftChild)
# if there is no left child then we instantiate it, and make a left child, same stuff happening for right child
else:
node.leftChild = Node(data)
else:
if node.rightChild:
self.insertNode(data, node.rightChild)
else:
node.rightChild = Node(data)
#Parent function of getminvalue
def getMinValue(self):
if self.root:
return self.getMin(self.root)
#Child function of getminvalue
def getMin(self,node):
#if there is a left child
if node.leftChild:
#go to left child recursively
return self.getMin(node.leftChild)
return node.data
#Parent function of getMaxValue
def getMaxValue(self):
if self.root:
return self.getMax(self.root)
#Child function of getmaxValue
def getMax(self, node):
if node.rightChild:
return self.getMax(node.rightChild)
return node.data
#Parent function of traverse
def traverse(self):
if self.root:
self.traverseInOrder(self.root)
#Child function of traverseinOrder
def traverseInOrder(self,node):
if node.leftChild:
self.traverseInOrder(node.leftChild)
print("%s " % node.data)
if node.rightChild:
self.traverseInOrder(node.rightChild)
#Inputs
bst = BinarySearchTree()
bst.insert(10)
bst.insert(15)
bst.insert(5)
bst.insert(4)
bst.insert(3)
bst.traverse()
I stepped through the code with a debugger (which I recommend you do, it is very helpful), and saw this:
as you can see, node with data 10 has no right child, whereas self has a root with data 10 and rightChild with data 15.
that made me look at the line that insert a new right child, there you had mistakenly wrote: self.rightChild = Node(data) instead of node.rightChild = Node(data) (like you correctly do with the left child)

Traverse tree and return a node instance after n traversals in python

The end goal is to copy a node from one tree to another tree. I want to visit each node in a binary tree and return a node instance after a number of traverses. I cannot seem to figure out how to return a specific node. Every time the node returned matches the id of the root node since I pass the root node to the function.
class node():
def __init__(self):
self.parent = None
self.left = None
self.right = None
def randnode(self, target):
global count
if target == count:
# print 'At target', '.'*25, target
return self
else:
if self.left is not None:
count += 1
self.left.randnode(target)
if self.right is not None:
count += 1
self.right.randnode(target)
If you're doing a DFS and counting iterations, you don't even need recursion, just a stack of places to try, and popping/pushing data.
def dfs(self,target):
count = 0
stack = [start]
while stack:
node = stack.pop()
if count == target:
return node
if node is None: # since we push left/right even if None
continue # stop pushing after we hit None node
stack.extend([self.left,self.right])
return -1 # ran out of nodes before count
Bonus points : swapping stack to a queue for BFS
Apart from that, you might want to pass the count as a parameter, like all self-respecting recursive calls, you can make this stateless ;-)
class node():
def __init__(self):
self.parent = None
self.left = None
self.right = None
def randnode(self, target,count=0):
if target == count:
# print 'At target', '.'*25, target
return self
if self.left is not None:
return self.left.randnode(target,count + 1)
if self.right is not None:
return self.right.randnode(target,count + 1)

Find number of elements smaller than a given element in BST

I have been struggling with this problem for a while and I am a Python beginner when it comes to BST, so I would appreciate some help. I am dynamically adding elements from an (unsorted) array into BST. That part is fine, I know how to do that. The next step, proved to be impossible with my current skill set. As I am adding elements to the tree, I need to be able to find current rank of any element in the tree. I know there are subtleties in this problem, so I would need help to at least find the number of nodes that are below the given node in BST. For example, in this case, node 15 has nodes 10,5 and 13 below it, so the function will return 3. Here is my existing code [this is a problem from Cracking the coding interview, chapter 11]
class Node:
"""docstring for Node"""
def __init__(self, data):
self.data = data
self.left=None
self.right=None
self.numLeftChildren=0
self.numRightChildren=0
class BSTree:
def __init__(self):
self.root = None
def addNode(self, data):
return Node(data)
def insert(self, root, data):
if root == None:
return self.addNode(data)
else:
if data <= root.data:
root.numLeftChildren+=1
root.left = self.insert(root.left, data)
else:
root.numRightChildren+=1
root.right = self.insert(root.right, data)
return root
def getRankOfNumber(self,root,x):
if root==None:
return 0
else:
if x>root.data :
return self.getRankOfNumber(root.right,x)+root.numLeftChildren+1
elif root.data==x:
return root.numLeftChildren
else:
return self.getRankOfNumber(root.left,x)
BTree=BSTree()
root=BTree.addNode(20)
BTree.insert(root,25)
BTree.insert(root,15)
BTree.insert(root,10)
BTree.insert(root,5)
BTree.insert(root,13)
BTree.insert(root,23)
You can go by this approach:
1. Have 2 more fields in each node numLeftChildren and numRightChildren.
2. Initialize both of them to 0 when you create a new node.
3. At the time of insertion, you make a comparison if the newly added node's
key is less than root's key than you increment, root's numLeftChildren and
call recursion on root's left child with the new node.
4. Do Same thing if new node's key is greater than root's key.
Now, come back to your original problem, You have to find out the number of children in left subtree. Just find out that node in O(logN) time and just print the numLeftChildren
Time Complexity: O(logN)
PS: I have added another field numRightChildren which you can remove if you are always interested in knowing the number of nodes in left subtree only.
You could modify your BST to contain the number of nodes beneath each node.
Or you could iterate over a traditional BST from least to greatest, counting as you go, and stop counting when you find a node of the required value.
You could simplify the code by using just instances of the Node class, as your BSTree instance operates on the root node anyway. Another optimization could be to not represent duplicate values as separate nodes, but instead use a counter of occurrences of the key:
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
self.num_left_children = 0
self.occurrences = 1
def insert(self, data):
if data < self.data:
if self.left is None:
self.left = Node(data)
else:
self.left.insert(data)
self.num_left_children += 1
elif data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.occurrences += 1
def get_rank(self, data):
if data < self.data:
return self.left.get_rank(data)
elif data > self.data:
return (self.occurrences + self.num_left_children +
self.right.get_rank(data))
else:
return self.num_left_children
Demo:
root = Node(20)
root.insert(25)
root.insert(15)
root.insert(10)
root.insert(10)
root.insert(5)
root.insert(13)
root.insert(23)
print(root.get_rank(15)) # 4
You can use the below function to find the number of the nodes in the tree (including the root).
def countNodes(self, root):
if root == None:
return 0
else
return (1 + countNodes(root.left) + countNodes(root.right));
To find the number of nodes that lie below root, subtract 1 from the value returned by the function. I think this will help get you started on the problem.
Your code will look like:
class Node:
"""docstring for Node"""
def init(self, data):
self.data = data
self.left=None
self.right=None
self.depth=0
class BSTree:
def init(self):
self.root = None
def addNode(self, data):
return Node(data)
def insert(self, root, data):
if root == None:
return self.addNode(data)
else:
if data <= root.data:
root.left = self.insert(root.left, data)
else:
root.right = self.insert(root.right, data)
return root
BTree=BSTree()
root=BTree.addNode(20)
BTree.insert(root,25)
BTree.insert(root,15)
BTree.insert(root,10)
BTree.insert(root,5)
BTree.insert(root,13)
BTree.insert(root,23)
BTree.insert(root,23)
numLeft = countNodes(root->left);
numRight = countNodes(root->right);
numChildren = numLeft + numRight;

cannot see syntax error

I'm trying to build a binary search tree library and I'm getting a syntax error on my piece of code:
class Node:
"""
Tree node: Left and Right child + data which can be any object
"""
def __init__(self,data):
"""
Node constructor
"""
self.left = None
self.right = None
self.data = data
def insert(self,data): # self --> object self.data
"""
Insert new node with data
"""
if data < self.data: # insert data less than current root
if self.left is None: # if left node is empty,
self.left = Node(data) # object left --> Node with new data
else:
self.left.insert(data) # if left node is not empty, go insert again
else:
if self.right is None: # insert data greater than current node
self.right = Node(data) # object right --> Node with new data
else:
self.right.insert(data) # if not empty, run insert again
def lookup(self, data, parent = None):
"""
Lookup node containing data
"""
if data < self.data:
if self.left is None:
return None, None
return self.left.lookup(data,self)
elif data > self.data:
if self.right is None:
return None, None
return self.right.lookup(data,self)
else:
return self, parent
def delete(self, data):
"""
delete node containing data
"""
""" no child """
if children_count == 0:
# if node has no children, remove it
if parent.left is node: # if parent is pointing to current node
parent.left = None # set parent pointing left to None
else:
parent.right = None # else set parent pointing right to None
del node # del node
""" 1 child """
elif children_count == 1:
# if node has 1 child
# replace node by it's child
if node.left:
n = node.left
else:
n = node.right
if parent:
if parent.left is node:
parent.left = n
else:
parent.right = n
del node
""" 2 children """
else:
# if node has 2 children
# find its successor
parent = node # parent is equal to current node target of deletion
successor = node.right # successor is right of the node
while successor.left:
parent = successor
successor = successor.left
# replace node data by its successor data
node.data = successor.data
#fix successor's parent's child
if parent.left == successor:
parent.left = successor.right
else:
parent.right = successor.right
def children_count(self):
""" Return the number of children """
if node is None:
return None
cnt = 0
if self.left:
cnt += 1
if self.right:
cnt += 1
return cnt
# method to print tree in order. Use recursion inside print_tree() to walk the tree breath-first
def print_tree(self):
if self.left:
self.left.print_tree()
print self.data,
if self.right:
self.right.print_tree()
the error is:
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
import BSTlib
File "BSTlib.py", line 78
elif children_count == 1:
^
I can't seem to see what is wrong =[ Can someone help me point this out? Thank you!
This is an error with the docstring and whitespace. Run this code:
if False:
print 'hi'
"""1 child"""
elif True:
print 'sdf'
And you get a similar SyntaxError.
Remove the docstring (or just move it) and remove the extra whitespace:
if False:
print 'hi'
elif True:
print 'sdf'
If you need to comment, then just use the hash #:
if False:
print 'hi'
# 1 child
elif True:
print 'sdf'

Categories

Resources