Вопрос о порядке рекурсивного возврата

Я работал над вопросом, который вычисляет суммы каждой ветви двоичного дерева и возвращает их в виде массива. Это в значительной степени проблема DFS, в которой вы накапливаете решения в массиве. Я просто изо всех сил пытаюсь понять, где разместить оператор return в моем коде. Я знаю правильный ответ, я просто не знаю, почему эти два фрагмента ниже не эквивалентны:

 def branchTot(root):
    soln = []
    fin  = help(root, root.value, soln)
    return fin


def help(root, sums, soln): 
    if root.left is None and root.right is None:
        soln.append(sums)
        return soln

    else:
        if root.right is not None and root.left is not None :
            help(root.left, sums + root.left.value, soln)
            help(root.right, sums + root.right.value, soln)
        elif root.right is not None:
            help(root.right, sums + root.right.value, soln)
        else:
            help(root.left, sums + root.left.value, soln)

и второе решение ниже:

 def branchTot(root):
    soln = []
    fin  = help(root, root.value, soln)
    return fin


def help(root, sums, soln): 
    if root.left is None and root.right is None:
        soln.append(sums)


    else:
        if root.right is not None and root.left is not None :
            help(root.left, sums + root.left.value, soln)
            help(root.right, sums + root.right.value, soln)
        elif root.right is not None:
            help(root.right, sums + root.right.value, soln)
        else:
            help(root.left, sums + root.left.value, soln)

    return soln

person JAVABB    schedule 18.12.2019    source источник
comment
Подсказка: либо используйте только аккумулятор и ничего не возвращайте, либо используйте только возвращаемые значения без аккумулятора. Смешение обоих только сбивает с толку.   -  person bruno desthuilliers    schedule 18.12.2019


Ответы (1)


Оба ваших решения будут работать, если есть дерево только с одним узлом (корневым узлом). Теперь поговорим о первом решении:

  • Вы возвращаете массив soln только в том случае, если оба дочерних элемента None. Теперь, если у узла есть один или несколько дочерних узлов, это условие всегда не выполняется. Следовательно, оператор return никогда не будет выполнен. И это причина, по которой первое решение возвращает None. Вот выполнение с использованием двоичного дерева поиска.

    class Tree:
        def __init__(self, val):
            self.value = val
            self.left = None
            self.right = None
    
        def add(self, val):
            if val <= self.value:
                if self.left is None:
                    self.left = Tree(val)
                else:
                    self.left.add(val)
            else:
                if self.right is None:
                    self.right = Tree(val)
                else:
                    self.right.add(val)
    
        def t_print(self):
            if self.left is not None:
                self.left.t_print()
            print self.value
            if self.right is not None:
                self.right.t_print()
    
    def help(root, sums, soln): 
       if root.left is None and root.right is None:
           soln.append(sums)
           print 'Returning value for node ' + str(root.value)
           return soln
    
       else:
            if root.right is not None and root.left is not None :
                help(root.left, sums + root.left.value, soln)
                help(root.right, sums + root.right.value, soln)
            elif root.right is not None:
                help(root.right, sums + root.right.value, soln)
            else:
                help(root.left, sums + root.left.value, soln)
        print 'Returning none for node ' + str(root.value)
        return None     # ----> This is what being executed after every recursive call finishes (for node with children)
    
    def branchTot(root):
        soln = []
        fin  = help(root, root.value, soln)
        return fin
    

Выполнение вышеуказанного даст следующий результат:

In [28]: root = Tree(9)
In [29]: root.add(5)
In [30]: root.add(3)
In [31]: root.add(2)
In [32]: root.add(10)
In [33]: root.add(13)
In [34]: root.add(11)


In [26]: branchTot(root)
Returning value for node 2
Returning none for node 3     ----> node with children
Returning none for node 5
Returning value for node 11    ------> node without children
Returning none for node 13
Returning none for node 10
Returning none for node 9

In [27]: 

Однако во втором решении вы взяли оператор return за пределы блока if, и, следовательно, оператор return выполняется, несмотря ни на что. Это возвращает последний массив.

Надеюсь это поможет.

person Shubham Bakshi    schedule 18.12.2019
comment
Я догадываюсь, почему я запутался в том, что в конечном итоге не дойду до оператора return, потому что это базовый случай, а предыдущие рекурсивные вызовы движутся вниз по дереву? - person JAVABB; 19.12.2019
comment
Я не понимаю, почему возврат None будет после каждого рекурсивного вызова, потому что каждый вызов метода должен иметь оператор возврата, а если нет, то он вернет None. И предыдущие операторы возврата перезаписываются последующими операторами возврата? - person JAVABB; 19.12.2019