Рекурсивная функция python возвращает узлы без дочерних элементов в дереве

     0
   /   \
  1     2
 / \   /|\
3   4 5 6 7

Я пытаюсь вернуть узлы без дочерних элементов (3,4,5,6,7) из объекта с помощью рекурсивной функции.

Он работает с глобальной переменной и этой функцией:

def find(self, nodes):
    if not hasattr(self, 'children'): 
        nodes.append(self)
    else:
        for i in self.children:
            i.find(nodes)


nodes = []
node.find(nodes) # can be any node (0,1,2,3,4, etc.)
print(nodes)

Но я бы хотел использовать return в своей функции. Я пробовал примерно так:

   def find2(self):
    if not hasattr(self, 'children'): 
        return self
    else:
        for i in self.children:
            return i.find2()


nodes = root.find2()
print(nodes)

Но у меня получается только 1 узел. Я также пробовал передать массив, как в этом посте: PYTHON Возвращает список из рекурсивной функции. Но я не получаю желаемого результата, потому что древовидная структура (я полагаю) ...

Я застрял, ты можешь мне помочь? Как «вернуть результат каждой итерации рекурсивной функции в переменную»? Спасибо

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
1 247
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Обратите внимание, что в вашем базовом случае вы возвращаете один узел. Затем этот узел распространяется обратно в рекурсии и в конечном итоге возвращается. Т.е. узел, который вам возвращается, является первым без дочерних узлов, с которыми вы столкнулись. Есть несколько способов решить эту проблему (например, путем возврата и объединения списков), но я думаю, что естественный способ сделать это - сделать вашу функцию генератором. Для этого просто замените return на yield. Затем возвращаемое значение функции функционирует как итератор, при этом каждая итерация дает следующее значение, которое будет «возвращено» при выполнении, пока функция не завершится.

Вы не предоставили мне достаточно кода, чтобы создать работоспособный и тестируемый пример, но вот мое предположение о том, что вы ищете:

def find(self):
    if not hasattr(self, 'children'):
        return [self]

    nodes = []

    for child in self.children:
        return nodes.extend(child.find())

    return nodes

# ...

nodes = root.find()
print(nodes)
Ответ принят как подходящий

Это пример ввода:

     0
   /   \
  1     2
 / \   /|\
3   4 5 6 7

Подумайте, что вы хотите, чтобы (рекурсивная) функция возвращала для каждого из узлов:

  • при вызове в корне (0) он должен возвращать полный результат (3, 4, 5, 6, 7)
  • при вызове на листовом узле (например, 5) он должен вернуть этот узел (5)
  • для любого другого узла (например, 1) он работает так, как если бы он был корневым узлом меньшего дерева

Таким образом, иногда он возвращает один результат, а иногда и несколько. Ошибка в вашем коде здесь, потому что функция заканчивается при первом возврате, она не возвращает много:

    for i in self.children:
        return i.find2()

Есть два решения:

  • сделать функцию генератора, или
  • создать функцию, которая возвращает список (пусть она всегда будет возвращать список, даже если в нем всего один элемент!)

Итак, вариант 1:

def find(self):
    if not hasattr(self, 'children'): 
        yield self
    else:
        for child in self.children:
            yield from child.find()

вариант 2:

def find(self):
    if not hasattr(self, 'children'): 
        return [self]
    else:
        rtn = []
        for child in self.children:
            for result in child.find():
                rtn.append(result)
        return rtn

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

def find_leaves(self):
    if self.children:
        for child in self.children:
            yield from child.find_leaves()
    else:
        yield self

Спасибо за очень хороший ответ. Я не знал ни о yield (и генераторах), ни о [self]. Сейчас я собираюсь прочитать документацию о них, чтобы понять, как они работают. Ты работает!

emile 21.05.2018 23:15

@cdlane for result in child.find() распаковывает список и затем добавляет каждый элемент в rtn. Не тестировал (тестировал только find_leaves), но думаю, должно работать ...

zvone 21.05.2018 23:50

Вы правы, вложенного цикла я не видел. Хотя я думаю, что .extend() имеет больше смысла, чем целый дополнительный цикл!

cdlane 22.05.2018 00:04

@cdlane Да, продлить было бы лучше, но я подумал, что это будет легче понять ...

zvone 22.05.2018 00:16

Другие вопросы по теме