web-dev-qa-db-fra.com

Traversée de l'ordre des arbres binaires sans récursivité

Quel est l'algorithme pour effectuer une traversée d'une commande binaire d'un arbre binaireSANSen utilisant la récursivité?

52
Patrik Svensson

Voici un lien qui fournit deux autres solutions sans utiliser aucun indicateur visité.

https://leetcode.com/problems/binary-tree-postorder-traversal/

Ceci est évidemment une solution basée sur la pile en raison de l’absence de pointeur parent dans l’arbre. (Nous n'aurions pas besoin d'une pile s'il y a un pointeur parent).

Nous voudrions d'abord placer le noeud racine dans la pile. Tant que la pile n'est pas vide, nous continuons à pousser l'enfant gauche du nœud à partir du haut de la pile. Si l'enfant de gauche n'existe pas, nous poussons son enfant de droite. S'il s'agit d'un nœud feuille, nous le traitons et le retirons de la pile.

Nous utilisons également une variable pour suivre un nœud précédemment traversé. Le but est de déterminer si le parcours descend/monte dans l’arbre, et nous pouvons également savoir s’il monte de gauche à droite.

Si nous montons l’arbre par la gauche, nous ne voudrions plus pousser son enfant de gauche dans la pile et nous devrions continuer à monter dans l’arbre si son enfant de droite existe. Si nous montons l’arbre de la droite, nous devrions le traiter et le retirer de la pile.

Nous traiterions le noeud et le retirerions de la pile dans les 3 cas suivants:

  1. Le nœud est un nœud feuille (pas d'enfants)
  2. Nous traversons simplement l'arbre de la gauche et il n'y a pas d'enfant de droite.
  3. Nous venons de traverser l'arbre par la droite.
25
1337c0d3r

Voici la version avec une pile et sans indicateur visité:

private void postorder(Node head) {
  if (head == null) {
    return;
  }
  LinkedList<Node> stack = new LinkedList<Node>();
  stack.Push(head);

  while (!stack.isEmpty()) {
    Node next = stack.peek();

    boolean finishedSubtrees = (next.right == head || next.left == head);
    boolean isLeaf = (next.left == null && next.right == null);
    if (finishedSubtrees || isLeaf) {
      stack.pop();
      System.out.println(next.value);
      head = next;
    }
    else {
      if (next.right != null) {
        stack.Push(next.right);
      }
      if (next.left != null) {
        stack.Push(next.left);
      }
    }
  }
}
33
tcb

Voici un exemple de wikipedia :

nonRecursivePostorder(rootNode)
  nodeStack.Push(rootNode)
  while (! nodeStack.empty())
    currNode = nodeStack.peek()
    if ((currNode.left != null) and (currNode.left.visited == false))
      nodeStack.Push(currNode.left)
    else 
      if ((currNode.right != null) and (currNode.right.visited == false))
        nodeStack.Push(currNode.right)
      else
        print currNode.value
        currNode.visited := true
        nodeStack.pop()
27
Nader Shirazie

Voici une solution en C++ qui ne nécessite aucun stockage pour la tenue des livres dans l’arborescence.
Au lieu de cela, il utilise deux piles. Un pour nous aider à parcourir et un autre pour stocker les nœuds afin que nous puissions en faire un post-parcours.

std::stack<Node*> leftStack;
std::stack<Node*> rightStack;

Node* currentNode = m_root;
while( !leftStack.empty() || currentNode != NULL )
{
    if( currentNode )
    {
        leftStack.Push( currentNode );
        currentNode = currentNode->m_left;
    }
    else
    {
        currentNode = leftStack.top();
        leftStack.pop();

        rightStack.Push( currentNode );
        currentNode = currentNode->m_right;
    }
}

while( !rightStack.empty() )
{
    currentNode = rightStack.top();
    rightStack.pop();

    std::cout << currentNode->m_value;
    std::cout << "\n";
}
2
Jens Agby

C’est l’approche que j’utilise pour le parcours itératif, post-ordre. J'aime cette approche parce que:

  1. Il ne gère qu'une seule transition par cycle, donc il est facile à suivre.
  2. Une solution similaire fonctionne pour les traversées dans l'ordre et dans l'ordre

Code:

enum State {LEFT, RIGHT, UP, CURR}

public void iterativePostOrder(Node root) {
  Deque<Node> parents = new ArrayDeque<>();
  Node   curr = root;
  State state = State.LEFT;

  while(!(curr == root && state == State.UP)) {
    switch(state) {
      case LEFT:
        if(curr.left != null) {
          parents.Push(curr);
          curr = curr.left;
        } else {
          state = RIGHT;
        }
        break;
      case RIGHT:
        if(curr.right != null) {
          parents.Push(curr);
          curr = curr.right;
          state = LEFT;
        } else {
          state = CURR;
        }
        break; 
      case CURR:
        System.out.println(curr);
        state = UP;
        break;
      case UP: 
        Node child = curr;
        curr = parents.pop();
        state = child == curr.left ? RIGHT : CURR;
        break;
      default:
        throw new IllegalStateException();
    }
  }
}

Explication:

Vous pouvez penser aux étapes comme ceci:

  1. Essayez LEFT
    • si le noeud gauche existe: essayez à nouveau GAUCHE
    • si le noeud de gauche n'existe pas: essayez à DROITE
  2. Essayez DROITE
    • Si un noeud de droite existe: essayez à gauche à partir de là
    • Si aucun droit n'existe, vous êtes sur une feuille: essayez CURR
  3. Essayez CURR
    • Imprimer le noeud actuel
    • Tous les noeuds ci-dessous ont été exécutés (post-commande): Try UP
  4. Essaies
    • Si le noeud est la racine, il n'y a pas d'UP, alors EXIT
    • Si vous venez de gauche, essayez à droite
    • Si vous venez de droite, essayez CURR
2
bcorso
import Java.util.Stack;

public class IterativePostOrderTraversal extends BinaryTree {

    public static void iterativePostOrderTraversal(Node root){
        Node cur = root;
        Node pre = root;
        Stack<Node> s = new Stack<Node>();
        if(root!=null)
            s.Push(root);
        System.out.println("sysout"+s.isEmpty());
        while(!s.isEmpty()){
            cur = s.peek();
            if(cur==pre||cur==pre.left ||cur==pre.right){// we are traversing down the tree
                if(cur.left!=null){
                    s.Push(cur.left);
                }
                else if(cur.right!=null){
                    s.Push(cur.right);
                }
                if(cur.left==null && cur.right==null){
                    System.out.println(s.pop().data);
                }
            }else if(pre==cur.left){// we are traversing up the tree from the left
                if(cur.right!=null){
                    s.Push(cur.right);
                }else if(cur.right==null){
                    System.out.println(s.pop().data);
                }
            }else if(pre==cur.right){// we are traversing up the tree from the right
                System.out.println(s.pop().data);
            }
            pre=cur;
        }
    }

    public static void main(String args[]){
        BinaryTree bt = new BinaryTree();
        Node root = bt.generateTree();
        iterativePostOrderTraversal(root);
    }


}
2
Anupam Gupta

// la version Java avec flag 

public static <T> void printWithFlag(TreeNode<T> root){
    if(null == root) return;

    Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
    stack.add(root);

    while(stack.size() > 0){
        if(stack.peek().isVisit()){
            System.out.print(stack.pop().getValue() + "  ");
        }else{

            TreeNode<T> tempNode = stack.peek();
            if(tempNode.getRight()!=null){
                stack.add(tempNode.getRight());
            }

            if(tempNode.getLeft() != null){
                stack.add(tempNode.getLeft());
            }



            tempNode.setVisit(true);


        }
    }
}
2
Jiaji Li

Veuillez voir cette implémentation Java complète. Copiez simplement le code et collez-le dans votre compilateur. Cela fonctionnera bien. 

import Java.util.LinkedList;
import Java.util.Queue;
import Java.util.Stack;

class Node
{
    Node left;
    String data;
    Node right;

    Node(Node left, String data, Node right)
    {
        this.left = left;
        this.right = right;
        this.data = data;
    }

    public String getData()
    {
        return data;
    }
}

class Tree
{
    Node node;

    //insert
    public void insert(String data)
    {
        if(node == null)
            node = new Node(null,data,null);
        else
        {
            Queue<Node> q = new LinkedList<Node>();
            q.add(node);

            while(q.peek() != null)
            {
                Node temp = q.remove();
                if(temp.left == null)
                {
                    temp.left = new Node(null,data,null);
                    break;
                }
                else
                {
                    q.add(temp.left);
                }

                if(temp.right == null)
                {
                    temp.right = new Node(null,data,null);
                    break;
                }
                else
                {
                    q.add(temp.right);
                }
            }
        }
    }

    public void postorder(Node node)
    {
        if(node == null)
            return;
        postorder(node.left);
        postorder(node.right);
        System.out.print(node.getData()+" --> ");
    }

    public void iterative(Node node)
    {
        Stack<Node> s = new Stack<Node>();
        while(true)
        {
            while(node != null)
            {
                s.Push(node);
                node = node.left;
            }



            if(s.peek().right == null)
            {
                node = s.pop();
                System.out.print(node.getData()+" --> ");
                if(node == s.peek().right)
                {
                    System.out.print(s.peek().getData()+" --> ");
                    s.pop();
                }
            }

            if(s.isEmpty())
                break;

            if(s.peek() != null)
            {
                node = s.peek().right;
            }
            else
            {
                node = null;
            }
        }
    }
}

class Main
{
    public static void main(String[] args) 
    {
        Tree t = new Tree();
        t.insert("A");
        t.insert("B");
        t.insert("C");
        t.insert("D");
        t.insert("E");

        t.postorder(t.node);
        System.out.println();

        t.iterative(t.node);
        System.out.println();
    }
}
0
avishek gurung

Voici une version courte (le marcheur mesure 3 lignes) que j'avais besoin d'écrire en Python pour un arbre général Bien sûr, cela fonctionne aussi pour un arbre binaire plus limité. Tree est un tuple du noeud et de la liste des enfants. Il n'a qu'une pile. Exemple d'utilisation montré.

def postorder(tree):
    def do_something(x):  # Your function here
        print(x),
    def walk_helper(root_node, calls_to_perform):
        calls_to_perform.append(partial(do_something, root_node[0]))
        for child in root_node[1]:
            calls_to_perform.append(partial(walk_helper, child, calls_to_perform))
    calls_to_perform = []
    calls_to_perform.append(partial(walk_helper, tree, calls_to_perform))
    while calls_to_perform:
        calls_to_perform.pop()()
postorder(('a', [('b', [('c', []), ('d', [])])]))

ré c b une

0
DaveSawyer

Voici une version de Python aussi :: 

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

def postOrderIterative(root):

    if root is None :
        return

    s1 = []
    s2 = []
    s1.append(root)

    while(len(s1)>0):
        node = s1.pop()
        s2.append(node)

        if(node.left!=None):
            s1.append(node.left)

        if(node.right!=None):
            s1.append(node.right)

    while(len(s2)>0):
        node = s2.pop()
        print(node.data)

root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
root.right.left = Node(6)
root.right.right = Node(7)
postOrderIterative(root)

Voici la sortie :: 

 enter image description here

0
Akash Kandpal

La logique de Post Order Traversal sans utiliser la récursivité

Dans Postorder traversal, l'ordre de traitement est left-right-current. Nous devons donc d'abord visiter la section de gauche avant de visiter d'autres parties. Nous allons essayer de descendre dans l’arbre le plus à gauche possible pour chaque nœud de l’arbre. Pour chaque nœud actuel, si le bon enfant est présent, placez-le dans la pile avant de pousser le nœud actuel alors que la racine n'est pas NULL/None. Maintenant, retirez un nœud de la pile et vérifiez si le bon enfant de ce nœud existe ou non. S'il existe, vérifiez s'il est identique à l'élément top ou non. S'ils sont identiques, cela indique que nous n'avons pas encore terminé avec la partie droite. Avant de traiter le nœud actuel, nous devons donc traiter la partie droite et, pour cela, afficher l'élément supérieur (enfant de droite) et repousser le nœud actuel dans la pile. . À chaque fois, notre tête est l'élément éclaté. Si l'élément actuel n'est pas identique au sommet et que la tête n'est pas NULL, nous en avons terminé avec les sections gauche et droite afin que nous puissions maintenant traiter le nœud actuel. Nous devons répéter les étapes précédentes jusqu'à ce que la pile soit vide.

def Postorder_iterative(head):
    if head is None:
        return None
    sta=stack()
    while True:
        while head is not None:
            if head.r:
                sta.Push(head.r)
            sta.Push(head)
            head=head.l
        if sta.top is -1:
            break
        head = sta.pop()
        if head.r is not None and sta.top is not -1  and head.r is sta.A[sta.top]:
            x=sta.pop()
            sta.Push(head)
            head=x
        else:
            print(head.val,end = ' ')
            head=None
    print()    
0
suvojit_007

Je n'ai pas ajouté la classe de noeuds car elle n'est pas particulièrement pertinente ni de cas de test, laissant ceux-ci comme exercice pour le lecteur, etc.

void postOrderTraversal(node* root)
{
    if(root == NULL)
        return;

    stack<node*> st;
    st.Push(root);

    //store most recent 'visited' node
    node* prev=root;

    while(st.size() > 0)
    {
        node* top = st.top();
        if((top->left == NULL && top->right == NULL))
        {
            prev = top;
            cerr<<top->val<<" ";
            st.pop();
            continue;
        }
        else
        {
            //we can check if we are going back up the tree if the current
            //node has a left or right child that was previously outputted
            if((top->left == prev) || (top->right== prev))
            {
                prev = top;
                cerr<<top->val<<" ";
                st.pop();
                continue;
            }

            if(top->right != NULL)
                st.Push(top->right);

            if(top->left != NULL)
                st.Push(top->left);
        }
    }
    cerr<<endl;
}

temps d'exécution O(n) - tous les nœuds doivent être visités ET espace O(n) - pour la pile, le cas le plus défavorable est constitué d'une liste chaînée à une seule ligne

0
gilla07

1.1 Créer une pile vide

2.1 Suivre alors que la racine n'est pas NULL

a) Push root's right child and then root to stack.

b) Set root as root's left child.

2.2 Extraire un élément de la pile et le définir en tant que racine.

a) If the popped item has a right child and the right child 
   is at top of stack, then remove the right child from stack,
   Push the root back and set root as root's right child.

b) Else print root's data and set root as NULL.

2.3 Répétez les étapes 2.1 et 2.2 tant que la pile n'est pas vide.

0
Ankur Lathiya

Je recherchais un extrait de code performant et simple à personnaliser. Les arbres filetés ne sont pas «simples». La solution à double pile nécessite O(n) de la mémoire. La solution LeetCode et la solution de tcb ont des vérifications et des efforts supplémentaires ... 

Voici un algorithme classique traduit en C qui a fonctionné pour moi:

void postorder_traversal(TreeNode *p, void (*visit)(TreeNode *))
{
    TreeNode   *stack[40];      // simple C stack, no overflow check
    TreeNode  **sp = stack;
    TreeNode   *last_visited = NULL;

    for (; p != NULL; p = p->left)
        *sp++ = p;

    while (sp != stack) {
        p = sp[-1];
        if (p->right == NULL || p->right == last_visited) {
            visit(p);
            last_visited = p;
            sp--;
        } else {
            for (p = p->right; p != NULL; p = p->left)
                *sp++ = p;
        }
    }
}

IMHO, cet algorithme est plus facile à suivre que le pseudocode wikipedia.org/Tree_traversal bien performant et lisible. Pour des détails glorieux, voir les réponses aux exercices sur les arbres binaires dans le Volume 1 de Knuth.

0
Sergey D

C'est très agréable de voir autant d'approches animées à ce problème. Très inspirant en effet!

Je suis tombé sur ce sujet à la recherche d'une solution itérative simple pour supprimer tous les nœuds de mon implémentation d'arborescence binaire. J'en ai essayé quelques-unes et j'ai essayé quelque chose de similaire trouvé ailleurs sur le Net, mais aucune d'entre elles n'était vraiment à mon goût.

Le fait est que je développe un module d’indexation de base de données dans un but très spécifique (indexation Bitcoin Blockchain) et que mes données sont stockées sur disque, pas dans la RAM. J'échange les pages au besoin et gère moi-même la mémoire. C'est plus lent, mais assez rapide pour le but, et avec le stockage sur disque au lieu de la RAM, je n'ai aucune influence religieuse contre le gaspillage d'espace (les disques durs sont bon marché).

Pour cette raison, mes nœuds dans mon arbre binaire ont des pointeurs parents. C'est (tout) l'espace supplémentaire dont je parle. J'ai besoin des parents parce que je dois itérer à la fois ascendant et descendant à travers l'arbre pour différentes raisons.

Ayant cela à l'esprit, j'ai rapidement écrit un petit morceau de pseudo-code sur la façon dont cela pourrait être fait, c'est-à-dire une suppression de nœuds à la volée après la commande. Il a été mis en œuvre et testé et est devenu une partie de ma solution. Et c'est assez rapide aussi.

Le problème est le suivant: cela devient vraiment, VRAIMENT, simple lorsque les nœuds ont des pointeurs parents et, en outre, depuis que je peux annuler le lien du parent vers le nœud "tout juste parti".

Voici le pseudo-code pour la suppression itérative de post-commande:

Node current = root;
while (current)
{
  if (current.left)       current = current.left;  // Dive down left
  else if (current.right) current = current.right; // Dive down right
  else
  {
    // Node "current" is a leaf, i.e. no left or right child
    Node parent = current.parent; // assuming root.parent == null
    if (parent)
    {
      // Null out the parent's link to the just departing node
      if (parent.left == current) parent.left = null;
      else                        parent.right = null;
    }
    delete current;
    current = parent;
  }
}
root = null;

Si vous êtes intéressé par une approche plus théorique du codage de collections complexes (comme mon arbre binaire, qui est en réalité un arbre rouge-noir auto-équilibrant), consultez ces liens:

http://opendatastructures.org/versions/edition-0.1e/ods-Java/6_2_BinarySearchTree_Unbala.htmlhttp://opendatastructures.org/versions/edition-0.1e/ods-Java/ 9_2_RedBlackTree_Simulated_.htmlhttps://www.cs.auckland.ac.nz/software/AlgAnim/red_black.html

Bonne codage :-)

Søren Fog http://iprotus.eu/

0
Søren L. Fog

Deux méthodes pour effectuer la traversée après commande sans récursivité: 

1. Utilisation d'un hachage de nœuds visités et d'une pile pour le retour en arrière:

private void postOrderWithoutRecursion(TreeNode root) {
    if (root == null || root.left == null && root.right == null) {
        return;
    }
    Stack<TreeNode> stack = new Stack<>();
    Set<TreeNode> visited = new HashSet<>();
    while (!stack.empty() || root != null) {
        if (root != null) {
            stack.Push(root);
            visited.add(root);
            root = root.left;
        } else {
            root = stack.peek();
            if (root.right == null || visited.contains(root.right)) {
                System.out.print(root.val+" ");
                stack.pop();
                root = null;
            } else {
                root = root.right;
            }

        }
    }
}


Complexité temporelle: O(n) 
Complexité de l'espace: O(2n) 

2. Utilisation de la méthode de modification d’arbre: 

private void postOrderWithoutRecursionAlteringTree(TreeNode root) {
    if (root == null || root.left == null && root.right == null) {
        return;
    }
    Stack<TreeNode> stack = new Stack<>();
    while (!stack.empty() || root != null) {
        if (root != null) {
            stack.Push(root);
            root = root.left;
        } else {
            root = stack.peek();
            if (root.right == null) {
                System.out.print(root.val+" ");
                stack.pop();
                root = null;
            } else {
                TreeNode temp = root.right;
                root.right = null;
                root = temp;
            }
        }
    }
}


Complexité temporelle: O(n) 
Complexité de l'espace: O(n) 

Classe TreeNode:

public class TreeNode {
    public int val;

    public TreeNode left;

    public TreeNode right;

    public TreeNode(int x) {
        val = x;
    }
}
0
Ritesh Puj

Vous pouvez donc utiliser une pile pour effectuer une traversée de post-commande.

private void PostOrderTraversal(Node pos) {
    Stack<Node> stack = new Stack<Node>();
    do {
        if (pos==null && (pos=stack.peek().right)==null) {
            for (visit(stack.peek()); stack.pop()==(stack.isEmpty()?null:stack.peek().right); visit(stack.peek())) {}
        } else if(pos!=null) {
            stack.Push(pos);
            pos=pos.left;
        }
    } while (!stack.isEmpty());
}
0
GGG

Ici, je colle différentes versions de c # (.net) comme référence: (Pour un parcours itératif dans l’ordre, vous pouvez vous référer à: Aidez-moi à comprendre Inversé sans utiliser la récursivité )

  1. wiki ( http://en.wikipedia.org/wiki/Post-order%5Ftraversal#Implementations ) (élégant)
  2. Une autre version de single stack (# 1 et # 2: utilise essentiellement le fait que lors du parcours suivant l'ordre, le nœud enfant approprié est visité avant de se rendre au nœud lui-même - nous nous fions donc simplement à la vérification si l'enfant de pile est le bon enfant est en effet le dernier nœud de traversée de commande post qui a été visité - j’ai ajouté des commentaires dans les extraits de code ci-dessous pour plus de détails) 
  3. Utilisation de la version à deux piles (réf: http://www.geeksforgeeks.org/iterative-postorder-traversal/ ) (Plus facile: en gros, post reverse traversal reverse n’est rien d’autre que pré commande traversal avec un simple Tweak qui le noeud droit est visité en premier, puis le noeud gauche)
  4. Utiliser le drapeau de visiteur (facile)
  5. Tests unitaires

~

public string PostOrderIterative_WikiVersion()
        {
            List<int> nodes = new List<int>();
            if (null != this._root)
            {
                BinaryTreeNode lastPostOrderTraversalNode = null;
                BinaryTreeNode iterativeNode = this._root;
                Stack<BinaryTreeNode> stack = new Stack<BinaryTreeNode>();
                while ((stack.Count > 0)//stack is not empty
                    || (iterativeNode != null))
                {
                    if (iterativeNode != null)
                    {
                        stack.Push(iterativeNode);
                        iterativeNode = iterativeNode.Left;
                    }
                    else
                    {
                        var stackTop = stack.Peek();
                        if((stackTop.Right != null)
                            && (stackTop.Right != lastPostOrderTraversalNode))
                        {
                            //i.e. last traversal node is not right element, so right sub tree is not
                            //yet, traversed. so we need to start iterating over right tree 
                            //(note left tree is by default traversed by above case)
                            iterativeNode = stackTop.Right;
                        }
                        else
                        {
                            //if either the iterative node is child node (right and left are null)
                            //or, stackTop's right element is nothing but the last traversal node
                            //(i.e; the element can be popped as the right sub tree have been traversed)
                            var top = stack.Pop();
                            Debug.Assert(top == stackTop);
                            nodes.Add(top.Element);
                            lastPostOrderTraversalNode = top;
                        }
                    }
                }
            }
            return this.ListToString(nodes);
        }

Voici la traversée post-commande avec une pile (ma version)

public string PostOrderIterative()
        {
            List<int> nodes = new List<int>();
            if (null != this._root)
            {
                BinaryTreeNode lastPostOrderTraversalNode = null;
                BinaryTreeNode iterativeNode = null;
                Stack<BinaryTreeNode> stack = new Stack<BinaryTreeNode>();
                stack.Push(this._root);
                while(stack.Count > 0)
                {
                    iterativeNode = stack.Pop();
                    if ((iterativeNode.Left == null)
                        && (iterativeNode.Right == null))
                    {
                        nodes.Add(iterativeNode.Element);
                        lastPostOrderTraversalNode = iterativeNode;
                        //make sure the stack is not empty as we need to peek at the top
                        //for ex, a tree with just root node doesn't have to enter loop
                        //and also node Peek() will throw invalidoperationexception
                        //if it is performed if the stack is empty
                        //so, it handles both of them.
                        while(stack.Count > 0) 
                        {
                            var stackTop = stack.Peek();
                            bool removeTop = false;
                            if ((stackTop.Right != null) &&
                                //i.e. last post order traversal node is nothing but right node of 
                                //stacktop. so, all the elements in the right subtree have been visted
                                //So, we can pop the top element
                                (stackTop.Right == lastPostOrderTraversalNode))
                            {
                                //in other words, we can pop the top if whole right subtree is
                                //traversed. i.e. last traversal node should be the right node
                                //as the right node will be traverse once all the subtrees of
                                //right node has been traversed
                                removeTop = true;
                            }
                            else if(
                                //right subtree is null
                                (stackTop.Right == null) 
                                && (stackTop.Left != null) 
                                //last traversal node is nothing but the root of left sub tree node
                                && (stackTop.Left == lastPostOrderTraversalNode))
                            {
                                //in other words, we can pop the top of stack if right subtree is null,
                                //and whole left subtree has been traversed
                                removeTop = true;
                            }
                            else
                            {
                                break;
                            }
                            if(removeTop)
                            {
                                var top = stack.Pop();
                                Debug.Assert(stackTop == top);
                                lastPostOrderTraversalNode = top;
                                nodes.Add(top.Element);
                            }
                        }
                    }
                    else 
                    {
                        stack.Push(iterativeNode);
                        if(iterativeNode.Right != null)
                        {
                            stack.Push(iterativeNode.Right);
                        }
                        if(iterativeNode.Left != null)
                        {
                            stack.Push(iterativeNode.Left);
                        }
                    }
                }
            }
            return this.ListToString(nodes);
        }

En utilisant deux piles

public string PostOrderIterative_TwoStacksVersion()
        {
            List<int> nodes = new List<int>();
            if (null != this._root)
            {
                Stack<BinaryTreeNode> postOrderStack = new Stack<BinaryTreeNode>();
                Stack<BinaryTreeNode> rightLeftPreOrderStack = new Stack<BinaryTreeNode>();
                rightLeftPreOrderStack.Push(this._root);
                while(rightLeftPreOrderStack.Count > 0)
                {
                    var top = rightLeftPreOrderStack.Pop();
                    postOrderStack.Push(top);
                    if(top.Left != null)
                    {
                        rightLeftPreOrderStack.Push(top.Left);
                    }
                    if(top.Right != null)
                    {
                        rightLeftPreOrderStack.Push(top.Right);
                    }
                }
                while(postOrderStack.Count > 0)
                {
                    var top = postOrderStack.Pop();
                    nodes.Add(top.Element);
                }
            }
            return this.ListToString(nodes);
        }

Avec indicateur visité en C # (.net):

public string PostOrderIterative()
        {
            List<int> nodes = new List<int>();
            if (null != this._root)
            {
                BinaryTreeNode iterativeNode = null;
                Stack<BinaryTreeNode> stack = new Stack<BinaryTreeNode>();
                stack.Push(this._root);
                while(stack.Count > 0)
                {
                    iterativeNode = stack.Pop();
                    if(iterativeNode.visted)
                    {
                        //reset the flag, for further traversals
                        iterativeNode.visted = false;
                        nodes.Add(iterativeNode.Element);
                    }
                    else
                    {
                        iterativeNode.visted = true;
                        stack.Push(iterativeNode);
                        if(iterativeNode.Right != null)
                        {
                            stack.Push(iterativeNode.Right);
                        }
                        if(iterativeNode.Left != null)
                        {
                            stack.Push(iterativeNode.Left);
                        }
                    }
                }
            }
            return this.ListToString(nodes);
        }

Les définitions:

class BinaryTreeNode
    {
        public int Element;
        public BinaryTreeNode Left;
        public BinaryTreeNode Right;
        public bool visted;
    }

string ListToString(List<int> list)
        {
            string s = string.Join(", ", list);
            return s;
        }

Tests unitaires

[TestMethod]
        public void PostOrderTests()
        {
            int[] a = { 13, 2, 18, 1, 5, 17, 20, 3, 6, 16, 21, 4, 14, 15, 25, 22, 24 };
            BinarySearchTree bst = new BinarySearchTree();
            foreach (int e in a)
            {
                string s1 = bst.PostOrderRecursive();
                string s2 = bst.PostOrderIterativeWithVistedFlag();
                string s3 = bst.PostOrderIterative();
                string s4 = bst.PostOrderIterative_WikiVersion();
                string s5 = bst.PostOrderIterative_TwoStacksVersion();
                Assert.AreEqual(s1, s2);
                Assert.AreEqual(s2, s3);
                Assert.AreEqual(s3, s4);
                Assert.AreEqual(s4, s5);
                bst.Add(e);
                bst.Delete(e);
                bst.Add(e);
                s1 = bst.PostOrderRecursive();
                s2 = bst.PostOrderIterativeWithVistedFlag();
                s3 = bst.PostOrderIterative();
                s4 = bst.PostOrderIterative_WikiVersion();
                s5 = bst.PostOrderIterative_TwoStacksVersion();
                Assert.AreEqual(s1, s2);
                Assert.AreEqual(s2, s3);
                Assert.AreEqual(s3, s4);
                Assert.AreEqual(s4, s5);
            }
            Debug.WriteLine(string.Format("PostOrderIterative: {0}", bst.PostOrderIterative()));
            Debug.WriteLine(string.Format("PostOrderIterative_WikiVersion: {0}", bst.PostOrderIterative_WikiVersion()));
            Debug.WriteLine(string.Format("PostOrderIterative_TwoStacksVersion: {0}", bst.PostOrderIterative_TwoStacksVersion()));
            Debug.WriteLine(string.Format("PostOrderIterativeWithVistedFlag: {0}", bst.PostOrderIterativeWithVistedFlag()));
            Debug.WriteLine(string.Format("PostOrderRecursive: {0}", bst.PostOrderRecursive()));
        }
0
Dreamer

La solution la plus simple ne semble pas être la meilleure solution, mais elle est facile à comprendre. Et je crois que si vous avez compris la solution, vous pouvez la modifier pour obtenir la meilleure solution possible.

// en utilisant deux piles

public List<Integer> postorderTraversal(TreeNode root){

 Stack<TreeNode> st=new Stack<>();
 Stack<TreeNode> st2=new Stack<>();
 ArrayList<Integer> al = new ArrayList<Integer>(); 

    if(root==null)
        return al;

 st.Push(root);  //Push the root to 1st stack

 while(!st.isEmpty())
 {
     TreeNode curr=st.pop();

     st2.Push(curr);

     if(curr.left!=null)
        st.Push(curr.left);
     if(curr.right!=null)
         st.Push(curr.right);

 }

while(!st2.isEmpty())
    al.add(st2.pop().val);

//this ArrayList contains the postorder traversal

  return al;  
}
0
pooh2
void postorder_stack(Node * root){
    stack ms;
    ms.top = -1;
    if(root == NULL) return ;

    Node * temp ;
    Push(&ms,root);
    Node * prev = NULL;
    while(!is_empty(ms)){
        temp = peek(ms);
        /* case 1. We are nmoving down the tree. */
        if(prev == NULL || prev->left == temp || prev->right == temp){
             if(temp->left)
                  Push(&ms,temp->left);
             else if(temp->right)
                  Push(&ms,temp->right);
             else {
                /* If node is leaf node */
                   printf("%d ", temp->value);
                   pop(&ms);
             }
         }
         /* case 2. We are moving up the tree from left child */
         if(temp->left == prev){
              if(temp->right)
                   Push(&ms,temp->right);
              else
                   printf("%d ", temp->value);
         }

        /* case 3. We are moving up the tree from right child */
         if(temp->right == prev){
              printf("%d ", temp->value);
              pop(&ms);
         }
         prev = temp;
      }

}
0
jitsceait

Voici l'implémentation Java avec deux piles

public static <T> List<T> iPostOrder(BinaryTreeNode<T> root) {
    if (root == null) {
        return Collections.emptyList();
    }
    List<T> result = new ArrayList<T>();
    Deque<BinaryTreeNode<T>> firstLevel = new LinkedList<BinaryTreeNode<T>>();
    Deque<BinaryTreeNode<T>> secondLevel = new LinkedList<BinaryTreeNode<T>>();
    firstLevel.Push(root);
    while (!firstLevel.isEmpty()) {
        BinaryTreeNode<T> node = firstLevel.pop();
        secondLevel.Push(node);
        if (node.hasLeftChild()) {
            firstLevel.Push(node.getLeft());
        }
        if (node.hasRightChild()) {
            firstLevel.Push(node.getRight());
        }
    }
    while (!secondLevel.isEmpty()) {
        result.add(secondLevel.pop().getData());            
    }       
    return result;
}

Voici les tests unitaires

@Test
public void iterativePostOrderTest() {
    BinaryTreeNode<Integer> bst = BinaryTreeUtil.<Integer>fromInAndPostOrder(new Integer[]{4,2,5,1,6,3,7}, new Integer[]{4,5,2,6,7,3,1});
    assertThat(BinaryTreeUtil.iPostOrder(bst).toArray(new Integer[0]), equalTo(new Integer[]{4,5,2,6,7,3,1}));

}
0
craftsmannadeem

Python avec 1 pile et pas d'indicateur:

def postorderTraversal(self, root):
    ret = []
    if not root:
        return ret
    stack = [root]
    current = None
    while stack:
        previous = current
        current = stack.pop()
        if previous and ((previous is current) or (previous is current.left) or (previous is current.right)):
            ret.append(current.val)
        else:
            stack.append(current)
            if current.right:
                stack.append(current.right)
            if current.left:
                stack.append(current.left)

    return ret

Et ce qui est mieux, c’est avec des déclarations similaires, pour que la traversée fonctionne aussi

def inorderTraversal(self, root):
    ret = []
    if not root:
        return ret
    stack = [root]
    current = None
    while stack:
        previous = current
        current = stack.pop()
        if None == previous or previous.left is current or previous.right is current:
            if current.right:
                stack.append(current.right)
            stack.append(current)
            if current.left:
                stack.append(current.left)
        else:
            ret.append(current.val)

    return ret
0
CopperCash
    import Java.util.Stack;
   class Practice
{

    public static void main(String arr[])
    {
        Practice prc = new Practice();
        TreeNode node1 = (prc).new TreeNode(1);
        TreeNode node2 = (prc).new TreeNode(2);
        TreeNode node3 = (prc).new TreeNode(3);
        TreeNode node4 = (prc).new TreeNode(4);
        TreeNode node5 = (prc).new TreeNode(5);
        TreeNode node6 = (prc).new TreeNode(6);
        TreeNode node7 = (prc).new TreeNode(7);
        node1.left = node2;
        node1.right = node3;
        node2.left = node4;
        node2.right = node5;
        node3.left = node6;
        node3.right = node7;
        postOrderIteratively(node1);
    }

    public static void postOrderIteratively(TreeNode root)
    {
        Stack<Entry> stack = new Stack<Entry>();
        Practice prc = new Practice();
        stack.Push((prc).new Entry(root, false));
        while (!stack.isEmpty())
        {
            Entry entry = stack.pop();
            TreeNode node = entry.node;
            if (entry.flag == false)
            {
                if (node.right == null && node.left == null)
                {
                    System.out.println(node.data);
                } else
                {
                    stack.Push((prc).new Entry(node, true));
                    if (node.right != null)
                    {
                        stack.Push((prc).new Entry(node.right, false));
                    }
                    if (node.left != null)
                    {
                        stack.Push((prc).new Entry(node.left, false));
                    }
                }
            } else
            {
                System.out.println(node.data);
            }
        }

    }

    class TreeNode
    {
        int data;
        int leafCount;
        TreeNode left;
        TreeNode right;

        public TreeNode(int data)
        {
            this.data = data;
        }

        public int getLeafCount()
        {
            return leafCount;
        }

        public void setLeafCount(int leafCount)
        {
            this.leafCount = leafCount;
        }

        public TreeNode getLeft()
        {
            return left;
        }

        public void setLeft(TreeNode left)
        {
            this.left = left;
        }

        public TreeNode getRight()
        {
            return right;
        }

        public void setRight(TreeNode right)
        {
            this.right = right;
        }

        @Override
        public String toString()
        {
            return "" + this.data;
        }
    }

    class Entry
    {
        Entry(TreeNode node, boolean flag)
        {
            this.node = node;
            this.flag = flag;
        }

        TreeNode node;
        boolean flag;

        @Override
        public String toString()
        {
            return node.toString();
        }
    }


}
0
Koustav Chatterjee
/**
 * This code will ensure holding of chain(links) of nodes from the root to till the level of the tree.
 * The number of extra nodes in the memory (other than tree) is height of the tree.
 * I haven't used Java stack instead used this ParentChain. 
 * This parent chain is the link for any node from the top(root node) to till its immediate parent.
 * This code will not require any altering of existing BinaryTree (NO flag/parent on all the nodes).
 *  
 *  while visiting the Node 11; ParentChain will be holding the nodes 9 -> 8 -> 7 -> 1 where (-> is parent)
 *  
 *             1                               
              / \               
             /   \              
            /     \             
           /       \            
          /         \           
         /           \          
        /             \         
       /               \        
       2               7               
      / \             /         
     /   \           /          
    /     \         /           
   /       \       /            
   3       6       8               
  / \             /             
 /   \           /              
 4   5           9               
                / \             
                10 11

 *               
 * @author ksugumar
 *
 */
public class InOrderTraversalIterative {
    public static void main(String[] args) {
        BTNode<String> rt;
        String[] dataArray = {"1","2","3","4",null,null,"5",null,null,"6",null,null,"7","8","9","10",null,null,"11",null,null,null,null};
        rt = BTNode.buildBTWithPreOrder(dataArray, new Counter(0));
        BTDisplay.printTreeNode(rt);
        inOrderTravesal(rt);
    }

public static void postOrderTravesal(BTNode<String> root) {
    ParentChain rootChain = new ParentChain(root);
    rootChain.Parent = new ParentChain(null);

    while (root != null) {

        //Going back to parent
        if(rootChain.leftVisited && rootChain.rightVisited) {
            System.out.println(root.data); //Visit the node.
            ParentChain parentChain = rootChain.Parent;
            rootChain.Parent = null; //Avoid the leak
            rootChain = parentChain;
            root = rootChain.root;
            continue;
        }

        //Traverse Left
        if(!rootChain.leftVisited) {
            rootChain.leftVisited = true;
            if (root.left != null) {
                ParentChain local = new ParentChain(root.left); //It is better to use pool to reuse the instances.
                local.Parent = rootChain;
                rootChain = local;
                root = root.left;
                continue;
            }
        } 

        //Traverse RIGHT
        if(!rootChain.rightVisited) {
            rootChain.rightVisited = true;
            if (root.right != null) {
                ParentChain local = new ParentChain(root.right); //It is better to use pool to reuse the instances.
                local.Parent = rootChain;
                rootChain = local;
                root = root.right;
                continue;
            }
        }
    }
}

class ParentChain {
    BTNode<String> root;
    ParentChain Parent;
    boolean leftVisited = false;
    boolean rightVisited = false;

    public ParentChain(BTNode<String> node) {
        this.root = node; 
    }

    @Override
    public String toString() {
        return root.toString();
    }
}
0
Kanagavelu Sugumar
void display_without_recursion(struct btree **b) 
{
    deque< struct btree* > dtree;
        if(*b)
    dtree.Push_back(*b);
        while(!dtree.empty() )
    {
        struct btree* t = dtree.front();
        cout << t->nodedata << " " ;
        dtree.pop_front();
        if(t->right)
        dtree.Push_front(t->right);
        if(t->left)
        dtree.Push_front(t->left);
    }
    cout << endl;
}
0
Kunal Bansal

Profondeur d'abord, ordre de poste, non récursif, sans pile

Quand tu as un parent:

   node_t
   {
     left,
     right
     parent
   }

   traverse(node_t rootNode)
   {
     bool backthreading = false 
     node_t node = rootNode

     while(node <> 0)

        if (node->left <> 0) and backthreading = false then
               node = node->left

            continue 
        endif

         >>> process node here <<<


        if node->right <> 0 then
            lNode = node->right
            backthreading = false
        else
            node = node->parent

            backthreading = true
        endif
    endwhile
0
Tim