Python recursive function to create generic tree [duplicate] - python-3.x

This question already has answers here:
Why does my recursive function return None?
(4 answers)
Closed 7 months ago.
I'm trying to create a tree with n children for each node.
Problem is, when I try to implement this using a recursive function, I ends up with multiple recursive calls so I can't have a single return statement, hence having None as a final result.
Here is my piece of code :
def recursive_func(tree, n):
if n == 0:
return tree
else:
permutations = get_permutations()
for permutation in permutations:
child_tree = recursive_func(Tree(permutation), n-1)
tree.addChild(child_tree)
get_permutations() gives a list of child trees to create. I also have a Tree class with a node value and a list of children.
Here is the Tree class:
class Tree:
def __init__(self, result):
self.node = node
self.children = []
def addChild(self, tree):
self.children.append(tree)
This is probably a rookie error in the design of my problem, but I would be glad to get some help.

TLDR: Since you use the result of recursive_func, it should always return its tree.
The recursive_func has three important points for this problem:
def recursive_func(tree, n):
if n == 0:
return tree # 1.
else:
permutations = get_permutations()
for permutation in permutations:
child_tree = recursive_func(Tree(permutation), n-1) # 2.
tree.addChild(child_tree)
# 3.
Now, 1. defines that the function sometimes returns a Tree. This matches 2. which always expects the function to return a Tree. However, both conflict with 3., which implicitly returns None when the second branch is done.
Since the first branch is empty aside from the return, both 1. and 3. can be collapsed to one path that always returns a Tree.
def recursive_func(tree, n):
if n > 0:
permutations = get_permutations()
for permutation in permutations:
child_tree = recursive_func(Tree(permutation), n-1)
tree.addChild(child_tree)
return tree

Related

Interviewbit - Merge k sorted linked lists: heappop returns max element instead of min

I'm solving the Interviewbit code challenge Merge K Sorted Lists:
Merge k sorted linked lists and return it as one sorted list.
Example :
1 -> 10 -> 20
4 -> 11 -> 13
3 -> 8 -> 9
will result in
1 -> 3 -> 4 -> 8 -> 9 -> 10 -> 11 -> 13 -> 20
The Python template code is:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# #param A : list of linked list
# #return the head node in the linked list
def mergeKLists(self, A):
pass
Here's my python 3 solution for the same:
from heapq import heapify, heappop, heappush
class Solution:
# #param A : list of linked list
# #return the head node in the linked list
def mergeKLists(self, A):
minheap = [x for x in A]
# print(minheap)
# heapify(minheap)
# print(minheap)
head = tail = None
# print(minheap)
while minheap:
# print(minheap)
heapify(minheap)
print([x.val for x in minheap])
minimum = heappop(minheap)
print(minimum.val)
if head is None:
head = minimum
tail = minimum
else:
tail.next = minimum
tail = minimum
if minimum.next:
heappush(minheap, minimum.next)
return head
With the print commands that are uncommented, you'll notice that in the intermediate runs of the while loop, heappop returns the largest element, as if we were dealing with a max heap, which we're not!
That's the place where the answer is going wrong as far as I can see. Can anyone suggest the reason for why heappop is working like this? And how that can be corrected?
When I run your code locally with sample data, I get an error on:
heapify(minheap)
TypeError: < not supported between instances of ListNode and ListNode
This is expected. The template definition of ListNode shows no support for making comparisons, and a heapify function will need to compare the items in the given list.
As the class ListNode is already defined by the code-challenge framework, it is probably better not to try to make that class comparable.
I would propose to put tuples on the heap which have list node instances as members, but have their val attribute value come first, followed by the number of the list (in A) they originate from. As third tuple member you'd finally have the node itself. This way comparisons will work, since tuples are comparable when their members are. And since the second tuple member will be a tie-breaker when the first member value is the same, the third tuple member (the list node instance) will never be subject to a comparison.
Unrelated to your question, but you should only heapify once, not in each iteration of the loop. The actions on the heap (heappush, heappop) maintain the heap property, so there is no need for calling heapify a second time. If you do it in each iteration, you actually destroy the efficiency benefit you would get from using a heap.
Here is your code updated with that change:
from heapq import heapify, heappop, heappush
class Solution:
def mergeKLists(self, A):
# place comparable tuples in the heap
minheap = [(node.val, i, node) for i, node in enumerate(A)]
heapify(minheap) # call only once
head = tail = None
while minheap:
# extract the tuple information we need
_, i, minimum = heappop(minheap)
if head is None:
head = minimum
tail = minimum
else:
tail.next = minimum
tail = minimum
minimum = minimum.next
if minimum:
# push a tuple, using same list index
heappush(minheap, (minimum.val, i, minimum))
return head

saving the result of the recursion iterations

This is a standart permutation function. Im tring to return the list of the lists of the permutations)
Could you help me with storaging the result of the recursion iterations? for example this code returns nonsense. It would be perfect if there was no global variable and rezulting list was inside the func
Thanks!
'''
z=[]
def func(N,M=-1,pref=None):
global z
if M == -1:
M = N
pref = pref or []
if M==0:
z.append(pref)
print(pref)
for i in range(N):
if i not in pref:
pref.append(i)
func(N,M-1,pref)
pref.pop()
func(3)
print(z)
'''
You are passing a list (pref variable in for loop) reference to your function and you are removing a single item from that and that's why you are ending with an empty list z.
Create a new list or copy the list before passing it to the function to avoid this situation.
z = []
def func(N, M=-1, pref=None):
global z
if M == -1:
M = N
pref = pref or []
if M == 0:
z.append(pref)
print(pref)
for i in range(N):
if i not in pref:
pref.append(i)
func(N, M - 1, pref[:])
pref.pop()
func(3)
print(z)
For better understand please read this one. List changes unexpectedly after assignment. How do I clone or copy it to prevent this?
If you want to have some kind of accumulator you must pass it to the recursion function, beware it could be a little nightmare.

Generate all valid binary search trees given a list of values

Hello I am trying to solve the following question on leetcode, [https://leetcode.com/problems/unique-binary-search-trees-ii/].
I know I have access to the solution but I tried solving the problem my way and I am stuck and I would like to know if it is solvable the way I am doing it.
Here is the code:
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def generateTrees(myrange, n, res = None):
if res == None:
res = []
if myrange == []:
res.append(None)
return
for root in myrange:
res.append(root)
generateTrees([i for i in range(root) if i in set(myrange)], n, res) #leftchild
generateTrees([i for i in range(root+1, n) if i in set(myrange)], n, res) #rightchild
return res
Initially myrange is just the list containing the node values, and n is the length of myrange.
The way I am doing it is a sort of DFS where I loop over the nodes making each one of them the root once and then I do the same for the left and right subtrees to get all combinations. But the problem I am facing is I can't figure out how to manage res to remove elements from it as my recursion backtracks (and make it so res only contains valid bst's and then put those in some other list that will be my actual result).
I would like some pointers or even just comments on if you think my approach is valid or bad ..etc.
Issues:
As you mention, your code only creates one list to which it keeps appending.
Even if you would fix that, the lists would never come out in the BFS kind of order, which is what the question's example seems to suggest.
For a chosen root, you need to list all combinations of its possible left subtrees with its possible right subtrees -- a Cartesian product if you wish. This logic is missing in your code.
I would:
not pass res as argument to the recursive function. Just return it, and let the caller deal with it.
not use ranges, as that only seems to complicate things. The if i in set(myrange) seems like an inefficient way to get the overlap between two ranges. I would instead pass the two extremes of the range as separate arguments.
use the TreeNode class to actually create the trees, and deal with generating the required output format later.
For generating the output format you need a BFS walk through the tree, and this could be implemented as a method on TreeNode.
Here is what I think would work:
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def breadth_first(self):
lst = []
todo = [self]
while any(todo):
node = todo.pop(0)
lst.append(node.val if node else None)
if node:
todo.append(node.left)
todo.append(node.right)
return lst
def generateTrees(n):
def recur(start, end): # end is not included
if start >= end:
return [None]
trees = []
for root in range(start, end):
lefts = recur(start, root)
rights = recur(root+1, end)
# Cartesian product:
for left in lefts:
for right in rights:
# Start with a new tree, and append to result
tree = TreeNode(root)
tree.left = left
tree.right = right
trees.append(tree)
return trees
return recur(1, n+1)
# Create the trees as a list of TreeNode instances:
trees = generateTrees(3)
# Convert to a list of lists
print([tree.breadth_first() for tree in trees])

Breadth First Tree Traversal using Generators in Python

I am studying how to use Generators in Python in David Beazly's excellent Python Cookbook text. The following code recipe defines Depth First Tree Traversal using generators very elegantly:
# example.py
#
# Example of depth-first search using a generator
class Node:
def __init__(self, value):
self._value = value
self._children = []
def __repr__(self):
return 'Node({!r})'.format(self._value)
def add_child(self, node):
self._children.append(node)
def __iter__(self):
return iter(self._children)
def depth_first(self):
yield self
for c in self:
yield from c.depth_first()
# Example
if __name__ == '__main__':
root = Node(0)
child1 = Node(1)
child2 = Node(2)
root.add_child(child1)
root.add_child(child2)
child1.add_child(Node(3))
child1.add_child(Node(4))
child2.add_child(Node(5))
for ch in root.depth_first():
print(ch)
# Outputs: Node(0), Node(1), Node(3), Node(4), Node(2), Node(5)
I am trying to come up with an equally elegant method
def breadth_first(self):
pass
I am deliberately not posting the crazy stuff that I have been trying since everything that I have tried requires maintaining 'state' within it. I don't want to use the traditional queue based solutions. The whole point of this academic exercise is to learn how generators behave in depth. Therefore, I want to create a parallel 'breadth_first' method using generators for the tree above.
Any pointers/solutions are welcome.
You can't use recursion (stack) for bfs without some serious hacks, but a queue would work:
def breadth_first(self):
q = [self]
while q:
n = q.pop(0)
yield n
for c in n._children:
q.append(c)
I find it both useful and elegant generating the whole breadth, one level at a time. Python 3 generator below:
def get_level(t: Node) -> Iterable[List]:
curr_level = [t] if t else []
while len(curr_level) > 0:
yield [node._value for node in curr_level]
curr_level = [child for parent in curr_level
for child in parent._children
if child]
It would be easy if itertools had:
# zip_chain('ABCD', 'xy') --> A x B y C D
It's almost a itertools.chain(itertools.zip_longest()), but not quite.
Anyway, zip_chain allows:
def bf(self):
yield self
yield from zip_chain(*map(Node.bf, self.children))
It doesn't create a whole row at a time either, I think,
The depth first solution you implement is essentially "iterate then recurse"
def depth_first(self):
yield self
for c in self.children:
yield from c.depth_first():
Inspired by this blog post the activestate post it references, you obtain a breadth first search as "recurse then iterate":
def breadth_first(self):
yield self
for c in self.breadth_first():
if not c.children:
return # stop the recursion as soon as we hit a leaf
yield from c.children
Edit: it turns out that the linked blog says "Termination check is absent", replaced with an activestate link, which I've adapted to use yield from above.

Iteration to Recurssion

so myListToPyList(lst): takes lst, a MyList object and returns a Python list containing the same data
def myListToPyList(lst):
return myListToPyListRec(lst.head)
here's my helper function:
def myListToPyListRec(node):
if node == None:
return
else:
st1 = []
st1.append(node.data)
myListToPyListRec(node.next)
return st1
it's not working correctly.
Now here is my iterative solution that works correctly:
def myListToPyList(lst):
"""
Takes a list and returns a python list containing
the same data
param; lst
return; list
"""
st1 = []
curr = lst.head
while curr != None:
st1.append(curr.data)
curr = curr.next
return st1
Your current recursive code doesn't work because each time it gets called, it creates a new empty list, adds a single value to the list, then recurses (without passing the list along). This means that when the last item in the link list is being processed, the call stack will have N one-element Python lists (where N is the number of list nodes).
Instead, you should create the list just once, in your non-recursive wrapper function. Then pass it along through all of the recursion:
def myListToPyList(lst):
result_list = [] # create just one Python list object
myListToPyListRec(lst.head, result_list) # pass it to the recursive function
return result_list # return it after it has been filled
def myListToPyListRec(node, lst):
if node is not None # the base case is to do nothing (tested in reverse)
lst.append(node.data) # if node exists, append its data to lst
myListToPyListRec(node.next, lst) # then recurse on the next node
Because Python lists are mutable, we don't need to return anything in our recursive calls (None will be returned by default, but we ignore that). The list referred to by result_list in myListToPyList is the same object referred to by lst in each of the recursive calls to myListToPyListRec. As long as the recursive function mutates the object in place (e.g. with append) rather than rebinding it, they'll all see the same thing.
Note that recursion is going to be less eficient in Python than iteration, since function calls have more overhead than just updating a couple variables.
A while loop is equivalent to tail recursion, and vice versa. (One reason Python does not have automatic tail-call elimination is that the 'vice versa' part is rather easy.) The tail recursion requires that you add an accumulator parameter to be returned in the base case. Although I do not have a linked list for testing, I believe the following should work. (If not, this is close.) Python's default arguments make the helper either easier or unnecessary.
def myListToPyListRec(node, py_list=[]):
if node
py_list.append(node.data)
return myListToPyListRec(node.next, py_list)
else:
return py_list

Resources