How to build a binary tree in Python - python

I am trying to build a binary tree, but stuck at adding two nodes to root.
What function should I write to enable adding node to these two nodes?
I have the following code:
class Btree:
def __init__(self, root):
self.key = root
self.lc = None
self.rc = None
def insert_lc(self, newNode):
if self.lc == None:
self.lc = Btree(newNode)
else:
t = Btree(newNode)
t.lc = self.lc
self.lc = t
def insert_rc(self, newNode):
if self.rc == None:
self.rc = Btree(newNode)
else:
t = Btree(newNode)
t.rc = self.rc
self.rc = t
def get_rc(self):
return self.rc
def get_lc(self):
return self.lc
def set_Root(self, val):
self.key = val
def get_Root(self):
return self.key
r = Btree(1)
r.insert_lc(2)
r.insert_rc(4)
I think I need a function so I can add left child and right child to nodes which have value 2 and 4

First of all, I do not quite understand why do you assign your new node's left (right) child to that new node itself. This will get you an infinite loop if you try to search the tree later.
t = Btree(newNode)
#The line below seems unnecessary
t.lc = self.lc
self.lc = t
Second of all, in the Btree constructor you have a parameter called root which seems like it's intended to be a reference to the root of the current node. However, you pass the node's key as that parameter, so there is no way to access node's root. I understand that is might be not even necessary in your case, still that parameter name is quite confusing. If you want to have a reference to the parent node you should add another parameter to your constructor:
def __init__(self, root, key):
self.root = root
self.key = key
self.lc = None
self.rc = None
This way you have both key and a parent node reference. You also will need to modify insert_rc and insert_lc methods:
def insert_rc(self, newNode):
if self.rc == None:
#Parent node is the one the insert_rc method is called on,
#so we pass self as the root parameter
self.rc = Btree(self, newNode)
else:
t = Btree(self, newNode)
self.rc = t
#Same with insert_lc
Finally,to answer your initial question: to add children to the added nodes you simply call get_rc or get_lc both of which will return you instances of Btree so you can add child nodes to them:
r = Btree(1)
r.insert_lc(2)
r.insert_rc(4)
#Insert left child to the node with key=2
r.get_lc().insert_lc(3)
#Insert right child to the node with key=4
r.get_rc().insert_rc(5)

Related

adding childern to tree stucture and print

I am trying to implement an n-arry tree based on this post :
[here][1]
and I am getting an error when trying to define a function that adds children:
class node(object):
def __init__(self, value, children = []):
self.value = value
self.children = children
def __str__(self, level=0):
ret = "\t"*level+repr(self.value)+"\n"
for child in self.children:
ret += child.__str__(level+1)
return ret
# trying to implement this method si that I can get rid of
# calling root.children[0].children
def add_child(self, obj):
self.children.append(obj)
def __repr__(self):
return '<tree node representation>'
root = node('grandmother')
root.children = [node('daughter'), node('son')]
root.children[0].children = [node('granddaughter'), node('grandson')]
root.children[1].children = [node('granddaughter'), node('grandson')]
root.add_child([node((1)), node(2)]) # error
print (root)
I want to be able to to create a tree and print it.
[1]: Printing a Tree data structure in Python
If you name a method add_child, it should add a child, not children. And if you add children, you should extend the list, not just append the given list on its end.
Working example:
class Node(object):
def __init__(self, value, children=None):
if children is None:
children = []
self.value = value
self.children = children
def __str__(self, level=0):
ret = "\t" * level + repr(self.value) + "\n"
for child in self.children:
ret += child.__str__(level + 1)
return ret
def add_children(self, obj):
self.children.extend(obj)
root = Node('grandmother')
root.children = [Node('daughter'), Node('son')]
root.children[0].children = [Node('granddaughter'), Node('grandson')]
root.children[1].children = [Node('granddaughter'), Node('grandson')]
root.add_children([Node(1), Node(2)])
print(root)
Output:
'grandmother'
'daughter'
'granddaughter'
'grandson'
'son'
'granddaughter'
'grandson'
1
2
You call add_child with an entire list object. Within add_child you use the method list.append which adds the entire list object to the list itself.
Solution 1: call add_child by specifying the nodes directly:
root.add_child(node((1))
root.add_child(node((2))
Solution 2: change the implementation of add_child by using list.extend instead of list.append. The former adds each element within the supplied argument to the list, while the latter adds the entire argument to the list.
def add_child(self, obj):
self.children.extend(obj)

Python - Removing a node from a linked-list at beginning, in between and at end

I learned about linked-lists today. I learned how to insert and remove nodes from them. In the following code, it teaches me how to insert nodes with three distinct functions: at beginning (the head node), in between and at the end. However, they teach me how to remove the node in and single function. I don't find the code in the remove function to be very clear. Can anyone help make an easier to understand code under the remove function? Is there a way to make it into three functions just like the inserting ones? I'm open to any suggestion or explanation. Thanks in advance.
Here's my code:
class Node:
def __init__(self, data=None):
self.data = data
self.nextnode = None
class LinkedList:
def __init__(self):
self.headnode = None
def printlist(self):
node = self.headnode
while node is not None:
print (node.data)
node = node.nextnode
def atbegining(self,new_node):
new_node.nextnode = self.headnode
self.headnode = new_node
# Function to add newnode
def AtEnd(self, newnode):
if self.headnode is None:
self.headnode = newnode
return
node = self.headnode
while(node.nextnode):
node = node.nextnode
node.nextnode=newnode
# Function to add node
def Inbetween(self,preNode,newNode):
if preNode is None:
print("The mentioned node is absent")
return
newNode.nextnode = preNode.nextnode
preNode.nextnode = newNode
# Function to remove node
def RemoveNode(self, RemoveVal):
node = self.headnode
if (node is not None):
if (node.data == RemoveVal):
self.headnode = node.nextnode
node = None
return
while (node is not None):
if node.data == RemoveVal:
break
prevnode = node
node = node.nextnode
if (node == None):
return
prevnode.nextnode = node.nextnode
node = None
list1 = LinkedList()
list1.headnode = Node("Mon")
n2 = Node("Tue")
n3 = Node("Wed")
# Link first Node to second node
list1.headnode.nextnode = n2
# Link second Node to third node
n2.nextnode = n3
n4 = Node("Sun")
n5 = Node("Tur")
n6 = Node("Newdate")
list1.atbegining(n4)
list1.AtEnd(n5)
list1.Inbetween(list1.headnode,n6)
list1.RemoveNode("Newdate")
list1.printlist()
RemoveNode is complicated by the fact that there are two structurally distinct kinds of LinkedLists: one whose head is None, and one whose head is not None. You can fix this by making sure every LinkedList contains at least one node. This is typically referred to as a dummy node, and you can use this node to store metadata (such as the length of the list).
The Node class itself does not change.
class Node:
def __init__(self, data=None):
self.data = data
self.nextnode = None
The LinkedList, however, simplifies by creating a dummy node. This provides
the guarantee that every node that stores real data is point to by another node.
class LinkedList:
def __init__(self):
self.headnode = Node(0)
def insert(self, preNode, newNode):
newNode.nextnode = preNode.nextnode
preNode.nextnode = newNode
self.headnode.data += 1
def append(self, newNode):
curr = self.headnode
while curr.nextNode is not None:
curr = curr.nextNode
self.insert(curr, newNode)
def prepend(self, newNode):
self.insert(self.headnode, newNode)
def _find_before(self, val):
pre = self.headnode
while pre.nextnode is not None:
curr = pre.nextnode
if curr.data == val:
return pre
pre = curr
def remove(self, RemoveVal):
pre = self._find_before(RemoveVal)
if pre is None:
return
pre.nextnode = pre.nextnode.nextnode
self.headnode.data -= 1
This simplifies all three insertions. The general case can always apply, since there is always a node that comes before the node you insert. append and prepend are simple wrappers that find the appropriate node to pass to insert.
Likewise, remove simply finds the node before the given value, and if the search succeeds, handles updating the prior node's nextnode attribute.
insert and remove also update the size of the list stored in the dummy node.
A find method becomes a simple wrapper around _find_before; if you find a node before the value you are looking for, just return the node that follows it.
I think that an alternative design will make the code much clearer. Consider for example the following:
class Node:
def __init__(self, data=None):
self.data = data
self.nextnode = None
def printlist(self):
print(self.data)
if self.nextnode is not None:
self.nextnode.printlist()
def push(self, node):
node.nextnode = self
return node
def insertafter(self, node):
node.nextnode = self.nextnode
self.nextnode = node
return self
def append(self, node):
lastnode = self
while lastnode.nextnode is not None:
lastnode = lastnode.nextnode
lastnode.nextnode = node
return self
def remove(self, value):
prev = None
walk = self
while walk is not None:
if walk.data == value:
if prev is None:
return walk.nextnode
else:
prev.nextnode = walk.nextnode
return self
else:
prev = walk
walk = walk.nextnode
return self
list1 = Node("Mon")
n2 = Node("Tue")
n3 = Node("Wed")
# Link first Node to second node
list1 = list1.insertafter(n2)
# Link second Node to third node
n2 = n2.insertafter(n3)
n4 = Node("Sun")
n5 = Node("Tur")
n6 = Node("Newdate")
list1 = list1.push(n4)
list1 = list1.append(n5)
list1 = list1.insertafter(n6)
list1 = list1.remove("Newdate")
list1.printlist()
The main idea is that a Node is the linked list. As long as you have the head of the list kept in a variable, you can have access to the entire list, without the need for a separate data structure.

Binary Tree Not Showing Nodes Present Python

I'm trying to implement a binary tree with insert and preorder methods.
After adding elements to the tree, only one element is displayed.
Can someone let me know where I'm wrong.
Below is code:
class Node(object):
def __init__(self, value, left=None, right=None):
self.value = value
self.left = None
self.right = None
def __repr__(self):
return '{}'.format(self.value)
class BinaryTree(object):
def __init__(self, root=None):
self.root = root
def add(self, value):
val = self.root
if not val:
self.root = value
val = value
elif not val.left:
val = value
elif not val.right:
val = value
else:
self.left = val.left.add(value)
return val
def preorder(self):
val = self.root
if not val: # this will handle the case when root node is None.
return
print(val)
if val.left:
val.left.preorder()
if val.right:
val.right.preorder()
def main():
binary_tree = BinaryTree()
print("Adding nodes to the tree")
for i in range(1, 11):
node = Node(i)
binary_tree.add(node)
print("Printing preorder...")
binary_tree.preorder()
if __name__ == '__main__':
main()
Output
Adding nodes to the tree
Printing preorder...
1
Your code has a few different errors. Some relate to how you modify self.root (or fail to), others have to do with attempts at recursion on the wrong types.
The first issue, which is why your code fails silently, has to do with your BinaryTree.add method, which does nothing when the tree is empty. The problem is that you initialize a local variable val to be equal to your root node (if you have one), and then later rebind it to some other value. But that never changes the root value at all, only the local val variable.
I suggest you get rid of val all together, and instead read and write self.root directly. Then you'll actually make some progress, and see the other issues.
Here's a start:
def add(self, value):
if self.root is None:
self.root = value
elif self.root.left.left is None:
self.root.left = value
...
The other issues I mention are both similar, though one occurs in BinaryTree.add and the other in BinaryTree.preorder. The issue is that you try to call the same method (add or preorder) on one of the children of your root node. But the nodes are Node instances, and don't have the methods that you've defined in the BinaryTree class.
This issue doesn't have as obvious a solution as the previous one. One idea might be to move the logic for the methods into the Node class (where you can recurse easily), and leave only the empty-tree handling code in the BinaryTree methods (everything else gets delegated to the root node).

Find all parent nodes of a node in a tree

I am creating a tree in python, and I had a method to find a path from the parent to the root node of the tree. That is as follows:
def get_sub_net(self, index):
node = self.nodes[index]
sub_net = []
sub_net.append(node)
while node.parent is not None:
node = node.parent
sub_net.append(node)
return sub_net[::-1]
Now I am trying to allow for each node to have multiple parents, and I am running into trouble.
def sub_net(self, index):
node = self.nodes[index]
sub_net = []
if node.parents == None:
return sub_net
else:
sub_net += node.parents
for i in node.parents:
while i is not None:
sub_net += i.parents
node = i
break
return sub_net[::-1]
#Noreddine-Kessa pointed out that this would be a graph, and not a tree, which is correct. However, I also solved my own problem, the solution I used i
def recursive_sub_net(self, node):
sub_net = []
sub_net.append(node)
if node.parents is not None:
for i in node.parents:
sub_net += self.recursive_sub_net(i)
return sub_net
By definition, every node in a tree has a single parent (and can have many ancestors), if you need to use a network of nodes (not tree) then you should use a graph.

Inserting a value into a Binary Search Tree in Python

I am reviewing for my final and one of the practice problem asks to implement a function that puts a value into a binary search tree in Python. Here is the Tree implementation I am using.
class Tree(object):
def __init__(self, entry, left=None, right=None):
self.entry = entry
self.left = left
self.right = right
Here is the function I need to fill in.
def insert(item, tree):
"""
>>> t = Tree(5, Tree(1, None, Tree(4)), Tree(7, Tree(6), Tree(8)))
>>> insert(2, t)
>>> t
Tree(5, Tree(1, None, Tree(4, Tree(2), None)), Tree(7, Tree(6), Tree(8)))
"""
Can anyone help me implement this code, as I have no idea where to start? Thanks!
def insert(item, tree):
if (item < tree.entry):
if (tree.left != None):
insert(item, tree.left)
else:
tree.left = Tree(item)
else:
if (tree.right != None):
insert(item, tree.right)
else:
tree.right = Tree(item)
Tree is a Non linear data structure.A tree is created by set of vertices and set of edges.Average searching complexity is logn . Let's consider how to insert values to tree.
First of all , you would create a Vertices.In another way, you would create nodes.then , Those nodes which is created insert hierarchical manner.In creating Node class , You can initialize all the properties of Node class in constructor function.Actually like this,
class Node:
def __init__(self,data):
self.data=data
self.left=None
self.right=None
At beginning, Node's data=data, left child of Node is None and right child of Node is None.And then , you can create a binary search tree using those created nodes.
class tree:
def __init__(self):
self.root=None
def insert(self,data):
if(self.root==None):
self.root=Node(data)
else:
self._insert(data,self.root)
def _insert(self, data, curNode):
if(curNode.data>data):
if(curNode.left==None):
curNode.left=Node(data)
else:
self._insert(data,curNode.left)
else:
if(curNode.right==None):
curNode.right=Node(data)
else:
self._insert(data,curNode.right)
At first, root node is initialized under constructor method of tree class.And then insert nodes using insert function.Using any tree traversal method can be printed elements of tree..I think , you could understand.thank you!

Categories