Python: breadth first search - python

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

Related

How to count all the nodes after parent node in python

In the given tree when we pass node-- 2 then output is 5, it counts all the nodes after 2,
4-5-6-7-8
def count(node):
if node is None:
return 0
return 1+count(node.lchild)+count(node.rchild)
but with this, I only count its child nodes
As others have said, your code is designed for node instances that have lchild and rchild members, but the tree in the picture has a node with 3 children, so it cannot be represented as such a node.
You need a different definition of your Node class:
class Node:
def __init__(self, value, *children):
self.value = value
self.children = children
Then I would define count as a method of that class, not as a stand-alone function:
class Node
# ...
def count(self):
return sum(1 + child.count() for child in self.children)
Example run:
# Create the tree as pictured in the question
root = Node(1,
Node(2,
Node(4),
Node(5,
Node(7),
Node(8)
),
Node(6)),
Node(3)
)
# Select the node with value 2 (at left of root) and call the `count` method:
print(root.children[0].count())
Your code runs correctly on Binary Tree but the Tree of your question is not Binary Tree, you need a different approach. You need to define list of child for every node in your class and use this code:
def count(node):
if node is None:
return 0
count = 1
for child in node_child
count += count(child)
return count

How to extract all ancestors of a nodes and leaves in a decision tree?

I don't know how difficult is this question. Suppose we train a decision tree and then I want to records all nodes and leaves in the tree, what are their ancestors (set of p for parents), and which of their ancestors are divided based on x<a (set A_l) and x>a (set A_r).
Actually, nodes can be classified as follows and I want to extract all of this information:
t = 1,...,T set of all nodes
p(t): parent of node t
A(t): set of all ancestors of node t
A_L(t): the set of ancestors of t whose left branch has been followed on the path from the root node to t
A_R(t): the set of ancestors of t whose left branch has been followed on the path from the root node to t
T_b: the set of branch nodes
T_l: the set of leaf nodes
I wrote a code and I could store all left and right children of a node, but I don't know how to determine the aforementioned sets.
class Nodes():
no_nodes = 0
def __init__(self,tree,no_total_nodes,node):
self.no_nodes = no_total_nodes
self.current_node= node
self.left_child = all_left_children(tree,self.current_node)
self.right_child = all_right_children(tree,self.current_node)
where
def func_right_node(tree,start_node):
node = tree.children_right[start_node]
return node
def func_left_node(tree,start_node):
node = tree.children_left[start_node]
return node
def all_right_children(tree,start_node):
List=[]
while True:
r_node = func_right_node(tree,start_node)
if r_node!= -1:
List.append(r_node)
start_node = r_node
elif r_node== -1:
break
return List
def all_left_children(tree,start_node):
List=[]
while True:
r_node = func_left_node(tree,start_node)
if r_node!= -1:
List.append(r_node)
start_node = r_node
elif r_node== -1:
break
return List
and all nodes and leaves are stores as follows:
TREE = decision_tree.tree_
total_number_nodes = decision_tree.tree_.node_count
All_Nodes = []
All_Leaves = []
for i in range(total_number_nodes):
All_Nodes.append(Nodes(TREE,total_number_nodes,i))
if not All_Nodes[i].left_child:
All_Leaves.append(All_Nodes[i])

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.

Successor and Predecessor - Binary Search Tree (Python)

I am trying out this successor and predecessor on Binary search tree.
Just wondering once I get hold of successor code, can I flip it over and use it for predecessor?
I've coded the successor, and tried to use it for predecessor.
However, my output value doesn't change, even though I tried to place other value..
Below is my code:
Succ
def succ(self, key):
temp = self.root
prev = None
if (temp.right is not None):
temp = temp.right
while (temp.left is not None):
temp = temp.left
prev = temp
elif temp.left is not None:e
temp = temp.left
while (temp.right is not None):
temp = temp.right
prev = temp
else:
return None
return prev.key
Predecessor
def pred(self, key):
temp = self.root
prev = None
#if right is not none, succ lies in the right sub tree
if (temp.right is not None):
temp = temp.right
while (temp.left is not None):
#return the node with the minimum key value
temp = temp.left
prev = temp
#if left not none, succ lies in the right sub tree
elif temp.left is not None:
#go right till .right is None
#return the node with the maximum key value
temp = temp.left
while (temp.right is not None):
temp = temp.right
prev = temp
else:
#no succ
return None
return prev.key
the tree
def createTree(self):
#root
self.put("F",6)
#leftSubTree
self.put("D",4)
#leftLeftSubTree
self.put("C",3)
self.put("B",2)
self.put("A",1)
#LeftRightSubTree
self.put("E",5)
#RightSubTree
self.put("I",9)
#RightLeftSubTree
self.put("G",7)
self.put("H",8)
#RightRightSubTree
self.put("J",10)
To flip the succ function and turn it into pred, you need to change every left to a right, and every right to a left.
def pred(self, key):
temp = self.root
prev = None
if (temp.left is not None):
temp = temp.left
while (temp.right is not None):
temp = temp.right
prev = temp
elif temp.right is not None:
temp = temp.right
while (temp.left is not None):
temp = temp.left
prev = temp
else:
return None
return prev.key
Let us assume you have a BST node class with three pointers/references: left, right, and parent, which correspond to the left child, right child, and parent of a given node. The only node in the tree which has a parent that points to None would be the root node.
Let us also assume that we have the following BST:
15
/ \
9 20
/ \ / \
3 10 17 21
/ \ \
1 5 11
The BST property states that for any given node n, all nodes in n's left sub-tree shall be less than n; and, all nodes in n's right sub-tree shall be greater than n.
To make things easier when implementing the successor and predecessor functions, it is helpful to have auxiliary functions for finding the minimum and maximum node of a given BST or BST sub-tree.
Minimum
def bst_minimum(tree):
minimum = tree
while minimum is not None:
minimum = minimum.left
return minimum
Maximum
def bst_maximum(tree):
maximum = tree
while maximum is not None:
maximum = maximum.right
return maximum
For the tree example above, these functions would return 1 for the minimum and 21 for the maximum.
To find the predecessor of a given node, you have to cover a few cases:
If the given node has a left sub-tree, then take the maximum of that sub-tree.
Otherwise, move up the tree, following parent nodes until either you hit None or you "turn left."
In the second case, if you hit None, that means there is no predecessor. This would be the case for the node with value 1 in the tree above. It would following parent pointers all the way past the root node.
If there is a predecessor, then it will be the first parent node you encounter after making a left turn up the tree. Put another way, it is the parent node whose value is less than the value of the node from which you started. So, node 17 above would return the root node with a value of 15.
Predecessor
def bst_predecessor(tree):
if tree.left is not None:
return bst_maximum(tree.left)
parent = tree.parent
child = tree
while parent is not None and child is parent.left:
child = parent
parent = child.parent
return parent
Since the successor is simply the symmetrical operation to predecessor, you can modify predecessor by flipping the various operations. Namely:
Instead of checking the left sub-tree and finding the maximum, you want to check the right tree and find its minimum.
Otherwise, follow parent nodes until you can't anymore (in which case there is no successor), or you turn right. So, the successor of node 5, would be node 9 in the tree above.
Successor
def bst_successor(tree):
if tree.right is not None:
return bst_minimum(tree.right)
parent = tree.parent
child = tree
while parent is not None and child is parent.right:
child = parent
parent = child.parent
return parent

Adding Children Nodes to a Tree in 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.

Categories