Maximum sum in a non-binary tree in Python - python

I have a non-binary tree and each node of that tree has a value. I would like to get the maximum sum available.
For example:
10
9 8 7
1 2 5 5 15
The return would be 10+7+15=32
I know how to do this if the tree was binary, but what if the tree has n branches?
This code is the binary one taken from the first answer of this question: Find the maximum sum of a tree in python

Assuming each node has a value attribute and a children attribute which is either a list of child nodes, an empty list, or None:
def tree_sum(node):
if node.children:
child_sums = []
for child in node.children:
child_sums.append(tree_sum(child) + node.value)
return max(child_sums)
else:
return node.value
print tree_sum(root)

Here's one approach:
class Node:
def __init__(self, value):
self.value = value
self.children = []
def max_sum(root):
if len(root.children) == 0:
return root.value
sums = []
for child in root.children:
sums.append(root.value + max_sum(child))
return max(sums)
n_9 = Node(9)
n_9.children.extend([Node(1), Node(2), Node(5)])
n_8 = Node(8)
n_8.children.extend([Node(5)])
n_7 = Node(7)
n_7.children.extend([Node(15)])
n_10 = Node(10)
n_10.children = [n_9, n_8, n_7]
print max_sum(n_10)
# Output: 32

Related

Python Printing Specific Character in Empty Binary Tree Output

I have a binary tree generated as follows
class Node:
def __init__(self,data):
# Left Child
self.left = None
# Right Child
self.right = None
# Node Value
self.data = data
def insert(self, data):
# Compare the new value with the parent node
if self.data:
# Less than or equal goes to the Left
if data <= self.data:
if self.left is None:
self.left = Node(data)
else:
self.left.insert(data)
# Greater than goes to the right
elif data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.data = data
Now suppose we populate the binary tree with the following
Numbers = [4, 7, 9, 1 , 3]
for index in range(len(Numbers)):
if index == 0:
root = Node(Numbers[index])
else:
root.insert(Numbers[index])
Which generates the following binary tree:
4
/ \
1 7
/ \ / \
. 3 . 9
I have written the following to print the binary tree:
def PrintTree(self, root):
thislevel = [root]
while thislevel:
nextlevel = list()
Curr_Level = ""
for n in thislevel:
Curr_Level += " " + str(n.data)
if n.left:
nextlevel.append(n.left)
if n.right:
nextlevel.append(n.right)
print(Curr_Level)
thislevel = nextlevel
root.PrintTree(root=root)
which generates the following output
4
1 7
3 9
However, I would like the code print the empty entries with an "#", i.e. I want my code to output the following:
4
1 7
# 3 # 9
How can I go about adjusting my PrintTree function to achieve this?
Run a modified version of BFS. More specifically, run breadth first search (BFS) starting from the root node. This will assign a level to each node. During BFS, when a current node has a missing child, add an # node in its place to the FIFO queue. Print a node each time it is removed from the queue. Print in a new line each time a node with a new level is removed from the queue.

How do I find the maximum depth of a tree?

I have a tree data structure, defined as below:
class Tree(object):
def __init__(self, name='ROOT', children=None):
self.name = name
self.children = []
if children is not None:
for child in children:
self.add_child(child)
def __repr__(self):
return self.name
def add_child(self, node):
assert isinstance(node, Tree)
self.children.append(node)
I need to write a function to find the depth of the tree. Here is the function I wrote (takes a Tree as input, and returns an integer value as output), but it is not giving the right answer:
def depth(tree):
count = 1
if len(tree.children) > 0:
for child in tree.children:
count = count + 1
depth(child)
return count
How do I correct it?
While your depth(child) does do the recursive call, it does not do anything with the return value (the depth). You seem to be simply counting the nodes at a given level and calling that the depth (it's really the width).
What you need is something like (pseudo-code):
def maxDepth(node):
# No children means depth zero below.
if len(node.children) == 0:
return 0
# Otherwise get deepest child recursively.
deepestChild = 0
for each child in node.children:
childDepth = maxDepth(child)
if childDepth > deepestChild:
deepestChild = childDepth
# Depth of this node is one plus the deepest child.
return 1 + deepestChild
How about you just do a max of all the depth on each node recursively?
def max_depth(self, depth=0):
if not self.children:
return depth
return max(child.max_depth(depth + 1) for child in self.children)

How do you print all nodes in a specific level?

I want to figure out how to print all nodes at a specific level. Right now, I can get to that level but I can only print out a part of the nodes. How would I get it to print all the nodes from all branches instead of nodes from one branch? I tried recursively calling get_level_nodes but it keeps outputting an error.
import random
class Node(object):
def __init__(self, value):
self.value = value
self.children = []
self.parent = None
def create_children(self, infects, depth):
# root node
if depth == 0:
return
for i in range(infects):
rand2 = random.random()
if rand2 <= 0.37:
if rand2 <= 0.02:
child = Node('NA')
else:
child = Node('CA')
else:
if rand2 <= 0.5:
child = Node('NS')
else:
child = Node('CS')
child.parent = self
child.grandparent = self.parent
self.children.append(child)
# recursive call to create more child nodes
child.create_children(infects, depth-1)
def tree_level(self):
level = 0
p = self.parent
while p:
level += 1
p = p.parent
return level
def print_tree(self):
spaces = ' ' * self.tree_level() * 2
prefix = spaces + '|__' if self.parent else ''
print(prefix + self.value, self.quarantined)
if self.children:
for child in self.children:
if child.value != None:
child.print_tree()
def get_level_nodes(self, cur_level):
level = 0
c = self.children
while c:
level += 1
c = self.children
if level == cur_level:
return c
if __name__ == "__main__":
rand1 = random.random()
if rand1 <= .35:
a = Node('CA')
else:
a = Node('CA')
a.create_children(2, 5) # create_children(R0, depth)
for child in a.get_level_nodes(4):
print(child.value)
a.print_tree()
Your get_level_nodes function has some issues:
c never changes value: it always represents self.children, so you are not actually moving down in the tree. You should somewhere iterate over those children and extend your collection of nodes with the children of these children.
You start out with self.children, but that list of nodes already represents the second level in the tree. You should foresee that the function can return the top-level of the tree, i.e. a list with just the root node in it.
I'll assume that you use the definition of "level" as specified in Wikipedia, although other definitions exist:
Level
      1 + the number of edges between a node and the root, i.e. (depth + 1)
Solution:
def get_level_nodes(self, cur_level):
nodes = [self]
for i in range(cur_level-1): # assuming that cur_level is at least 1
children = []
for node in nodes:
children.extend(node.children)
nodes = children
return nodes

How can I find the depth of a specific node inside a binary tree?

I'm trying to figure out a recursive solution to this problem. The main thing is to return the level in the binary tree where the node is.
def find_depth(tree, node):
if node == None:
return 0
else:
return max(find_depth(tree.left))
#recursive solution here
Using this class for the values:
class Tree:
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
Example: Calling find_depth(tree, 7) should return the level where 7 is in the tree. (level 2)
3
/ \
7 1 <------ return that 7 is at level 2
/ \
9 3
maybe this is what you are looking for
def find_depth(tree, node):
if node is None or tree is None:
return 0
if tree == node:
return 1
left = find_depth(tree.left, node)
if left != 0:
return 1 + left
right = find_depth(tree.right, node)
if right != 0:
return 1 + right
return 0
You need to provide information about depth in find_depth call. It might look like this (assuming 0 is a sentinel informing that node is not found):
def find_depth(tree, node, depth=1):
if node == None:
return 0
if tree.value == node:
return depth
left_depth = find_depth(tree.left, node, depth+1)
right_depth = find_depth(tree.right, node, depth+1)
return max(left_depth, right_depth)
Then you call it with two parameters: x = find_depth(tree, 7).
Recursion is a functional heritage and so using it with functional style yields the best results -
base case: if the input tree is empty, we cannot search, return None result
inductive, the input tree is not empty. if tree.data matches the search value, return the current depth, d
inductive, the input tree is not empty and tree.data does not match. return the recursive result of tree.left or the recursive result of find.right
def find (t = None, value = None, d = 1):
if not t:
return None # 1
elif t.value == value:
return d # 2
else:
return find(t.left, value, d + 1) or find(t.right, value, d + 1) # 3
class tree:
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
t = tree \
( 3
, tree(7, tree(9), tree(3))
, tree(1)
)
print(find(t, 7)) # 2
print(find(t, 99)) # None
You can implement the find method in your tree class too
def find (t = None, value = None, d = 1):
# ...
class tree
def __init__ #...
def find(self, value)
return find(self, value)
print(t.find(7)) # 2
print(t.find(99)) # None

Counting nodes in a binary tree recursively

I have to count nodes in a binary tree recursively. I'm new to python and can't find any solution for my problem to finish my code.
This is what I have already tried. As you can see it is not complete, and I can't figure out where to go.
class Tree:
def __init__(self, root):
self.root = root
def add(self, subtree):
self.root.children.append(subtree)
class Node:
def __init__(self, value, children=None):
self.value = value
self.children = children if children is not None else []
def check_root(tree):
if tree.root is None:
return 0
if tree.root is not None:
return count_nodes(tree)
def count_nodes(tree):
if tree.root.children is not None:
j = 0
for i in tree.root.children:
j = 1 + count_nodes(tree)
return j
print(count_nodes(Tree(None))) # 0
print(count_nodes(Tree(Node(10)))) # 1
print(count_nodes(Tree(Node(5, [Node(6), Node(17)])))) #3
With every new step I'm getting different error. E.g. with this code I have exceeded maximum recursion depth.
Thank you for your time reading this. Any hint or help what to do next would be greatly appreciated.
I would start by passing the root node to the count_nodes function -
print(count_nodes(Tree(None)).root) # 0
print(count_nodes(Tree(Node(10))).root) # 1
print(count_nodes(Tree(Node(5, [Node(6), Node(17)]))).root) #3
or make a helper function for that.
Then the count_nodes function can simply look like this
def count_nodes(node):
return 1 + sum(count_nodes(child) for child in node.children)
EDIT: I have just noticed, you can have a None root, this means, you should also handle that:
def count_nodes(node):
if node is None:
return 0
return 1 + sum(count_nodes(child) for child in node.children)
And if you really want to handle tree or node in one function, you can make it a bit uglier:
def count_nodes(tree_or_node):
if isinstance(tree_or_node, Tree):
return count_nodes(tree_or_node.root)
if tree_or_node is None:
return 0
return 1 + sum(count_nodes(child) for child in tree_or_node.children)
and then you can call it like you originally did.
Your problem is that you're counting the same tree infinitely. Take a look at this line:
j = 1 + count_nodes(tree)
An Easy Way:
Lets assume, A is a binary tree with children or nodes which are not NULL. e.g.
3
/ \
7 5
\ \
6 9
/ \ /
1 11 4
Now in order to count number of nodes, we have a simple workaround.
Recursive Method: >>> get_count(root)
For a binary tree, the basic idea of Recursion is to traverse the tree in Post-Order. Here, if the current node is full, we increment result by 1 and add returned values of the left and right sub-trees such as:
class TestNode():
def __init__(self, data):
self.data = data
self.left = None
self.right = None
Now we move forward to get the count of full nodes in binary tree by using the method below:
def get_count(root):
if (root == None):
return 0
res = 0
if (root.left and root.right):
res += 1
res += (get_count(root.left) +
get_count(root.right))
return res
At the end, in order to run the code, we'll manage a main scope:
Here we create our binary tree A as given above:
if __name__ == '__main__':
root = TestNode(3)
root.left = TestNode(7)
root.right = TestNode(5)
root.left.right = TestNode(6)
root.left.right.left = TestNode(1)
root.left.right.right = TestNode(4)
Now at the end, inside main scope we will print count of binary tree nodes such as:
print(get_Count(root))
Here is the time complexity of this recursive function to get_count for binary tree A.
Time Complexity: O(n)

Categories

Resources