2015-04-18 1 views
3

Im en utilisant un arbre binaire décrit dans ce livre problem solving with algorithms and data structurespython retournant une liste à partir d'une méthode récursive

class BinaryTree: 
    def __init__(self,rootObj): 
     self.key = rootObj 
     self.leftChild = None 
     self.rightChild = None 

Il existe déjà une méthode de pré-commande défini traversal comme suit.

def preorder(tree): 
    if tree: 
     print(tree.self.key) 
     preorder(tree.getLeftChild()) 
     preorder(tree.getRightChild()) 

Je veux juste ajouter une valeur de retour de la liste des nœuds visités. Donc, je peux faire quelque chose comme

for i in preorder(tree): 
    etc... 

J'ai du mal à retourner une liste d'une méthode récursive. La récursion arrête dès qu'elle touche le « retour » que j'ai essayé d'utiliser les variations

return [tree.self.key] + preorder() 

Ou

yield ... 

Toutes les idées?

+0

Quelle erreur obtenez-vous? Est-ce quelque chose à propos de la concaténation de None et de la liste? – YXD

+1

1). Il semble que 'preorder()' soit une fonction d'assistance et non une méthode de la classe 'BinaryTree', donc l'appeler une méthode est un peu confus. 2). Si 'tree' est une instance de' BinaryTree', alors 'tree.self.key' est faux. 3). En Python, vous avez rarement besoin de méthodes getter (ou setter), vous accédez directement aux attributs. Par exemple, 'preorder (tree.leftChild)'. –

Répondre

2

Vous avez à fait retour une valeur de la fonction récursive (actuellement, il est juste l'impression des valeurs). Et vous devez construire la liste que vous allez, et nettoyer peut-être le code un peu - quelque chose comme ceci:

def preorder(tree): 
    if not tree: 
     return [] 
    # optionally, you can print the key in this line: print(self.key) 
    return [tree.key] + preorder(tree.leftChild) + preorder(tree.rightChild) 
+0

Merci beaucoup pour les réponses. J'utilise python v3.4, je n'ai pas fonctionné, je suis encore un peu perdu entre les itérateurs et les générateurs ... De toute façon, cette liste vide 'sinon' retourne le problème que j'avais avec 'can not + NoneType ' – Damo

1

Vous pouvez ajouter deuxième argument à la fonction preorder, quelque chose comme

def preorder(tree, visnodes): 
    if tree: 
     visnodes.append(tree.self.key) 
     print(tree.self.key) 
     preorder(tree.getLeftChild(), visnodes) 
     preorder(tree.getRightChild(), visnodes) 

... 
vn = [] 
preorder(tree, vn) 
5

Êtes-vous sûr que vous voulez tree.self.key et pas simplement tree.key lorsque vous imprimez?

Sinon, une solution avec yield from (Python 3.3+):

def preorder(tree): 
    if tree: 
     yield tree 
     yield from preorder(tree.getLeftChild()) 
     yield from preorder(tree.getRightChild()) 

Ou avec de simples yield:

def preorder(tree): 
    if tree: 
     yield tree 
     for e in preorder(tree.getLeftChild()): 
      yield e 
     for e in preorder(tree.getRightChild()): 
      yield e 

Notez que l'utilisation yield ou yield from transforme la fonction en generator function; en particulier, si vous voulez une liste réelle (pour l'indexation, le découpage ou l'affichage par exemple), vous devrez le créer explicitement: list(preorder(tree)).

Si vous avez un nombre variable d'enfants, il est facile d'adapter:

def preorder(tree): 
    if tree: 
     yield tree 
     for child in tree.children: 
      yield from preorder(child) 
+0

Puisque vous accédez directement à 'tree.key', vous pouvez également utiliser' preorder (tree.leftChild) 'et' preorder (tree.getRightChild) '. De plus, vous devriez mentionner que pour obtenir la liste des nœuds de cette façon, vous devez faire quelque chose comme 'nodes = list (preorder (tree))' ou 'nodes = [node for node en précommande (tree)]'. – martineau

+0

Merci pour la suggestion sur la liste. En ce qui concerne votre autre point, j'accède à 'tree.key' parce que je ne veux pas deviner s'il y a une méthode' getKey() 'mais je crois que' tree.self.key' de l'OP pourrait être défectueux. Il y a déjà un commentaire sur le manque de besoin de getters et setters en python mais ici c'est vraiment à côté de ça. –

+0

J'ai mentionné comment montrer une liste en raison du titre de la question. Notez également que cela devrait être «print tree.key», pas «yield tree.key» - l'OP veut une liste de nœuds, pas un avec un mélange de nœuds et de clés. – martineau

0

Vous pouvez simplement retourner une liste concaténée pour chaque appel récursif, qui combine la clé actuelle, le sous-arbre gauche et le sous-arbre droit :

def preorder(tree): 
     if tree: 
      return ([tree.key] + preorder(tree.getLeftChild()) + 
        preorder(tree.getRightChild())) 
     return [] 

Pour un arbre n-aire:

def preorder(tree): 
    if tree: 
     lst = [tree.key] 
     for child in tree.children: 
      lst.extend(preorder(child)) 
     return lst 
    return [] 
+0

Merci pour votre réponse fonctionne parfaitement. Juste errant si ce n'est pas un arbre binaire comment puis-je faire une boucle sur tous les enfants, par exemple. def précommande (arbre): si arbre: return [tree.key] + [précommande (enfant, msg) pour enfant dans tree.children] – Damo

+0

@DamianSavage Oui, mais l'utilisation de la liste de compréhension conduirait à une liste de listes , puisque chaque appel '' 'preorder''' renvoie une liste. Vous pouvez utiliser une boucle pour y parvenir. Je vais mettre à jour ma réponse avec ça. –

+0

c'est exactement ce que je cherchais, merci :) – Damo