Adding Children Nodes to a Tree in Python - python

I am trying to create a tree in python, which I want to be able to do a breadth first traversal later on. However, when I try to loop through the children of a node (i.e the root), it doesn't seem to find any children. However, if I try to access the child separately (root.children[1]) it is valid. I am pretty sure I am doing something silly, but I am not sure where. Here is my code:
class Component:
def __init__(self, compName, originName, connected = False): #removed to decrease code size
def __str__(self):
return "\n\tComponent Name: {0}\n\tOrigin Name: {1}\n\tConnected: {2}\n".format(self.name, self.origin, str(self.connected));
class Node:
def __init__(self, component, parent):
self.children = [];
def add_node(self, node):
self.children.append(node);
#...left out some broken code that is commented out...#
def __str__(self):
return "{0}".format(str(self.component));
class Tree:
def __init__(self):
def add_component(self, component, parent = None):
if self.root is None:
self.root = Node(component, parent);
else:
self.root.add_node(Node(component, parent));
def breadth_first(node):
result = [];
queue = [];
queue.append(node);
while queue:
node = queue.pop(0);
result.append(node);
plog("Adding to result\n");
plog(str(node));
if node in node.children:
for child in node.children:
if child not in result and child not in queue:
queue.append(child);
else:
plog("NO CHILDREN\n"); // this is being displayed
return result;
def main(ScriptArgument, oDesktop):
component = Component("Laminate", "B7_TX");
tree = Tree();
tree.add_component(component);
component = Component("B7", "B7_TX");
tree.add_component(component, "Laminate");
result = breadth_first(tree.root);
for x in result:
plog(str(x) + "\n");
This is the output I am getting:
Adding to result # output from breadth-first
Component Name: Laminate #output from breadth-first
Origin Name: B7_TX
Connected: False
NO CHILDREN # this is indicating that the child was not added properly, I believe
Component Name: Laminate # output from the loop in main
Origin Name: B7_TX
Connected: False

Why are you checking if the parent is in the list of children with the following line?
if node in node.children:
I would simply do:
[...]
while queue:
node = queue.pop(0);
result.append(node);
plog("Adding to result\n");
plog(str(node));
for child in node.children:
if child not in result and child not in queue:
queue.append(child);
return result;

My "if" check was wrong. I was checking to see if the root (or current) node is in its own children list, which was wrong. I simply changed this to check if there are any children (if node.children:) and it worked.

Related

Binary Tree Conditional Insert

I am trying to write a logic to insert a node into a binary tree.
The node looks like this
class BinTree:
def __init__(self, Id):
self.Id = Id
self.NodeCounter = 1
self.left = None
self.right = None
I need to insert a new node only if it doesnt exist in the tree but increment the counter if it exists already.
As of now, what im doing is whenever i get a new element to insert, i first search it in the binary tree, if the node is found i increment the NodeCounter by 1, otherwise I again start traversing from root node and then go and insert the new node
The problem here is that for every new node, i am traversing the tree twice which i dont want… And when i am trying to search and insert at the same time,the counters get messed because of recursion.
Is there a way I can achieve this?
Any tips would be appreciated
i first search it in the binary tree
...this would only be an efficient process if your binary tree is a binary search tree (BST). I'll assume that is what we are talking about.
if the node is found i increment the NodeCounter by 1, otherwise I again start traversing from root node and then go and insert the new node
Why would you start from the root again? When you did the search and didn't find the node, there was a last node that you visited. Just attach the new node to it.
Here is a possible implementation:
class Node:
def __init__(self, id):
self.id = id
self.nodeCounter = 1
self.left = None
self.right = None
class BinTree:
def __init__(self):
self.root = None
def add(self, id):
self.root = self.addrecur(self.root, id)
def addrecur(self, node, id):
if not node:
node = Node(id)
elif id == node.id:
node.nodeCounter += 1
elif id < node.id:
node.left = self.addrecur(node.left, id)
else:
node.right = self.addrecur(node.right, id)
return node
def __repr__(self):
return self.indented(self.root)
def indented(self, node, indent=""):
if not node:
return ""
return (self.indented(node.right, indent + " ")
+ f"{indent}{node.id} ({node.nodeCounter})\n"
+ self.indented(node.left, indent + " "))
tree = BinTree()
tree.add(4)
tree.add(2)
tree.add(3)
tree.add(2)
tree.add(6)
tree.add(5)
tree.add(5)
print(tree)
This outputs the tree in side-ways view (root at left) with the node count in parentheses:
6 (1)
5 (2)
4 (1)
3 (1)
2 (2)

Python: breadth first search

Node contains:
State(an integer unique ID of the node of the graph), Parent (a node in the search tree that generated this node), Path cost(a cost associated with current node)
"""A node in a search tree. Contains a pointer to the parent (the node
that this is a successor of) and to the state for this node
representing actual graph node (graph node ID)."""
#given function
def __init__(self, state, parent=None, path_cost=0):
"""Create a search tree Node"""
self.state = state
self.parent = parent
self.path_cost = path_cost
self.depth = 0
if parent:
self.depth = parent.depth + 1
#given function
def child_node(self, graph, state):
"""Create a new search node and mark it as a child.
The child node will have current node as a parent."""
next_node = Node(state,
parent=self,
path_cost=self.path_cost + 1)
return next_node
# expand function was given to us
def expand(self, graph):
"""List the nodes reachable in one step from this node i.e
neighbours of the current node."""
return [self.child_node(graph, state)
for state in graph.neighbors(self.state)]
Here we have implement the bfs function as our assignment.
def bfs(graph, start, dest):
to_check = []
visited = set()
to_check.insert(0, start)
#while to_check has nodes
while to_check:
next_node = queue.pop()
visited.add(next_node)
for sibling in next_node.expand(graph):
if sibling not in visited and sibling not in to_check:
if sibling == dest:
return sibling
else:
to_check.insert(0, next_node)
The code I ran using the above functions:
start_graph_state = 3470524959
destination_graph_state = 5674155097
start = Node(state=start_graph_state)
dest = Node(state=destination_graph_state)
solution_node = bfs(graph, start, dest)
I'm supposed to plot an appropriate graph, but I've commented out and instead I was running function to check whether the nodes were being iterated correctly. But I keep getting stuck on the starting node because it is never placed in set nor is it removed from the to_check queue even after I have popped it out. (Even when the destination node is directly one edge away, I get an infinite loop) I'm very new to Python and I feel that I'm just stuck on simple syntax problems, but I'm confused. Any help would be appreciated!
You should make sure that you use a FIFO queue (such as the one available in collections).
The general structure of the traversal would be as follows:
from collections import deque
q = deque()
q.append(firstNode)
visited = set()
while q:
node = q.popleft()
if node in visited: continue
visited.add(node)
for nextNode in node.neighbours:
q.append(nextNode)
# perform required processing on node

Adding Child To Parent also adds child to the current node

So I just started learning Python so forgive me if I'm missing something here. I have a simple node class that has data and children as a list. In another class where Im recursively going through a grid, I attempt to add the entire grid to a node to create a sort of state space for the problem. My issue is that when I'm adding a child to its parent, it also adds itself as a child to itself for some reason.
This is my node class
class StateSpaceNode:
def __init__(self, data=None, children=[]):
self.data = data
self.children = children
def add_data(self, data):
self.data = data
def add_child(self, child):
self.children.append(child)
and this is the portion where im adding the child
def traverse_dfs(self, grid, x, y, seen, root):
self.traverse_dfs_helper(grid, x, y, seen, root)
def traverse_dfs_helper(self, grid, x, y, seen, old_root):
key = "%s, %s" % (x, y)
seen[key] = True
if old_root.data is not None:
node = StateSpaceNode()
print("ADDING CHILD")
print("NEW NODE:", node)
print("NEW NODE CHILDREN: ", node.children)
node.add_data(copy.deepcopy(grid))
old_root.add_child(node)
print("PARENT CHILDREN:", old_root.children)
print("CHILDREN TO NEW NODE:", node.children)
else:
print("MAKING ROOT")
old_root.add_data(copy.deepcopy(grid))
print("OLD ROOT DATA ADDED", old_root.data)
node = old_root
print("CHILDREN TO OLD ROOT", node.children)
Take note of the print statements. This is the output for that portion of the code.
MAKING ROOT
OLD ROOT DATA ADDED [[0, 0], [0, 2]]
CHILDREN TO OLD ROOT []
ADDING CHILD
NEW NODE: <state_space.StateSpaceNode object at 0x104d2dcc0>
NEW NODE CHILDREN: []
PARENT CHILDREN: [<state_space.StateSpaceNode object at 0x104d2dcc0>]
CHILDREN TO NEW NODE: [<state_space.StateSpaceNode object at 0x104d2dcc0>]
and if I print the tree out, it just keeps going on and on with the same child. However, the "ADDING CHILD" portion only happens three times in total so Im not sure whats going on. Any help is appreciated!

Counting nodes in General tree in python

I have created a Tree structure that is not a binary tree and having difficulties in getting the correct node count.
class TreeNode(object):
def __init__(self, name='root', children=None,Parent=[]):
self.Name = name
self.Parents=Parent
self.Children = []
if children is not None:
for child in children:
self.add_child(child.Name)
def __repr__(self):
return self.Name
def add_child(self, node):
self.Children.append(node)
and this is the latest in what I have tried to do in order to count the number of nodes in the tree.
def countNodes(Tree):
for Child in Tree.Children:
return countNodes(Child)+1
return 1
Could someone explain why this doesn't work?
EDIT: I should clarify, When I say doesn't work it gives me a completely wrong count for he number of nodes in my graph.
You countNodes function is not well. A parent node can have two childs, if you put a return statement within the for loop, it will return on the first child count and the second child count will be missing. You need to do something like this:
def countNodes(Tree):
count = 1
for Child in Tree.Children:
count += countNodes(Child)
return count
Just to add #levi has missed an edge case where root is None
so the modified code will be :
def numNodes(root):
if root == None:
return 0
node = 1
for child in root.children:
node = node + numNodes(child)
return node

How to add a grandchild to a python tree?

I'm trying to implement a Tree in python, I found this thread and tried to work my own tree, but I got stuck at how to add grand childrens.
the tree I'm trying to construct is like:
Root
ch1
ch2
ch3
ch4
So I figured that the add_child() method should be recursive:
1, If the tree has no children, add children to Root
2, for each children of Root, if one of the children equals parent, add children to it and stop the loop(so the new child is actually a grand child).
3, if there is no match, call add_child() on the current children.
But my code gives me:
Root
ch1
ch2
ch3
ch4
Btw, every time I work with recursive algorithms I get confused, could anyone give me some good advice of how to write recursive codes? or is there any good tutorials?
class Node(object):
def __init__(self, data, parent=None):
self.data = data
self.children = []
self.parent = parent
def __repr__(self, level=0):
ret = "\t" * level + repr(self.data) + "\n"
for child in self.children:
ret += child.__repr__(level + 1)
return ret
def add_child(self, node, parent):
if self.children == []:
self.children.append(node)
return
for child in self.children:
if child == parent:
child.children.append(node)
return
else:
child.add_child(node, parent)
# self.children.append(node)
if __name__ == '__main__':
tree = Node('Root')
tree.add_child(Node('ch1'), 'Root')
tree.add_child(Node('ch2'), 'ch1')
tree.add_child(Node('ch3'), 'ch2')
tree.add_child(Node('ch4'), 'ch2')
print tree
The following section makes no sense:
if self.children == []:
self.children.append(node)
return
If a node has no children you automatically add the node to that node? What if the node should be added to a different parent?
You probably meant to write:
def add_child(self, node, parent):
if self.data == parent:
self.children.append(node)
return
for child in self.children:
child.add_child(node, parent)
which produces the tree as expected.

Categories