postorder traversal how do this code reach the print line - Python - python

I have question about postorder traversal.
The code from online is:
def postorder(tree):
if tree != None:
postorder(tree.getLeftChild())
postorder(tree.getRightChild())
print(tree.getRootVal())
i am not sure how this will ever reach the print line. Here it will keep going left until there is no left so we never get past
postorder(tree.getLeftChild())
when there is no left this line:
if tree != None:
wont be met and it will not print.

Consider a leaf, which has no children. Line by line:
if tree != None: # isn't None, so continue
postorder(tree.getLeftChild()) # will call postorder(None), which won't pass if
postorder(tree.getRightChild()) # will call postorder(None), which won't pass if
print(tree.getRootVal()) # will print
So it will reach the very bottom of the tree, and invoke the print of leaves there. Then it will recurse back up. As you noted, left subtrees will be printing before right subtrees.
Specifically about "never get past", it will. Let's consider this line, again for a leaf:
postorder(tree.getLeftChild())
For a leaf getLeftChild returns None. So that line effectively means
postorder(None)
And the if statement means that the method will just do nothing and return if None is passed.

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,#,#

Counting the leaves of a binary tree using recursion: the final return statement of (recursive function)+(recursive function)

I have been learning binary trees lately and have looked through the code for counting the leaves.
This is the recursive function to count the leaves:
def __count_leaves_recursive(self, node):
if node == None:
return 0
elif node.left == None and node.right == None:
return 1
else:
return self.__count_leaves_recursive(node.left) + self.__count_leaves_recursive(node.right)
When learning how recursion works with trees, the Python Tutor visualisation tool has been invaluable. However it hasn't helped me visualise the final return statement. I am struggling to visualise what's happening when a recursion function is added to another recursive function in the same line.
Is it simply the same as any other time the program reaches a recursive function? In that, the program simply records where it enter the function in order to return to the same spot when the function has been completed?
Is it simply the same as any other time the program reaches a recursive function?
Yes, you can image that line of code like this:
a = self.__count_leaves_recursive(node.left)
b = self.__count_leaves_recursive(node.right)
return a + b
So the first recursive call has to finish completely before the second one is launched. When that second recursive call also has finished its job, both returned values are summed up, and that value is returned to the caller.

How do we traverse from nth to last element in a linked list?

The code below returns the kth to last element of a linked list. But I don't understand how this is, because doesn't 'for I in range(k)' return values from 0 to k?? As opposed to k to the last element?
Also in general, can someone please explain the traversal of the below, as I don't quite understand it- I do understand the fundamentals of linked list and the syntax but can't quite follow the code below. e.g. why is there a need for a runner (I'm assuming this is some sort of pointer?)
def kth_to_last(l1,k):
runner = current = l1.head
for i in range(k):
if runner is None:
return None
runner = runner.next
while runner:
current = current.next
runner = runner.next
return current
e.g. input is a linked list: a -> b -> c-> d-> None
if k is b then
output: b -> c -> d -> None
in linked list, each node only knows the next node (some times the previous one too). in that case, you cannot just "jump" k nodes forward. you need to move 1 node forward k times.
in this case, runner is the pointer for the 'current' node. its often also named "current", but since this one 'runs' over the list and doesn't really care much for its content, they named it "runner".
let say runner holds the rout, i.e. node #0
runner = runner.next
the node next to node#0 is node#1, so now runner is node#1
runner = runner.next
and now runner is node#2 and so forth. each iteration of runner = runner.next forward you 1 node.
so in order to move from node#0 to node#27, you need to write runner = runner.next 27 times, or use a loop for it.
(note: the "if" part of the loop is mostly to avoid exceptions, since you cant get the "next" of null)
a simpler way to make\understand this function is by finding the length of the list, decreasing it by k and than moving forward that many nodes.

Why is the queue's peep function removing the last item and appending it?

This bit of code is from hackerrank.com.
def pop(self):
#looks at the top of the queue
if len(self.stack2) > 0:
top = self.stack2.pop()
self.stack2.append(top)
Can someone please explain why it is popping off the last item in the stack/queue and then just appending it? I thought in queues, it is first in first out. In that case, the "top" item in the queue should be self.stack2.pop(0) ?
If you are referring to this code:
def peek(self):
if len(self.stack2) > 0:
top = self.stack2.pop()
self.stack2.append(top)
else:
while(len(self.stack1) > 1):
self.stack2.append(self.stack1.pop())
top = self.stack1.pop()
self.stack2.append(top)
return top
... then the clue is in the name: the two lines in question pop a value off the top of self.stack2, storing it in the variable top, then push it back onto the top of the stack so that the stack remains unchanged, and the value can be returned in the last line of the method. Hence the name peek, as in "take a peek at the top value on the stack without permanently changing anything".
The rest of the code, including the else clause in peek(), is the classic implementation of a two-stack queue, explained in detail here:
https://stackoverflow.com/a/39089983

Understanding This Depth First Search Algorithm

I have been given a DFS algorithm that returns the shortest path to a goal node. It takes as arguments a graph (with all of the nodes and their paths), a starting node, a goal node, and a list of nodes that have been visited (initialized as empty). Here is the code:
def shortestPath(graph, start, end, visited = []):
path = str(start)
if start == end:
return path
shortest = None
for node in graph.childrenOf(start):
if str(node) not in visited:
visited = visited + [str(node)]
newPath = shortestPath(graph, start, end, visited)
if newPath = None:
continue
if shortest == None or len(newPath) < shortest:
shortest = newPath
if shortest != None:
path = path + shortest
else:
path = None
return path
I understand the concept of Depth First Search, but this recursion is boggling my mind. Let me know if my train of thought is at all on track and where I'm getting derailed.
So basically, the recursion occurs when newPath is assigned a value, which of course is a call to shortestPath. At that point, the recursion goes all the way down the graph until it either reaches a node with no children or the goal node. If it reaches a node with no children that isn't the goal, the base case is ignored, and the entire for loop is ignored, returning a value of none. That None then is simply passed up the chain of recursion. If it reaches the goal node, then the bottom layer of the recursion actually returns a value (path), which bubbles up to the top of the recursion.
At that point I get confused, because of what is going on with "shortest." So every time an actual value is returned for newPath, shortest is assigned that value, but then it is added to path. But let's say I have multiple paths to the goal node. I successfully find the first path, and path is equal to the sum of all of the newPaths/shortests. But then for the next recursion that successfully reaches the goal, doesn't path just keep adding on more newPaths? So won't the final result be a long list of every path I COULD visit to reach the goal node instead of the shortest path?
The path variable is local to the function. Every recursion call has its own stack frame - it is independent from the other calls). That means when the next call starts, then everything is brand new.

Categories