BFS / level order traversal in Non-Binary Tree using queue - python

I have to make two classes: NonBinaryTree and SingleNode class containig some methods working on nodes as well as entire tree (in class NonBinaryTree). I have encountered problems with implementing BFS (level order) traversal through Non Binary Tree using queue (first in, first out type). As there are many resources for Binary Tree, where each node have up to two children, I have not found anything that could help me solve problem with Non Binary Tree.
So far, I made this code:
import queue
from typing import List, Callable
class SingleNode:
def __init__(self, name : str):
self.name : str = name
self.children : List['SingleNode'] = []
def add(self, *nodes : List['SingleNode']):
for node in nodes:
self.children.append(node)
def is_leaf(self):
if len(self.children) == 0:
return True
return False
def level_order_traversal(self, visit: Callable[['SingleNode'], None]) -> List[List[int]]:
fifo = queue.Queue()
levels = []
fifo.put([root])
while fifo and root:
currNode, nextLevel = [], []
while not fifo.empty():
node = fifo.get()
currNode.append(node)
for child in node.children:
nextLevel.append(child)
fifo.put(nextLevel)
levels.append(currNode)
return levels
def search(self, name : str):
if self.name == name:
print(self.__repr__())
for child in self.children:
child.search(name)
return None
def __str__(self):
return f"{self.name}"
def __repr__(self):
return f"TreeNode({self.name}) : {self.children}"
class NonBinaryTree:
root_node: SingleNode
My tree:
enter image description here
I need to go on nodes in this order: 1, 2, 3, 4, 5, 6, 7, 8, and so on...

Why don't you follow similar approach as BFS traversal in binary tree, it's just in this case it's non binary but the logic is always gonna be same,
class Solution:
def levelOrder(self, root: 'Node') -> List[List[int]]:
levels = []
queue = [root]
while queue and root:
currNode,nextLevel = [],[]
for node in queue:
currNode.append(node.val)
for child in node.children:
nextLevel.append(child)
queue = nextLevel
levels.append(currNode)
return levels

Related

How to pass in list input into function for traversing tree?

I am writing some code for traversing a tree:
root = [1, None, 2, 3]
class Treenode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def post_order_traversal_iterative(self,root):
stack = [root]
output = []
if not root:
return []
while stack:
curr = stack.pop()
output.append(curr.val)
if curr.right:
stack.append(curr.right)
if curr.left:
stack.append(curr.left)
return output
x = Solution()
print(Solution.post_order_traversal_iterative(x,root))
But I am getting the error that a 'list object has no attribute val'- which I totally get, but then how do I pass in my list as the input??
There are a few issues in your code:
post_order_traversal_iterative expects a Treenode instance but you're passing it a list instead; you should do something like root = Treenode() and then x.post_order_traversal_iterative(root)
once again since you put on the stack the left and right values of the current node they too should be instances of Treenode, not integer
apart from being a list and not a Treenode your root contains four elements while three are requested
So assuming you were trying to create a mini tree with just a root node "1" with two children "2" and "3" you should have something like
rootnode = Treenode(val=1)
firstchild = Treenode(val=2)
secondchild = Treenode(val=3)
rootnode.left = firstchild
rootnode.right = secondchild
or more succinctly
rootnode = Treenode(val=1, left=Treenode(val=2), right=Treenode(val=3))

How to find max depth of n-ary tree using bfs?

This is my node definition :
class Node(object):
def __init__(self, val, children):
self.val = val
self.children = children
Now I've to find max depth in the tree. I'm using breadth-first search to mark the level of each node, then returning the max of levels.
This is my code :
def maxDepth(self, root):
"""
:type root: Node
:rtype: int
"""
if(root == None):
return 0
q = []
q.append(root)
level={root.val:1}
while(len(q)>0):
s = q.pop(0)
for c in s.children:
q.append(c)
level[c.val]=level[s.val]+1
return max(level.values())
It's working on some cases but giving the wrong answer in many cases. I don't understand where I'm missing the concept?
As suggested by #pfctgeorge, i was appending level according to node value, but there can be multiple nodes with same value as it's a tree, it'll give wrong answer in that cases.
Since you know where you went wrong, you could do something like below to achieve max depth of the tree-
Pseudocode:
q = []
q.offer(root)
level = 1
while q.isEmpty() == false:
size = q.size()
for i = 0 to size:
curr_node = q.poll()
for each_child in curr_node:
q.offer(each_child)
level = level + 1
return level

Printing Binary Tree in Level Order without Left or Right in Python

This question is seeking an alternative to the answers given in this post.
How can I create a string which has each level of the tree on a new line with the following Binary Tree Structure:
# A Node is an object
# - value : Number
# - children : List of Nodes
class Node:
def __init__(self, value, children):
self.value = value
self.children = children
My problem is that I'm used to Tree Structures like this:
class Node(object):
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
Here is an example tree:
exampleTree = Node(1,[Node(2,[]),Node(3,[Node(4,[Node(5,[]),Node(6,[Node(7,[])])])])])
That would print as:
1
23
4
56
7
Any help or ideas on how to create a definition using that new structure would be very appreciated.
You can just use list.extendto add child nodes instead of appending them one by one.
class Node:
def __init__(self, value, children):
self.value = value
self.children = children
def traverse(root):
curr = [root]
while curr:
next_level = []
for n in curr:
print(n.value, end='')
next_level.extend(n.children)
print()
curr = next_level
exampleTree = Node(1,[Node(2,[]),Node(3,[Node(4,[Node(5,[]),Node(6,[Node(7,[])])])])])
traverse(exampleTree)
prints
1
23
4
56
7
(For anyone who didn't read the question, this is entirely derivative of this answer)
You could use a queue to perform a BFS on your tree:
try:
from queue import Queue # Python 3
except ImportError:
from Queue import Queue # Python 2
q = Queue() # create new queue
q.put(root) # where "root" is the root node of the tree
while not q.empty():
curr = q.get() # get next node from queue
print(curr.value) # get node's value
for child in curr.children:
q.put(child) # add each child to the queue
Note that this solution works for all trees, not just binary
EDIT: Sorry, didn't realize that you wanted all the ones in the same level to be in the same line of output. Use the other solution (or modify mine appropriately)

Python How to implement a recursive method of Binary Search Tree that returns a list that contains every node in this tree

If there's a tree example
Return form: [(depth 1, [ all items in depth 1]), (depth 2, [ all items in depth2]) ]
this method printitem_all_layers() should returns [ (1,[2] ) , ( 2,[1,3] ) ]
Though I wrote a recursive method, items_at_depth(self, d) that can return a list of items of a tree at depth d, so I know it is easy to implement the method printitem_all_layers() using items_at_depth(self, d). But it is much lesser efficient, So I'm thinking how to make printitem_all_layers() recursive itself so that I don't need another recursive method
class BinarySearchTree:
def __init__(self, root):
if root is None:
self._root = None
self._left = None
self._right = None
else:
self._root = root
self._left = BinarySearchTree(None)
self._right = BinarySearchTree(None)
def is_empty(self):
return self._root is None
def items_at_depth(self, d):
"""Return a sorted list of all items in this BST at depth <d>.
Precondition: d >= 1.
#type self: BinarySearchTree
#type d: int
#rtype: list
"""
lst = []
if d - 1 >= 1 and not self._left.is_empty():
lst.extend(self._left.items_at_depth(d-1))
if d == 1 and not self.is_empty():
lst.append(self._root)
if d - 1 >= 1 and not self._right.is_empty():
lst.extend(self._right.items_at_depth(d-1))
return lst
and following one is what I did before with no recursion
def printitem_all_layers(self):
"""Return a list of items in the tree, separated by level.
#type self: BinarySearchTree
#rtype: list[(int, list)]
"""
lst = list()
for each in range(1, self.height()+1):
lst.append(tuple((each, self.items_at_depth(each))))
return lst
What follows is an iterative version of breadth-first search, which is suitable for your problem, more efficient in terms of stack-space usage and guarantees similar runtime as a purely recursive implementation:
from collections import defaultdict
class Node:
def __init__(self, value, descendants=[]):
''' A class to represent the node of a tree '''
self.value = value
# note that descendants should be iterable for
# our breadth-first search logic to take place
# - otherwise it doesn't really matter what type
# it is.
self.descendants = descendants
def __repr__(self):
return str(self.value)
def print_layer(root):
# private queue consists of elements of the form (depth, Node)
private_queue = [(0,root)]
# instantiate a dictionary where every new value is always initialized
# to a list
depth_to_nodes_map = defaultdict(list)
# keep adding descendants of each node in your tree to your queue
# in order of visiting them, and also store each popped value in
# your defaultdict, mapping depth to a list of nodes seen. Look up
# breadth-first search if you don't understand why I'm waiting for
# the queue to exhaust itself.
while private_queue != []:
# get the first element of private_queue
current_depth, current_node = private_queue.pop(0)
depth_to_nodes_map[current_depth].append(current_node)
for child in current_node.descendants:
private_queue.append((current_depth + 1, child))
return depth_to_nodes_map.items()
An example with a reference tree:
2 -> {1 -> {0}, 3}
We would create this tree as follows:
root = Node(2, [Node(1, [Node(0)]), Node(3)])
and calling print_layers(root) gives:
[(0, [2]), (1, [1, 3]), (2, [0])]
which is exactly what you want.

Get child node if exists otherwise create in Python

I have a basic class containing two attributes 'Name' and 'Children.
class Node():
def __init__(self, name):
self.name = name
self.children = []
I have a core root node as follows:
# Create Master Root Node
root = Node('root')
How would I go about creating a function that I could pass a path to a specific node in the tree, and the function return that node.
However if that node doesn't exist it would create/append to the tree, and still return the node.
path = ['Leslie','Marie','Tori'] # simple example
def get_node_by_path(path=[])...
If a path failed before reaching the end of the path, it would automatically create the missing nodes in order to make the entire path complete.
path = ['Leslie','Marie','Tori','Kevin'] # more complex requires two nodes to be created
def get_node_by_path(path=[])...
I'd do something like this. It's a non recursive solution.
def get_node_by_path(path):
cur_node = root
for elem_name in path:
found = False
for child in cur_node.children:
if child.name == elem_name:
cur_node = child
found = True
break
if not found:
new_node = Node(elem_name)
cur_node.children.append(new_node)
cur_node = new_node
return cur_node
class Node:
def __init__(self, name):
self.name = name
self.children = []
def path_to(self, path):
if not path:
return self
head, *tail = path
for child in self.children:
if child.name == head:
return child.path_to(tail)
newborn = Node(head)
self.children.append(newborn)
return newborn.path_to(tail)
Here's a solution that recursively considers whether the first name in the list is a child of the current node.
For Python 2, head, *tail = path can be replaced with
head = path[0]
tail = path[1:]
start with the last dag object and go to the root
class Node():
def __init__(self, name = "", childern = []):
self.name = name
self.children = childern
print ("Node Name: {0} Childern Nodes {1}".format(self.name, self.children))
def get_node_by_path(path=[]):
for c,n in enumerate(reversed(path)):
if not c:
Node(name = n)
else:
Node(name = n, childern = path[-c:])
path = ['root', 'Leslie','Marie','Tori','Kevin']
get_node_by_path(path)

Categories

Resources