Python, calculating family tree depth from one member to another - python

I have a dictionary with family tree data(key - name of a person, it's value - children).
I'd like to recursively get a depth from one given member to another (get_depth(from_person, to_person)).

I would choose DFS, since it makes keeping track of the depth easy.
def get_depth(root, target):
if root == target:
return 0
if not d[root]:
return None
for child in d[root]:
depth = get_depth(child, target)
if depth is not None:
return 1 + depth
return None
The last return is strictly speaking unnecessary, but I prefer to spell these things out. Feel free to ask any questions, but this should be fairly self-explanatory. You might feel more comfortable replacing None with -1 and then checking if depth >= 0

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.

Perfect Binary Tree with correct data

I am having a problem trying to fill the data a perfect binary tree with a known number of nodes with the correct data. Basically, I have an implementation that creates this:
7
5 6
1 2 3 4
However, I am looking to create a tree like this:
7
3 6
1 2 4 5
My current implementation for inserting the nodes of a tree is as follows.
def _add_node(self, val, ref = None):
# reference to root of tree
ref = self.root if ref is None else ref
if ref.right is None:
ref.right = Node(val, ref)
return
elif ref.left is None:
ref.left = Node(val, ref)
return
else:
parent = (val - 1) / 2
if parent % 2 == 0:
self._add_node(val, ref.left)
else:
self._add_node(val, ref.right)
Given x nodes I create a tree using range(x) and calling add_node(i) for each iteration. This works fine except its order is incorrect.
For the life of me I cannot figure out an easy way to set the values to represent the bottom layout rather than the top. Can anyone help me out?
This seems to be an issue with the order that you are entering data in. How are you passing in the data?
Also think about your implementation. You check to see whether the right child is empty and if it is you place the node there. However, if it isn't you move on to the left node. This is where the issue is happening.
Assuming you are passing in the data in reverse chronological order you start with 7 at the root. Then you move to 6 which you place in the right node. Then move on to 5; you check to see whether the right node is empty, which is isn't because it is filled with 6, so you move on to check if the left node is empty and find that it is. So you place 5 there.
Do you see the issue?
You need to figure out a way to get around this issue, but hopefully this was good in helping you debug.
Good Luck!

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