10
votes

Profondeur itératif - premier trershasel d'arbre avec pré et post-visite à chaque noeud

Quelqu'un peut-il me dire à Pseudocode pour une traversée de profondeur itérative-premier arbre, où il est possible de faire des actions sur chaque noeud à la fois avant et après l'ordre?

C'est-à-dire une action avant décente dans les enfants d'un nœud, puis une action après l'ascension des enfants?

En outre, mon arbre n'est pas binaire - chaque nœud a 0..n enfants.

Fondamentalement, mon boîtier transformera une traversée récursive, où je fais la pré et les post-opérations sur le nœud actuel, de chaque côté de la récursivité dans les enfants.


5 commentaires

Une question assez générique, avec des exigences assez précises;). Qu'en est-il de simplement demander des allusions sur une traversée itérative - Pre / Post Ops va seulement s'intégrer;).


On dirait que quelqu'un peut-il me montrer comment itération de la matrice et exécuter une fonction sur chaque élément '. Quel est le problème avec itération étape par étape, comme vous l'avez décrit?


Chaque parent doit être visité avant son enfance (pré-exploitation) puis visité une fois de plus après ses enfants (après l'opération). Nous perdons ce contexte lorsque nous iTerons un tableau. Facile à faire de manière récursive, mais cela me bat comment faire cela itérativement.


Traversal d'arbre est intrinsèquement récursif. Lors de la conversion d'une approche itérative, vous aurez toujours besoin d'utiliser une pile de votre propre pour pouvoir remonter l'arbre.


Je ne sais pas si cela s'applique, mais j'ai fait une chose la même pour un projet UNI. Fondamentalement, il s'agissait d'un programme dans lequel vous pouvez entrer une formule binaire et essayera de le résoudre. Pour cela, l'arborescence de formule doit être convertie plusieurs fois, donc j'ai créé un système dans lequel les "marcheurs" sont appliqués à chaque noeud de l'arbre, de la racine vers le bas aux feuilles. Lorsque le Walker retourne quelque chose pas null, il remplacerait le nœud avec la valeur renvoyée. Voir le code source ici Github.com/narrowtux/til-Project-3/blob/master/src/main/java / de / ...


7 Réponses :


3
votes
class Node:
  def __init__( self, value ):
    self.value    = value
    self.children = []

def preprocess( node ):
  print( node.value )

def postprocess( node ):
  print( node.value )

def preorder( root ):
  # Always a flat, homogeneous list of Node instances.
  queue = [ root ]
  while len( queue ) > 0:
    a_node = queue.pop( 0 )
    preprocess( a_node )
    queue = a_node.children + queue

def postorder( root ):
  # Always a flat, homogeneous list of Node instances:
  queue   = [ root ]
  visited = set()
  while len( queue ) > 0:
    a_node = queue.pop( 0 )
    if a_node not in visited:
      visited.add( a_node )
      queue = a_node.children + [ a_node ] + queue
    else:
      # this is either a leaf or a parent whose children have all been processed
      postprocess( a_node )

1 commentaires

Est-il difficile de le faire fonctionner pour un graphique général DFS, plutôt que des arbres DFS? Cela ne fonctionnera pas tel quel, car dans un graphique général, a_node peut être dans visité sans être un parent.



1
votes

Je pense que j'ai exactement ce dont j'ai besoin en insérant une préprocession dans la fonction Postard Food de El Mariachi:

def postorder( root ):
 # Always a flat, homogeneous list of Node instances:
 queue   = [ root ]
 visited = set()
 while len( queue ) > 0:
   a_node = queue.pop( 0 )
   if a_node not in visited:
     preprocess( a_node )                  # <<<<<<<< Inserted
     visited.add( a_node )
     queue = a_node.children + [ a_node ] + queue
   else:
     # this is either a leaf or a parent whose children have all been processed
     postprocess( a_node )


0 commentaires

2
votes

0 commentaires

5
votes

Je me rends compte que ce post a plusieurs années, mais aucune des réponses ne semble répondre directement à la question, alors j'ai pensé que j'écris quelque chose d'un peu simple.

Ceci suppose un graphique indexé entier; Mais vous pouvez certainement l'adapter si nécessaire. La clé de faire des DFS itérativement et d'avoir des opérations pré-commandes / post-commandes consiste à ne pas simplement ajouter tous les enfants em> tous les em> se comporter exactement comme des DFs récursifs, qui ajoute un enfant qui ajoute un enfant -node à la pile à la fois et ne les retirez que de la pile une fois qu'elle est terminée. Je l'accomplie dans mon exemple en créant un nœud wrapper avec la liste des adjacents comme une pile. Juste omettre le chèque de cycle si vous souhaitez autoriser des cycles (il ne traverse pas de nœuds visités de toute façon, cela fonctionnera toujours) P>

class Stack(object):
    def __init__(self, l=None):
        if l is None:
            self._l = []
        else:
            self._l = l
        return

    def pop(self):
        return self._l.pop()

    def peek(self):
        return self._l[-1]

    def push(self, value):
        self._l.append(value)
        return

    def __len__(self):
        return len(self._l)

class NodeWrapper(object):
    def __init__(self, graph, v):
        self.v = v
        self.children = Stack(graph[v])
        return

def iterative_postorder(G, s):
    onstack = [False] * len(G)
    edgeto = [None] * len(G)
    visited = [False] * len(G)

    st = Stack()
    st.push(NodeWrapper(G, s))

    while len(st) > 0:
        vnode = st.peek()
        v = vnode.v
        if not onstack[v]:
            print "Starting %d" % (v)
        visited[v] = True
        onstack[v] = True
        if len(vnode.children) > 0:
            e = vnode.children.pop()
            if onstack[e]:
                cycle = [e]
                e = v
                while e != cycle[0]:
                    cycle.append(e)
                    e = edgeto[e]
                raise StandardError("cycle detected: %s, graph not acyclic" % (cycle))
            if not visited[e]:
                edgeto[e] = v
                st.push(NodeWrapper(G, e))
        else:
            vnode = st.pop()
            onstack[vnode.v] = False
            print 'Completed %d' % (vnode.v)


1 commentaires

Impressionnant. Merci d'avoir examiné mes exigences de base de Pre / Post Ops.



13
votes

Mon plan est d'utiliser deux piles. Un pour une traversée de pré-commande et un autre est pour une traversée post-commande. Maintenant, j'exécute une standard itérative DFS (Profond-première traversée), et dès que je POP code> de la pile "Pre" Je le pousse dans la pile "Post". À la fin, ma pile "post" aura un nœud enfant en haut et et une racine en bas.

public void treeSearch(Tree tree) {
    Stack<Integer> preStack = new Stack<Integer>();
    Stack<Integer> postStack = new Stack<Integer>();
    preStack.add(tree.root);
    while (!preStack.isEmpty()) {
        int currentNode = preStack.pop();
        // do pre-order visit on current node
        postStack.add(currentNode);
        int[] children = tree.getNeighbours(currentNode);
        for (int child : children) {
            preStack.add(child);
        }
    }

    while (!postStack.isEmpty()) {
        int currentNode = postStack.pop();
        // do post-order visit on current node
    }
}


1 commentaires

On dirait que cela fera d'abord les pré-visites sur tout le nœud, puis les post-visites, mais si la post-visite d'un enfant est nécessaire avant la pré-visite du sœur suivant, cela ne fonctionnera pas.



1
votes

Une simple implémentation de python avec deux visiteurs différents xxx


1 commentaires

Cela fonctionne, mais ce n'est plus itératif (comme demandé par la question de l'auteur)



1
votes

Solution itérative pour les graphiques non-arbores

Après une expérience sans succès avec différentes solutions, permettez-moi d'ajouter de pseudocode pour une solution itérative dans laquelle vous recréez essentiellement l'espace de pile d'appel de fonction (qui pourrait déborder dans une version récursive) dans une variable de pile .

Tout l'état que vous devez stocker est le numéro Vertex Number et le nombre de voisins déjà traitées . Cela peut être un tuple, une liste, un objet, quelle que soit votre langue le permet.

L'avantage de cette solution est que vous n'obtenez pas trop de pile, cela fonctionne également pour les graphiques ayant des cycles < / fort> et c'est assez robuste. Obtenir le prochain voisin est facile si vous utilisez une liste d'adjacence ou une matrice.

C'est pseudocode car il est plus facile de comprendre et vous ne copieriez pas simplement le code de cela, n'est-ce pas? < Pré> xxx


0 commentaires