BFS binary tree that implements Stack in Python - python

I am looking for implementing BFS (Breadth-First Search) of binary tree in Python using Stack (not Queue!).
class Stack:
def __init__(self):
self.data = []
def Empty(self):
return self.data == []
def Push(self, x):
self.data.append(x)
def Pop(self):
return self.data.pop()
def Peek(self):
return self.data[len(self.data)-1]
def Size(self):
return len(self.data)
class Node:
def __init__(self, data, left, right):
self.data = data
self.l_node = left
self.r_node = right
class Tree:
def __init__(self):
self.root= None
def bfs_stack(self, node):
pass
t = Tree()
t.root = Node("1")
t.root.l_node = Node("2")
t.root.l_node.l_node = Node("4")
t.root.l_node.r_node = Node("5")
t.root.l_node.r_node.l_node = Node("8")
t.root.r_node = Node("3")
t.root.r_node.l_node = Node("6")
t.root.r_node.r_node = Node("7")
t.root.r_node.r_node.l_node = Node("9")
t.root.r_node.r_node.l_node.l_node = Node("11")
t.root.r_node.r_node.r_node = Node("10")
I created Stack() class to work with.
I tried to combine recursion and stack pushing but I'm out of ideas.
Queue implementation is very easy but it's important for me to have a Stack() implementation.

Algorithmically, a BFS is tied to queue operations and DFS is tied to stack operations.
If you only have stacks though, you can form something like a queue out of two stacks.
Stacks implement a FILO (first-in,last-out) order, whereas queues implement FIFO (first-in, first out).
If you put three numbers, 1,2,3 in a stack, and pull them out, you come up with 3,2,1.
If you did the same thing with a queue, they would come out as 1,2,3.
Now suppose we put 1,2,3 in stack A, pulled them out as 3,2,1, and put them in stack B. Taking them out of stack B would yield them as 1,2,3, which means that going through two stacks resembles going through a queue.
Now this argument by itself works if you have the whole sequence and input everything all at once and then take it all out. But for BFS/DFSsearches this is not true, you input some things, then take them out before you input more.
You can still make a BFS work by only moving things from stack A to stack B if stack B is totally empty, and at that point transferring the entirety of stack A into B. B being empty ensures things that are put into stack B are all processed before the things being collected in stack A. Putting the entirety of A into B ensures all nodes at the same distance from the center node are kept in the same stack (either A or B) at any given time. Every transfer of content from stack A to B represents being done processing a BFS level at a particular distance from the start node, and inner layers are guaranteed to process before outer layers, which is what a BFS is.
stack_a = Stack()
stack_b = Stack()
stack_b.Push(t.root)
while len(stack_a)+len(stack_b)>0:
if len(stack_b) >0:
current_node = stack_b.Pop()
else:
while len(stack_a)> 0:
stack_b.Push(stack_a.Pop())
current_node = stack_b.Pop()
process(current_node) # this gets called on nodes in BFS order
for neighbor in [current_node.l_node, current_node.r_node]:
stack_a.Push(neighbor)
#can generalize this to non-binary graphs by iterating through all unvisited neighbors
#for cyclical graphs, must track processed nodes to ensure nodes don't get processed more than once

Related

Populate binary decision tree from indented file in C#

I have nested if-else statements generated by the D4.5 algorithm from a dataset in python. I want to transform this into a binary decision tree in Unity C# so I can traverse through it with my NPCs to create simple data-driven AI.
This is my input (currently indented by tabs but I can change it to a sequence of chars or just a number which tells me what level I am currently at):
HP is > 0:
SeesEnemy is False:
HearEnemy is False:
Idle
HearEnemy is True:
Seeking
SeesEnemy is True:
EnemyInRange is True:
Attacking
EnemyInRange is False:
Chasing
HP is <= 0:
Dead
And I want Tree like this with negative child on left and positive on right:
Tree
I do not have a problem with the implementation or traversing a tree but with the creation of it from data.
Another variant would be to transform input to this format, which I can deserialize to desired tree:
"HP > 0?,Dead,#,#,SeesEnemy?,HearEnemy?,Idle,#,#,Seeking,#,#,EnemyInRange?,Chasing,#,#,Attacking,#,#"
Where # means there is no child on left side and #,# means there are no children at all. This could be ideally done on python side.
I tried to read the input line by line while the number of tabs at the start of the line was incrementing like in the Depth-first search. My idea was to create a child of a current node on the left or right side based on false/true (<=/>) and return to the parent when the indentation of the next line was smaller than the previous one and continue with another side. But there was a problem with pointing to the current node.
I also tried to parse the file in levels (level 0 was "HP is > 0" and "HP is <= 0" etc.) but there were other problems which I could not solve.
I think there is some elegant recursion way to do this but I cannot find it nor figure it out itself. Thanks.
Instead of building Data Structure Tree and then make a decision traversing, you can build it through expressions. Straight with your boolean conditions and actions and lazy execution of branches. Just traverse your file and build it through expression tree iterator:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/
Then, when you got your final expression you can just invoke (compile and invoke) and it will give you result. I built several DSL on this for my work, which are more complex (with bodies, loops, etc) than your case, so you should be fine.
If you struggle with parsing/traversing you can read more about bottom-up parsing on wiki - https://en.wikipedia.org/wiki/Bottom-up_parsing
To say it simple, you just create stack of simple expressions out of you file (usually constants or simple boolean conditions) and as you go through file, when something complete formed at the tail you transform tail (one or more elements) to next expression, then continue until you parsed entire file.
Here is a way to create a tree, using a stack while reading the input string
import re
class Node:
def __init__(self, data, condition=None):
self.data = data
self.condition = condition
self.left = self.right = None
def add(self, data, test):
node = Node(data, test)
if not self.right and self.condition != "False":
self.right = node
else:
self.left = node
if self.condition in ("False", "True"):
self.condition = ""
return node
def preorder(self):
if self:
yield self.data + (" " + self.condition if self.condition else "") + ("?" if self.condition is not None else "")
yield from Node.preorder(self.left)
yield from Node.preorder(self.right)
else:
yield "#"
def tree(s):
stack = [(-1, Node(None))]
nodedepth = -1
for match in re.finditer(r"([ ]*)(\S+)(?: is (.*?):)?[ ]*$", s, re.M):
depth = len(match[1])
while depth <= stack[-1][0]:
nodedepth, node = stack.pop()
parent = stack[-1][1]
stack.append((depth, node if nodedepth == depth else parent.add(match[2], match[3])))
return stack[0][1].right
The tree function makes the tree from a string. The preorder method can be used to generate the serialized output string in the format you gave (with the hashes).
Example run:
s = """HP is > 0:
SeesEnemy is False:
HearEnemy is False:
Idle
HearEnemy is True:
Seeking
SeesEnemy is True:
EnemyInRange is True:
Attacking
EnemyInRange is False:
Chasing
HP is <= 0:
Dead"""
root = tree(s)
print(",".join(root.preorder()))
Output:
HP > 0?,Dead,#,#,SeesEnemy?,HearEnemy?,Idle,#,#,Seeking,#,#,EnemyInRange?,Chasing,#,#,Attacking,#,#

How to go back to pre-visited node in a binary tree (preorder traversal, solving No.1028 problem in LeetCode )

I'm struggling to solving No.1028 problem in LeetCode by myself. As a step of my solution, I wanna construct a binary tree below by adding nodes one by one in an order of 'preorder traversal'.
When I'm done with leftmost nodes with moving the cursor., now I'm supposed to add 'TreeNode(5)' as a right child node of 'TreeNode(2)'.
class TreeNode(object):
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
root = TreeNode(1)
# cursor = root
# Add TreeNode(N) as a childNode
# cursor = cursor.left
# ...repeat
# Now cursor reaches TreeNode(4)
However, I have no idea of bactracking to the pre-visited nodes.
I tried to do so by stacking pre-visited nodes in my stack and popping few times.
tmp = [TreeNode(1), TreeNode(2), TreeNode(3), TreeNode(4)]
tmp.pop()
tmp.pop()
cursor = tmp.pop()
But only to fail since cursor does contain TreeNode(2) but the tree-relationship between nodes are deleted (I know actually they are not deleted but just cursor becomes another class object).
Could anyone let me know how to visit parent node?
I tried to do so by stacking pre-visited nodes in my stack and popping few times.
That really is the way to do it.
tmp = [TreeNode(1), TreeNode(2), TreeNode(3), TreeNode(4)]
You should only create nodes as you process them from the input, and append them to the stack (using stack.append(node)). Don't recreate nodes, as those will be different objects.
Before appending the node to the stack, you should first verify what the level is you get from the input. That should become the size of the stack -- so if the stack is larger than the level, then pop elements from it until the stack has the right size. Only then append the new node to the stack.
Finally, you need to establish the relationship between new node and its parent. Its parent is the preceding node on the stack. Remains to find out whether the new node should become a left child or a right child. If the parent happens to already have a left child, then make the new node the right child of the parent, otherwise it should become the left child.
With these ingredients you should be able to code it.
Here is a spoiler solution:
import re # Use regular expression to easily tokenise the input
class Solution:
def recoverFromPreorder(self, s):
stack = []
for dashes, valstr in re.findall("(-*)(\d+)", s):
level = len(dashes)
node = TreeNode(int(valstr))
del stack[level:] # Potentially truncate the stack
if level: # This node has a parent: establish link
if not stack[-1].left:
stack[-1].left = node
else:
stack[-1].right = node
stack.append(node)
return stack[0]
# Test run
root = Solution().recoverFromPreorder("1-2--3---4-5--6---7")

Walk through decision tree and capture each node

I'm trying to walk through a Decision Tree one node at a time.
Each node can have 2-3 paths
On the nodes with 3 paths, one of the paths is always an end point, and one is sometimes and end point
We can't move backwards, but can start over
Our available functions are
getCurrentNode() #returns string of current node's path from start (ex. 'A-B-A-A-B')
getCurrentNodePaths() #returns number of possible paths from this node
startOver() #puts us back at node 0
takePath(int pathNumber) #traverse the decision tree down a desired path
I've written this pseudo code that should walk through each node recursively, but only for the 'left' most path
# Start
def walk(pathNumber):
takePath(pathNumber)
next_nodes_paths = getCurrentNodePaths()
if next_nodes_paths.length > 0:
walk(0)
startOver()
walk(0)
How can I get this to keep track of where it's been, start over, and take a new path
This creates a model of the decision tree. You can navigate to a certain Node with the select_path method. path is a string like '03231002'. You can walk over the whole tree and apply a function at each point, by using the apply_function method. There is an example for walking the whole tree.
def select_path(path):
startOver()
for pathNumber in path:
takePath(int(pathNumber))
class Node:
def __init__(self,path):
self.path = path
self.select()
self.num_children = getCurrentNodePaths().length
self.children = [Node(path+str(i)) for i in range(self.num_children)]
def select(self):
select_path(self.path)
def apply_function(self, func, recursive=False):
self.select()
func()
if recursive:
for child in self.children:
apply_function(self, func, recursive=True)
root = Node('')
#walk whole tree and apply function function:
#def function:
# pass
#root.apply_function(function, recursive=True)
Since we cannot move backwards, your approach of (recursive) depth-first search is probably difficult to handle: You can never know if a node is an end node without actually moving there, and once you have arrived, you can only make a new walk to the previous node all the way from the start.
I suggest using a breadth-first search instead (partly adopted from this example):
def walk(currentNode):
queue = []
visited = []
queue.append(currentNode)
visited.append(currentNode)
while queue:
s = queue.pop(0)
# go to node from start by following the path
startOver()
for p in s:
takePath(int(p))
for i in range(getCurrentNodePaths()):
nextNode = getCurrentNode() + str(i)
queue.append(nextNode)
visited.append(nextNode)
# Use this if you want a list of paths to end points only
# if getCurrentNodePaths() > 0:
# visited.remove(s)
print(visited)
startOver()
walk(getCurrentNode())
This will give you a list of paths to all nodes in your tree in visited.
A few notes:
A node in the queue and visited lists is assumed to be represented by its path from the start node as a string (e.g. 0, 101, 012012).
Thus, a node can be reached by just following its sequence of numbers.
Moreover, the successor nodes can be constructed by
appending the numbers within range(getCurrentNodePaths()).

Checking for a loop in an un-directed tree graph python

I am trying to develop a python program to check if there is a loop in the graph when a new line is added.
I am storing different lines in a list ordered by shortest length first, and the lines are a class:
class Line():
def __init__(self,node1,node2,length):
self.node1 = node1
self.node2 = node2
self.length = int(length)
self.drawn = False
And the nodes are stored in a list:
nodes = ["A","B","C","D","E","F"]
When my program has run it stores the route as a list:
route = [class(Line),class(Line)...]
What i want it to do is to check that when a new line is added that it does not form a cycle. I plan to use a method inside of a bigger class:
something like:
def check_loop(new_line,graphs):
add new line to graph
if there is a loop in graphs:
return False
else:
return True
(sorry this is one of my first posts so the format is rubbish)
To identify if a cycle is created in a tree is pretty simple, all you need to do is pick a node and then breadth first search the entire tree from that node. If any node has been visited before by the time you reach it, then you know that there is a cycle because there was an alternative path that reached that node beside the one that you have taken.

Recursion and Binary Trees

#Get length of the longest path through recursion
def max_height(node):
if not node:
return 0
left = max_height(node.left) #Base Case based on my understanding
right = max_height(node.right) #Base Case based on my understanding
return max_height(left, right) + 1
I keep calling the max_height to get the length but I'm getting an error. I've thought of three possibilities:
1) I misunderstand the concept of the base case and I don't actually have a base case.
2) I'm not properly spacing Python code.
3) I'm not recursively getting the height of the BST at all but rather the width of the tree, which is affecting later calculations.
I know it is similar to this question, but the main difference is that I'm really trying to use recursion , where the other question used iteration and merely called it recursion.
how to find the height of a node in binary tree recursively
The base case is where the recursion stops and you have one: not node (node == None)
I don't see an issue with the spacing... Make sure you use only tabs or only spaces
This does produce the height: the number of nodes from root to leaf along the longest root-leaf path. At every node level, you add 1, and follow the higher subtree.
def max_height(node):
if not node: # this is the base case:
return 0 # where all recursive calls eventually stop
left = max_height(node.left) # <- these are the recursive calls:
right = max_height(node.right) # <- function x is called inside function x
return max(left, right) + 1 # max here, not max_height
Note that this is merely a more verbose version of this answer to the question you linked.
All answered were right but, I faced little problem while writing inside the class;
So, the code goes like this, I hope this helps.
class Tree(object):
def height(self, root):
if root == None: #root == None
return 0
else:
return 1 + max(self.height(root->left), self.height(root->left))
t = Tree()
t.height(t)

Categories