J'ai réalisé récemment que, même si j'avais utilisé les nombreuses ressources de BST dans ma vie, je n'avais jamais envisagé d'utiliser autre chose que Inorder Traversal (bien que je sache à quel point il est facile d'adapter un programme pour utiliser les parcours pré/post-ordre).
En réalisant cela, j’ai sorti certains de mes anciens manuels de structures de données et j’ai cherché un raisonnement derrière l’utilité des parcours avant et après commande - ils n’en ont cependant pas beaucoup parlé.
Quels sont quelques exemples de quand utiliser pratiquement en pré-commande/post-commande? Quand est-ce plus logique que dans l'ordre?
Avant de pouvoir comprendre dans quelles circonstances utiliser la pré-commande, la commande et la post-commande pour un arbre binaire, vous devez comprendre exactement le fonctionnement de chaque stratégie de parcours. Utilisez l'arbre suivant comme exemple.
La racine de l'arbre est 7, le noeud le plus à gauche est , le noeud le plus à droite est 1.
traversée pré-commande:
Résumé: commence à la racine (7), se termine au nœud le plus à droite (1)
Séquence de traversée: 7, 1, 0, 3, 2, 5, 4, 6, 9, 8, 10
dans l'ordre:
Résumé: commence au nœud le plus à gauche (), se termine au nœud le plus à droite (1)
Séquence de traversée: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
traversée après commande:
Résumé: commence par le noeud le plus à gauche (), se termine par la racine (7)
Séquence de traversée: 0, 2, 4, 6, 5, 3, 1, 8, 10, 9, 7
La stratégie de parcours choisie par le programmeur dépend des besoins spécifiques de l'algorithme en cours de conception. L'objectif étant la vitesse, choisissez la stratégie qui vous apporte les nœuds dont vous avez le plus besoin.
Si vous savez que vous devez explorer les racines avant d'inspecter les feuilles, vous choisissez en pré-commande car vous rencontrerez toutes les racines avant toutes les feuilles.
Si vous savez que vous devez explorer toutes les feuilles avant les nœuds, vous sélectionnez post-commande car vous ne perdez pas de temps à inspecter les racines dans la recherche de feuilles.
Si vous savez que l'arborescence a une séquence inhérente dans les nœuds et que vous souhaitez l'aplatir dans sa séquence d'origine, utilisez un parcours dans l'ordre. L'arbre serait aplati de la même manière qu'il avait été créé. Une traversée pré-commande ou post-commande peut ne pas dérouler l’arbre dans la séquence qui a été utilisée pour le créer.
struct Node{
int data;
Node *left, *right;
};
void preOrderPrint(Node *root)
{
print(root->name); //record root
if (root->left != NULL) preOrderPrint(root->left); //traverse left if exists
if (root->right != NULL) preOrderPrint(root->right);//traverse right if exists
}
void inOrderPrint(Node *root)
{
if (root.left != NULL) inOrderPrint(root->left); //traverse left if exists
print(root->name); //record root
if (root.right != NULL) inOrderPrint(root->right); //traverse right if exists
}
void postOrderPrint(Node *root)
{
if (root->left != NULL) postOrderPrint(root->left); //traverse left if exists
if (root->right != NULL) postOrderPrint(root->right);//traverse right if exists
print(root->name); //record root
}
Si je voulais simplement imprimer le format hiérarchique de l'arborescence dans un format linéaire, j'utiliserais probablement le parcours en pré-ordre. Par exemple:
- ROOT
- A
- B
- C
- D
- E
- F
- G
tilisation en pré-commande/en commande/post-commande: mots simples
Pre-order: Utilisé pour créer une copie de l’arborescence Exemple: Si vous souhaitez créer une réplique d’une arborescence et que vous avez besoin de valeurs de nœud dans un tableau, vous devez insérer ces valeurs à partir de l’index 0 nouvel arbre, vous obtenez une réplique
In-order:: Pour obtenir les valeurs du noeud dans un ordre non croissant
Post-order:: Lorsque vous souhaitez supprimer un arbre de la feuille à la racine
Le pré-ordre et le post-ordre sont liés aux algorithmes récursifs descendant et ascendant, respectivement. Si vous voulez écrire un algorithme récursif donné sur des arbres binaires de manière itérative, c'est essentiellement ce que vous allez faire.
Notez en outre que les séquences de pré-ordre et de post-ordre spécifient ensemble complètement l’arbre en question, ce qui donne un codage compact (pour les arbres épars au moins).
Il y a des tonnes d'endroits où vous voyez que cette différence joue un rôle réel.
Un excellent exemple que je mentionnerai concerne la génération de code pour un compilateur. Considérez la déclaration:
x := y + 32
Pour générer ce code, vous devez (naïvement bien entendu) commencer par générer le code permettant de charger y dans un registre, de charger 32 dans un registre, puis de générer une instruction permettant d’ajouter les deux. Parce que quelque chose doit être dans un registre avant de le manipuler (supposons que vous pouvez toujours faire des opérandes constants mais peu importe), vous devez le faire de cette façon.
En général, les réponses que vous pouvez obtenir à cette question se résument essentiellement à ceci: la différence est vraiment importante lorsqu'il existe une certaine dépendance entre le traitement de différentes parties de la structure de données. Vous le voyez lors de l’impression des éléments, lors de la génération de code (l’état externe fait toute la différence, bien sûr), ou lors d’autres types de calculs sur la structure qui impliquent des calculs en fonction des enfants traités en premier. .