3
votes

production de membres de données dans l'arborescence de recherche binaire

J'essaye d'implémenter un itérateur dans mon arbre de recherche binaire. Pour y parvenir, j'essaie de faire un parcours dans l'ordre dans l'arborescence et de produire chaque membre de données individuel. Cela me permettra de parcourir chaque élément de l'arborescence.

Ma fonction:

TypeError: iter() returned non-iterator of type 'NoneType'

Lors du test de cette fonction avec une itération telle que

for i in tree:

Je reçois cette erreur:

def __iter__(self):
    """
    in-order traversal of a binary search tree
    """
    if self.root is not None:
        self.check(self.root)

def check(self, cur_node):
    if cur_node is not None:
        self.check(cur_node.left)
        yield cur_node.data #if I were to print this data member, it would be fine
        self.check(cur_node.right)


0 commentaires

3 Réponses :


2
votes

L'indice est

iter () a renvoyé ....

Vous devez donc renvoyer un itérateur. Votre classe est un itérateur, donc retournez self

class Tree:
    def __init__(...): ...

    def __iter__(self):
        return self

    def __next__(self):
        if self.left is not None:
            yield from self.left
        yield self.data
        if self.right is not None:    
            yield from self.right 

Vous devriez probablement implémenter également __next__ pour obtenir réellement la valeur.

La solution pourrait donc ressembler à

def __iter__(self):
    """
    in-order traversal of a binary search tree
    """
    if self.root is not None:
        self.check(self.root)
    return self

Vous utilisez ici yield from pour déléguer aux nœuds enfants. Voir https: / /docs.python.org/3/whatsnew/3.3.html#pep-380-syntax-for-delegating-to-a-subgenerator

Vous avez en fait besoin de trois instructions yield, car vous devez parcourir à la fois les enfants gauche et droit, ainsi que produire la valeur du nœud actuel.


3 commentaires

Changer l'état interne d'une opération d'énumération est une mauvaise idée ... et si plusieurs utilisateurs veulent itérer le même arbre en même temps?


Je traverse une boucle infinie? J'ai fait un léger ajustement à votre code en éditant cur_node.left en self.cur_node.left. Êtes-vous sûr que nous avons besoin de 3 déclarations de rendement?


J'ai mis à jour ceci pour résoudre le problème de multi-threading et utiliser les attributs de classe.



5
votes

Pour implémenter un générateur récursif, vous ne pouvez pas simplement "appeler" vous-même, vous devez extraire des éléments et les produire.

Python a une syntaxe spéciale pour cela:

class Node:
    def __init__(self, data, left, right):
        self.data = data
        self.left = left
        self.right = right

    def __iter__(self):
        if self.left:
            yield from self.left
        yield self.data
        if self.right:
            yield from self.right

expr est itérable, et il peut être vu comme un raccourci pour

 for x in expr:
     yield x

En utilisant ceci, vous pouvez implémenter la traversée dans l'ordre d'un arbre avec quelque chose comme:

 yield from expr


0 commentaires

2
votes

Vous voulez généralement que votre itérateur soit une entité distincte de votre structure de données, afin que vous puissiez avoir plusieurs itérateurs sur vos données, et ainsi vous pouvez itérer sur vos données plusieurs fois. Ci-dessous, je montre comment mettre en œuvre un algorithme DFS simple pour une classe BST de base.

class Node:
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
    def __iter__(self):
        return BSTIterator(self)

class BSTIterator:
    def __init__(self, root):
        self.stack = []
        curr = root
        while curr:
            self.stack.append(curr)
            curr = curr.left
    def __next__(self):
        if not self.stack:
            raise StopIteration()
        node = self.stack.pop()
        val = node.val
        node = node.right
        while node:
            self.stack.append(node)
            node = node.left
        return val
    def __iter__(self):
        return self

root = Node(5, Node(3, Node(1), Node(4)), Node(10, (Node(6, None, Node(7)))))
list(root)
# [1, 3, 4, 5, 6, 7, 10]


0 commentaires