Je suis capable de comprendre la traversée de pré-commande sans utiliser la récursivité, mais j'ai de la difficulté à traverser en ordre. Je n'arrive pas à comprendre, peut-être parce que je n'ai pas compris le fonctionnement interne de la récursion.
C'est ce que j'ai essayé jusqu'à présent:
def traverseInorder(node):
lifo = Lifo()
lifo.Push(node)
while True:
if node is None:
break
if node.left is not None:
lifo.Push(node.left)
node = node.left
continue
prev = node
while True:
if node is None:
break
print node.value
prev = node
node = lifo.pop()
node = prev
if node.right is not None:
lifo.Push(node.right)
node = node.right
else:
break
La boucle intérieure tout ne se sent pas bien. De plus, certains éléments sont imprimés deux fois. peut-être que je peux résoudre ce problème en vérifiant si ce nœud a déjà été imprimé, mais cela nécessite une autre variable qui, encore une fois, ne semble pas appropriée. Où vais-je mal?
Je n'ai pas essayé la traversée post-commande, mais je suppose que c'est similaire et que je ferai face au même blocage conceptuel là aussi.
Merci pour votre temps!
P.S .: Définitions de Lifo
et Node
:
class Node:
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
class Lifo:
def __init__(self):
self.lifo = ()
def Push(self, data):
self.lifo = (data, self.lifo)
def pop(self):
if len(self.lifo) == 0:
return None
ret, self.lifo = self.lifo
return ret
Commencez avec l'algorithme récursif (pseudocode):
traverse(node):
if node != None do:
traverse(node.left)
print node.value
traverse(node.right)
endif
Il s'agit clairement d'un cas de récursion de la queue, vous pouvez donc facilement le transformer en boucle while.
traverse(node):
while node != None do:
traverse(node.left)
print node.value
node = node.right
endwhile
Vous êtes laissé avec un appel récursif. Ce que fait l'appel récursif, c'est pousser un nouveau contexte sur la pile, exécuter le code depuis le début, puis récupérer le contexte et continuer à faire ce qu'il faisait. Donc, vous créez une pile pour le stockage et une boucle qui détermine, à chaque itération, si nous sommes dans une situation de "première exécution" (nœud non nul) ou dans une situation de "renvoi" (nœud nul, pile non vide ) et exécute le code approprié:
traverse(node):
stack = []
while !empty(stack) || node != None do:
if node != None do: // this is a normal call, recurse
Push(stack,node)
node = node.left
else // we are now returning: pop and print the current node
node = pop(stack)
print node.value
node = node.right
endif
endwhile
La partie difficile à saisir est la partie "retour": vous devez déterminer, dans votre boucle, si le code que vous utilisez est dans la situation "entrer dans la fonction" ou dans la situation "revenir d'un appel", et vous aura une chaîne if/else
avec autant de cas que vous avez de récursions non terminales dans votre code.
Dans cette situation spécifique, nous utilisons le nœud pour conserver des informations sur la situation. Une autre façon serait de stocker cela dans la pile elle-même (comme le fait un ordinateur pour la récursion). Avec cette technique, le code est moins optimal mais plus facile à suivre
traverse(node):
// entry:
if node == NULL do return
traverse(node.left)
// after-left-traversal:
print node.value
traverse(node.right)
traverse(node):
stack = [node,'entry']
while !empty(stack) do:
[node,state] = pop(stack)
switch state:
case 'entry':
if node == None do: break; // return
Push(stack,[node,'after-left-traversal']) // store return address
Push(stack,[node.left,'entry']) // recursive call
break;
case 'after-left-traversal':
print node.value;
// tail call : no return address
Push(stack,[node.right,'entry']) // recursive call
end
endwhile
Voici un code c ++ simple et non récursif dans l'ordre.
void inorder (node *n)
{
stack s;
while(n){
s.Push(n);
n=n->left;
}
while(!s.empty()){
node *t=s.pop();
cout<<t->data;
t=t->right;
while(t){
s.Push(t);
t = t->left;
}
}
}
def print_tree_in (racine): pile = [] actuelle = racine tant que True: tant que la valeur actuelle n'est pas Aucune: stack.append (current) current = current.getLeft (); si non stack: renvoyer current = stack.pop () print current.getValue () alors que current.getRight vaut Aucun et empiler: current = stack.pop () print current.getValue () [. ] current = current.getRight ();
Voici un exemple de traversée en ordre utilisant stack in c # (.net):
(pour post-commande itérative, vous pouvez vous référer à: Traversée de post-commande de l'arbre binaire sans récursion )
public string InOrderIterative()
{
List<int> nodes = new List<int>();
if (null != this._root)
{
Stack<BinaryTreeNode> stack = new Stack<BinaryTreeNode>();
var iterativeNode = this._root;
while(iterativeNode != null)
{
stack.Push(iterativeNode);
iterativeNode = iterativeNode.Left;
}
while(stack.Count > 0)
{
iterativeNode = stack.Pop();
nodes.Add(iterativeNode.Element);
if(iterativeNode.Right != null)
{
stack.Push(iterativeNode.Right);
iterativeNode = iterativeNode.Right.Left;
while(iterativeNode != null)
{
stack.Push(iterativeNode);
iterativeNode = iterativeNode.Left;
}
}
}
}
return this.ListToString(nodes);
}
Voici un exemple avec le drapeau visité:
public string InorderIterative_VisitedFlag()
{
List<int> nodes = new List<int>();
if (null != this._root)
{
Stack<BinaryTreeNode> stack = new Stack<BinaryTreeNode>();
BinaryTreeNode iterativeNode = null;
stack.Push(this._root);
while(stack.Count > 0)
{
iterativeNode = stack.Pop();
if(iterativeNode.visted)
{
iterativeNode.visted = false;
nodes.Add(iterativeNode.Element);
}
else
{
iterativeNode.visted = true;
if(iterativeNode.Right != null)
{
stack.Push(iterativeNode.Right);
}
stack.Push(iterativeNode);
if (iterativeNode.Left != null)
{
stack.Push(iterativeNode.Left);
}
}
}
}
return this.ListToString(nodes);
}
les définitions de l'utilitaire binarytreenode, listtostring:
string ListToString(List<int> list)
{
string s = string.Join(", ", list);
return s;
}
class BinaryTreeNode
{
public int Element;
public BinaryTreeNode Left;
public BinaryTreeNode Right;
}
def traverseInorder(node):
lifo = Lifo()
while node is not None:
if node.left is not None:
lifo.Push(node)
node = node.left
continue
print node.value
if node.right is not None:
node = node.right
continue
node = lifo.Pop()
if node is not None :
print node.value
node = node.right
PS: Je ne connais pas Python, il peut donc y avoir quelques problèmes de syntaxe.
Voici une solution C++ itérative comme alternative à ce que @Emadpres a publié:
void inOrderTraversal(Node *n)
{
stack<Node *> s;
s.Push(n);
while (!s.empty()) {
if (n) {
n = n->left;
} else {
n = s.top(); s.pop();
cout << n->data << " ";
n = n->right;
}
if (n) s.Push(n);
}
}
class Tree:
def __init__(self, value):
self.left = None
self.right = None
self.value = value
def insert(self,root,node):
if root is None:
root = node
else:
if root.value < node.value:
if root.right is None:
root.right = node
else:
self.insert(root.right, node)
else:
if root.left is None:
root.left = node
else:
self.insert(root.left, node)
def inorder(self,tree):
if tree.left != None:
self.inorder(tree.left)
print "value:",tree.value
if tree.right !=None:
self.inorder(tree.right)
def inorderwithoutRecursion(self,tree):
holdRoot=tree
temp=holdRoot
stack=[]
while temp!=None:
if temp.left!=None:
stack.append(temp)
temp=temp.left
print "node:left",temp.value
else:
if len(stack)>0:
temp=stack.pop();
temp=temp.right
print "node:right",temp.value
Voici un code Python itératif pour Inorder Traversal ::
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def inOrder(root):
current = root
s = []
done = 0
while(not done):
if current is not None :
s.append(current)
current = current.left
else :
if (len(s)>0):
current = s.pop()
print current.data
current = current.right
else :
done =1
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
inOrder(root)
On peut se souvenir implicitement de l'état,
traverse(node) {
if(!node) return;
Push(stack, node);
while (!empty(stack)) {
/*Remember the left nodes in stack*/
while (node->left) {
Push(stack, node->left);
node = node->left;
}
/*Process the node*/
printf("%d", node->data);
/*Do the tail recursion*/
if(node->right) {
node = node->right
} else {
node = pop(stack); /*New Node will be from previous*/
}
}
}
Traversée simple dans l'ordre sans récursion
'''iterative inorder traversal, O(n) time & O(n) space '''
class Node:
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
def inorder_iter(root):
stack = [root]
current = root
while len(stack) > 0:
if current:
while current.left:
stack.append(current.left)
current = current.left
popped_node = stack.pop()
current = None
if popped_node:
print popped_node.value
current = popped_node.right
stack.append(current)
a = Node('a')
b = Node('b')
c = Node('c')
d = Node('d')
b.right = d
a.left = b
a.right = c
inorder_iter(a)
Cela peut être utile (implémentation Java)
public void inorderDisplay(Node root) {
Node current = root;
LinkedList<Node> stack = new LinkedList<>();
while (true) {
if (current != null) {
stack.Push(current);
current = current.left;
} else if (!stack.isEmpty()) {
current = stack.poll();
System.out.print(current.data + " ");
current = current.right;
} else {
break;
}
}
}
Petite optimisation de la réponse par @Emadpres
def in_order_search(node):
stack = Stack()
current = node
while True:
while current is not None:
stack.Push(current)
current = current.l_child
if stack.size() == 0:
break
current = stack.pop()
print(current.data)
current = current.r_child
@ Victor, j'ai une suggestion sur votre mise en œuvre en essayant de pousser l'état dans la pile. Je ne vois pas que c'est nécessaire. Parce que chaque élément que vous retirez de la pile est déjà laissé traversé. Ainsi, au lieu de stocker les informations dans la pile, tout ce dont nous avons besoin est un indicateur pour indiquer si le prochain nœud à traiter provient de cette pile ou non. Voici ma mise en œuvre qui fonctionne bien:
def intraverse(node):
stack = []
leftChecked = False
while node != None:
if not leftChecked and node.left != None:
stack.append(node)
node = node.left
else:
print node.data
if node.right != None:
node = node.right
leftChecked = False
Elif len(stack)>0:
node = stack.pop()
leftChecked = True
else:
node = None