Delete a root from a tree in python - python

I am implementing a deletion of a node from a binary search tree in python.
I got stuck in an edge case.
Consider next code:
class Node():
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
root = Node(5)
root.right = Node(10)
How to implement a function that deletes the root.
I do not want the function return new root.
In C++ I can modify pointer to make root point to its child, however in python variables are labels essentially. Is it even possible to do in python?

There is indeed no way to replace root and have it replaced wherever the instance pointed to by the name root appears.
The only way to achieve what you want is to mutate root to duplicate the child node.
def delete(node, inheritLeft=True):
child = node.left if inheritLeft else node.right
node.value = child.value
node.left = child.left
node.right = child.right
(Obviously you might want to do something smarter regarding choosing which node to inherit).

Related

How to fix NoneType error in Python Binary Search Tree?

I'm creating a basic binary search tree program where the nodes have to be strings however, I keep getting this error:
'builtins.AttributeError: 'NoneType' object has no attribute 'addNode'
I'm a bit confused because I thought you had to declare the children nodes as None. My code is below (please excuse the messiness and extra print statements):
class BinarySearchTree:
#constructor with insertion value & left/right nodes as None
def __init__(self, data):
self.data = data
self.left = None
self.right = None
#function to insert node
def addNode(root, data):
#when tree doesn't exist
if root == None:
return BinarySearchTree(data)
else:
#when node is already in tree
if root.data == data:
return root
#smaller values go left
elif data < root.data:
root.left.addNode(data)
#bigger values go right
else:
root.right.addNode(data)
return root
#function to find smallest node value (to help with deletion)
def smallestNode(root):
node = root
#loop goes to lowest left leaf
while(node.left is not None):
node = node.left
return node
#function to delete node
def removeNode(root, data):
if root == None:
return root
#when node to be deleted in smaller than root, go left
if data < root.data:
root.left = root.left.removeNode(data)
#when node to be deleted in bigger than root, go right
elif data > root.data:
root.right = root.right.removeNode(data)
##when node to be deleted in the same as root...
else:
#when node has only 1 or 0 children
if root.right == None:
move = root.left
root = None
return move
elif root.left == None:
move = root.right
root = None
return move
#when node has 2 children, copy then delete smallest node
move = root.right.smallestNode()
root.data = move.data
root.right = root.right.removeNode(move.data)
return root
def findNode(root, data):
#if current node is equal to data value then return the root
if root.data == data or root == None:
return root
#if current node is greater than the data value then, search to the left
elif data < root.data:
return root.left.findNode(data)
#if current node is less than the data value then, search to the right
else:
return root.right.findNode(data)
def createBST(keys):
root = BinarySearchTree(keys[0])
for i in range(1,len(keys)):
root.addNode(keys[i])
return root
print('Hi! Welcome to the Binary Search Tree Builder')
print('Here are your options below:')
print('1) Build new tree')
print('2) Add a node')
print('3) Find a node')
print('4) Delete a node')
choice = int(input('What would you like to do?: '))
if choice == 1:
nodes = list(input("Enter the strings you would like to build your tree from (separate by a space): ").split())
print(nodes)
tree = createBST(nodes)
print(tree)
I'm wondering where exactly is this error coming from and how can I fix it? Also, if you see any other problems occuring in my code, please let me know!
You have conflated the notion of "tree node" and "tree". What you have there is a mixture of the two. Remember, the first parameter to ALL member functions should be "self". Replacing "root" by "self" might make your problem more clear.
So, you might create a BinaryTree class, which has a single member called self.root that holds a BinaryTreeNode object, once you have a node. The nodes will hold the left and right values, each of which will either have None or a BinaryTreeNode object. The node class probably doesn't need much code -- just self.left and self.right.
The BinaryTree class will have an addNode member that knows how to traverse the tree to find the right spot, but when you find the spot, you just set self.left = BinaryTreeNode(...). A node does not know about the tree, so a node does not know how to add new nodes. That's a function of the tree itself.
Does that make your path forward more clear?

Classes Binary Search Tree Python

I am new to Python and came across an old problem in HackerRank which defines a Binary Tree as such. I reviewed this video on classes and instances (and the next one) to try to understand what is happening in the below code but I still don't fully grasp what is going on.
I understand the role of the __ init __(self, ...) but I'm not sure what attribute info has. I also do not understand why self.left = None, self.right = None, self.level = None.
In the second class BinarySearchTree, there's an init with no attribute and I also do not understand the self.root = None.
Even though I don't understand most of the code below, I think if someone can explain why the person set self.____= None, it would help me understand how to define a Binary Search Tree.
class Node:
def __init__(self, info):
self.info = info
self.left = None
self.right = None
self.level = None
def __str__(self):
return str(self.info)
class BinarySearchTree:
def __init__(self):
self.root = None
def create(self, val):
if self.root == None:
self.root = Node(val)
else:
current = self.root
while True:
if val < current.info:
if current.left:
current = current.left
else:
current.left = Node(val)
break
elif val > current.info:
if current.right:
current = current.right
else:
current.right = Node(val)
break
else:
break
If you try sketch your tree structure as a bunch of circles with some values inside, you will get something like that:
The 'info' attribute will contain the values that are inside of the circles. Every node of a binary tree can have at most two children, that's what the 'left' and 'right' attributes are used for. If the 'left' attribute is 'None', it basically means there is no child node on the left side yet (like in case of the node 16 on the image). If you create a new node, you usually do not expect it to have any children, that's why the 'left' and 'right' attributes are 'None' by default.
The class 'BinarySearchTree' represents a tree as a whole and keeps the current root node (the top one on the image) in the corresponding 'root' attribute. At the beginning the tree is empty, so the 'root' attribute equals to 'None'.
Hope it helps!

Python: actually modify a node in binary search tree instead of just attaching a label name

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)

Binary Tree: How Do Class Instances Link?

I am trying to understand binary trees, but doing so has brought me to confusion about how class instances interact, how does each instance link to another?
My Implementation:
class Node(object):
def __init__(self, key):
self.key= key
self.L = None
self.R = None
class BinaryTree(object):
def __init__(self):
self.root = None
def get_root(self):
return self.root
def insert(self, key):
if self.get_root()==None:
self.root = Node(key)
else:
self._insert(key, self.root)
def _insert(self, key, node):
if key < node.key:
if node.L == None:
node.L = key
else:
self._insert(key, Node(node.L))
if key > node.key:
if node.R == None:
node.R = key
else:
self._insert(key, Node(node.R))
myTree= BinaryTree()
A Scenario
So lets say I want to insert 10, I do myTree.insert(10) and this will instantiate a new instance of Node(), this is clear to me.
Now I want to add 11, I would expect this to become the right node of the root node; i.e it will be stored in the attribute R of the root node Node().
Now here comes the part I don't understand. When I add 12, it should become the child of the root nodes right child. In my code this creates a new instance of Node() where 11 should the be key and 12 should be R.
So my question is 2-fold: what happens to the last instance of Node()? Is it deleted if not how do I access it?
Or is the structure of a binary tree to abstract to think of each Node() connected together like in a graph
NB: this implementation is heavily derived from djra's implementation from this question How to Implement a Binary Tree?
Make L and R Nodes instead of ints. You can do this by changing the parts of your _insert function from this:
if node.L == None:
node.L = key
to this:
if node.L == None:
node.L = Node(key)
There is also a problem with this line:
self._insert(key, Node(node.L))
The way you're doing it right now, there is no way to access that last reference of Node() because your _insert function inserted it under an anonymously constructed node that has no parent node, and therefore is not a part of your tree. That node being passed in to your insert function is not the L or R of any other node in the tree, so you're not actually adding anything to the tree with this.
Now that we changed the Ls and Rs to be Nodes, you have a way to pass in a node that's part of the tree into the insert function:
self._insert(key, node.L)
Now you're passing the node's left child into the recursive insert, which by the looks of thing is what you were originally trying to do.
Once you make these changes in your code for both the L and R insert cases you can get to the last instance of Node() in your
10
\
11
\
12
example tree via myTree.root.R.R. You can get its key via myTree.root.R.R.key, which equals 12.
Most of you're questions come from not finishing the program; In your current code after myTree.insert(11) you're tree is setting R equal to a int rather than another Node.
If the value isn't found then create the new node at that point. Otherwise pass the next node into the recursive function to keep moving further down the tree.
def _insert(self, key, node):
if key < node.key:
if node.L == None:
node.L = Node(key)
else:
self._insert(key, node.L)
if key > node.key:
if node.R == None:
node.R = Node(key)
else:
self._insert(key, node.R)
P.S. This isn't finished you're going to need another level of logic testing incase something is bigger than the current Node.key but smaller than the next Node.

Binary Search Tree - storing reference to parent node

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?

Categories

Resources