Quando usar a estratégia de pré-pedido, pedido e pós-pedido transversal
Antes que você possa entender sob quais circunstâncias usar a pré-ordem, a ordem e a pós-ordem para uma árvore binária, você precisa entender exatamente como cada estratégia de passagem funciona. Use a seguinte árvore como exemplo.
A raiz da árvore é 7 , o nó mais à esquerda é 0 , o nó mais à direita é 10 .
Traversal de pré-encomenda :
Resumo: começa na raiz ( 7 ), termina no nó mais à direita ( 10 )
Sequência transversal: 7, 1, 0, 3, 2, 5, 4, 6, 9, 8, 10
Percurso em ordem :
Resumo: começa no nó mais à esquerda ( 0 ), termina no nó mais à direita ( 10 )
Sequência transversal: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
Traversal pós-pedido :
Resumo: começa com o nó mais à esquerda ( 0 ), termina com a raiz ( 7 )
Sequência transversal: 0, 2, 4, 6, 5, 3, 1, 8, 10, 9, 7
Quando usar a pré-encomenda, encomenda ou pós-encomenda?
A estratégia de passagem que o programador seleciona depende das necessidades específicas do algoritmo que está sendo projetado. O objetivo é a velocidade, então escolha a estratégia que traz os nós de que você precisa com mais rapidez.
Se você sabe que precisa explorar as raízes antes de inspecionar as folhas, faça uma pré-encomenda porque encontrará todas as raízes antes de todas as folhas.
Se você sabe que precisa explorar todas as folhas antes de qualquer nó, selecione pós-pedido porque não perde tempo inspecionando raízes em busca de folhas.
Se você sabe que a árvore tem uma sequência inerente nos nós e deseja achatar a árvore de volta à sua sequência original, uma travessia em ordem deve ser usada. A árvore seria achatada da mesma forma que foi criada. Uma passagem de pré-pedido ou pós-pedido pode não desdobrar a árvore de volta à sequência que foi usada para criá-la.
Algoritmos recursivos para pré-pedido, pedido e pós-pedido (C ++):
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
}
Pré-encomenda: Usado para criar uma cópia de uma árvore. Por exemplo, se você deseja criar uma réplica de uma árvore, coloque os nós em uma matriz com uma travessia de pré-ordem. Em seguida, execute uma operação Insert em uma nova árvore para cada valor do array. Você vai acabar com uma cópia de sua árvore original.
Em ordem:: usado para obter os valores dos nós em ordem não decrescente em um BST.
Pós-pedido:: usado para excluir uma árvore da folha à raiz
fonte
Se eu quisesse simplesmente imprimir o formato hierárquico da árvore em um formato linear, provavelmente usaria travessia de pré-ordem. Por exemplo:
fonte
TreeView
componente em um aplicativo GUI.A pré e pós-ordem estão relacionadas a algoritmos recursivos de cima para baixo e de baixo para cima, respectivamente. Se você quiser escrever um determinado algoritmo recursivo em árvores binárias de maneira iterativa, é isso que você essencialmente fará.
Observe, além disso, que as sequências de pré e pós-ordem em conjunto especificam completamente a árvore em questão, produzindo uma codificação compacta (para árvores esparsas, pelo menos).
fonte
Há muitos lugares onde você vê que essa diferença desempenha um papel real.
Um ótimo que vou apontar é a geração de código para um compilador. Considere a declaração:
A maneira como você geraria código para isso é (ingenuamente, é claro) primeiro gerar o código para carregar y em um registrador, carregar 32 em um registrador e então gerar uma instrução para adicionar os dois. Porque algo tem que estar em um registro antes de você manipulá-lo (vamos supor que você sempre pode fazer operandos constantes, mas tanto faz), você deve fazer dessa maneira.
Em geral, as respostas que você pode obter para essa pergunta se reduzem basicamente a isto: a diferença realmente importa quando há alguma dependência entre o processamento de diferentes partes da estrutura de dados. Você vê isso ao imprimir os elementos, ao gerar o código (o estado externo faz a diferença, você também pode ver isso monadicamente, é claro) ou ao fazer outros tipos de cálculos sobre a estrutura que envolvem cálculos dependendo dos filhos sendo processados primeiro .
fonte