← Back to home

Tree Traversal

By Pscodium · 8/4/2026 · 2 views

Tree Traversal — Como Percorrer Árvores

Tree Traversal (percurso em árvores) é o conjunto de técnicas utilizadas para visitar os nós de uma estrutura de dados chamada árvore.

Árvores aparecem em diversos lugares da computação:

  • Estruturas de arquivos
  • Bancos de dados
  • Sistemas de busca
  • DOM de páginas web
  • Sistemas de decisão
  • Compiladores
  • Inteligência artificial
  • Estruturas de índices
  • Árvores binárias de busca

Para trabalhar com árvores, precisamos primeiro entender como percorrer todos os seus nós.

Os principais métodos são:

DFS
├── Preorder
├── Inorder
└── Postorder

BFS
└── Level Order

1. O que é uma árvore?

Uma Tree é uma estrutura de dados hierárquica formada por nós.

Imagine uma organização de arquivos:

Projeto
├── src
│   ├── components
│   └── pages
├── public
└── package.json

Isso é uma estrutura de árvore.

Temos um elemento inicial:

Projeto

Chamado de:

Root

E seus elementos filhos:

src
public
package.json

Dentro de src, temos outros elementos:

components
pages

Cada elemento pode ter seus próprios filhos.


2. Estrutura de uma árvore

Podemos representar uma árvore assim:

          A
        /   \
       B     C
      / \     \
     D   E     F

Temos:

A → Root

Os filhos de A são:

B e C

Os filhos de B são:

D e E

O filho de C é:

F

Os nós que não possuem filhos são chamados de:

Leaf Nodes

Nesse exemplo:

D
E
F

são folhas.


3. O que é uma árvore binária?

Uma Binary Tree (árvore binária) é uma árvore em que cada nó pode ter no máximo dois filhos.

Normalmente chamamos os filhos de:

Left
Right

Por exemplo:

        10
       /  \
      5    15
     / \     \
    3   7     20

O nó 10 possui:

Left  → 5
Right → 15

O nó 5 possui:

Left  → 3
Right → 7

Já o nó 3 não possui filhos.

Uma implementação simples seria:

class TreeNode {
  value: number;
  left: TreeNode | null;
  right: TreeNode | null;

  constructor(value: number) {
    this.value = value;
    this.left = null;
    this.right = null;
  }
}

Podemos criar uma árvore:

const root = new TreeNode(10);

root.left = new TreeNode(5);
root.right = new TreeNode(15);

root.left.left = new TreeNode(3);
root.left.right = new TreeNode(7);

root.right.right = new TreeNode(20);

Visualmente:

        10
       /  \
      5    15
     / \     \
    3   7     20

4. O que é Tree Traversal?

Tree Traversal significa percorrer os nós de uma árvore seguindo uma determinada ordem.

Por exemplo:

        10
       /  \
      5    15
     / \     \
    3   7     20

Podemos visitar:

10 → 5 → 3 → 7 → 15 → 20

Ou:

3 → 5 → 7 → 10 → 15 → 20

Ou ainda:

3 → 7 → 5 → 20 → 15 → 10

A ordem depende do algoritmo utilizado.


5. DFS e BFS

Existem duas grandes categorias de Tree Traversal.

Tree Traversal
│
├── DFS
│
└── BFS

DFS significa:

Depth-First Search

Busca em profundidade.

A ideia é:

Ir o mais fundo possível antes de voltar.

BFS significa:

Breadth-First Search

Busca em largura.

A ideia é:

Visitar os nós por nível.


6. DFS — Depth-First Search

Imagine:

        10
       /  \
      5    15
     / \     \
    3   7     20

Com DFS, podemos começar no 10.

Depois ir para:

5

Depois:

3

Chegamos ao final daquele caminho.

Então voltamos:

5

E visitamos:

7

Depois voltamos para:

10

E seguimos para:

15

Depois:

20

O conceito é:

10
 ↓
5
 ↓
3
 ↓
volta
 ↓
7
 ↓
volta
 ↓
15
 ↓
20

DFS normalmente utiliza:

  • Recursão
  • Stack

7. Preorder Traversal

No Preorder, a ordem é:

Root
Left
Right

Ou:

Root → Left → Right

Para:

        10
       /  \
      5    15
     / \     \
    3   7     20

O percurso será:

10 → 5 → 3 → 7 → 15 → 20

Primeiro visitamos:

10

Depois percorremos a subárvore esquerda:

5 → 3 → 7

Depois a direita:

15 → 20

8. Implementando Preorder

function preorder(
  root: TreeNode | null
): number[] {
  if (root === null) {
    return [];
  }

  const result: number[] = [];

  function traverse(node: TreeNode | null) {
    if (node === null) {
      return;
    }

    result.push(node.value);

    traverse(node.left);

    traverse(node.right);
  }

  traverse(root);

  return result;
}

Resultado:

[10, 5, 3, 7, 15, 20]

A ordem é:

10
 ↓
5
 ↓
3
 ↓
7
 ↓
15
 ↓
20

9. Inorder Traversal

No Inorder, a ordem é:

Left
Root
Right

Ou:

Left → Root → Right

Na mesma árvore:

        10
       /  \
      5    15
     / \     \
    3   7     20

O resultado será:

3 → 5 → 7 → 10 → 15 → 20

Observe que os valores estão ordenados.

Isso acontece porque essa árvore é uma Binary Search Tree, ou BST.


10. Implementando Inorder

function inorder(
  root: TreeNode | null
): number[] {
  if (root === null) {
    return [];
  }

  const result: number[] = [];

  function traverse(node: TreeNode | null) {
    if (node === null) {
      return;
    }

    traverse(node.left);

    result.push(node.value);

    traverse(node.right);
  }

  traverse(root);

  return result;
}

Resultado:

[3, 5, 7, 10, 15, 20]

A ordem:

Left
  ↓
Root
  ↓
Right

11. Por que Inorder é importante?

Em uma Binary Search Tree, os valores menores ficam à esquerda e os maiores ficam à direita.

Por exemplo:

        10
       /  \
      5    15
     / \     \
    3   7     20

Ao fazer:

Left → Root → Right

obtemos:

3 → 5 → 7 → 10 → 15 → 20

Ou seja:

Array ordenado

Por isso, o Inorder Traversal é frequentemente utilizado para:

  • Obter valores de uma BST em ordem crescente
  • Validar estruturas de BST
  • Encontrar valores em ordem
  • Processar dados ordenados

12. Postorder Traversal

No Postorder, a ordem é:

Left
Right
Root

Ou:

Left → Right → Root

Para:

        10
       /  \
      5    15
     / \     \
    3   7     20

O resultado será:

3 → 7 → 5 → 20 → 15 → 10

Primeiro visitamos os filhos.

Só depois visitamos o pai.


13. Implementando Postorder

function postorder(
  root: TreeNode | null
): number[] {
  if (root === null) {
    return [];
  }

  const result: number[] = [];

  function traverse(node: TreeNode | null) {
    if (node === null) {
      return;
    }

    traverse(node.left);

    traverse(node.right);

    result.push(node.value);
  }

  traverse(root);

  return result;
}

Resultado:

[3, 7, 5, 20, 15, 10]

14. Por que Postorder é útil?

Postorder é especialmente útil quando precisamos processar os filhos antes do pai.

Um exemplo clássico é excluir uma árvore.

Imagine:

        A
       / \
      B   C

Não podemos remover A primeiro se ainda precisamos acessar:

B
C

Então fazemos:

B
C
A

Primeiro removemos os filhos.

Depois o pai.

Esse padrão aparece em:

  • Exclusão de árvores
  • Avaliação de expressões
  • Processamento de dependências
  • Cálculos recursivos
  • Compiladores

15. Comparando DFS

Para:

        10
       /  \
      5    15
     / \     \
    3   7     20

Temos:

Preorder

Root → Left → Right

10 → 5 → 3 → 7 → 15 → 20

Inorder

Left → Root → Right

3 → 5 → 7 → 10 → 15 → 20

Postorder

Left → Right → Root

3 → 7 → 5 → 20 → 15 → 10

Uma maneira fácil de memorizar:

Preorder

ROOT aparece primeiro.


Inorder

ROOT aparece no meio.


Postorder

ROOT aparece por último.

16. BFS — Breadth-First Search

Agora vamos conhecer o BFS.

Em vez de ir até o final de um caminho, visitamos os nós por nível.

Temos:

        10
       /  \
      5    15
     / \     \
    3   7     20

Primeiro nível:

10

Segundo nível:

5 → 15

Terceiro nível:

3 → 7 → 20

Resultado:

10 → 5 → 15 → 3 → 7 → 20

Esse tipo de percurso é chamado de:

Level Order Traversal


17. Implementando BFS

Para BFS normalmente utilizamos uma fila:

Queue

A ideia:

function levelOrder(
  root: TreeNode | null
): number[] {
  if (root === null) {
    return [];
  }

  const result: number[] = [];
  const queue: TreeNode[] = [root];

  while (queue.length > 0) {
    const node = queue.shift()!;

    result.push(node.value);

    if (node.left) {
      queue.push(node.left);
    }

    if (node.right) {
      queue.push(node.right);
    }
  }

  return result;
}

Resultado:

[10, 5, 15, 3, 7, 20]

18. Como o BFS funciona?

Começamos:

Queue:

[10]

Retiramos 10.

Adicionamos:

5
15

Agora:

Queue:

[5, 15]

Retiramos 5.

Adicionamos:

3
7

Agora:

Queue:

[15, 3, 7]

Retiramos 15.

Adicionamos:

20

Agora:

Queue:

[3, 7, 20]

Visitamos:

3
7
20

Resultado final:

10 → 5 → 15 → 3 → 7 → 20

19. DFS vs BFS

Podemos visualizar:

DFS

        10
       ↓
       5
       ↓
       3
       ↓
       7
       ↓
       15
       ↓
       20

A ideia é:

Profundidade primeiro.

Já o BFS:

        10
         ↓
      5     15
       ↓   ↓
      3  7 20

A ideia é:

Nível por nível.

20. Quando usar DFS?

DFS é uma boa escolha quando precisamos:

  • Explorar toda a árvore
  • Procurar um caminho
  • Resolver problemas recursivos
  • Processar subárvores
  • Calcular propriedades de nós
  • Trabalhar com profundidade

Por exemplo:

Qual é a altura máxima da árvore?

Podemos explorar recursivamente cada subárvore.

function maxDepth(
  root: TreeNode | null
): number {
  if (root === null) {
    return 0;
  }

  const leftDepth = maxDepth(root.left);
  const rightDepth = maxDepth(root.right);

  return (
    1 +
    Math.max(
      leftDepth,
      rightDepth
    )
  );
}

Para:

        10
       /  \
      5    15
     /       \
    3         20

A altura é:

3

21. Quando usar BFS?

BFS é especialmente interessante quando precisamos encontrar algo pelo menor número de níveis.

Por exemplo:

Qual é a distância mínima entre a raiz e um determinado nó?

Ou:

Qual é o nó mais próximo que satisfaz determinada condição?

Como o BFS visita:

Nível 0
Nível 1
Nível 2
Nível 3

o primeiro momento em que encontramos um nó pode representar o menor número de passos em determinadas estruturas.


22. Exemplo prático: sistema de arquivos

Imagine:

Projeto
├── src
│   ├── components
│   │   └── Button.tsx
│   └── pages
│       └── Home.tsx
├── public
│   └── logo.png
└── package.json

Essa estrutura pode ser representada como uma árvore.

Podemos usar DFS para procurar um arquivo:

Projeto
 ↓
src
 ↓
components
 ↓
Button.tsx

Ou BFS para encontrar arquivos mais próximos da raiz:

Projeto
 ↓
src
public
package.json
 ↓
components
pages
logo.png

A escolha depende do problema.


23. Exemplo prático: DOM

O HTML de uma página também possui uma estrutura hierárquica.

Por exemplo:

<body>
  <main>
    <h1>Meu Site</h1>

    <div>
      <p>Hello World</p>
    </div>
  </main>
</body>

Podemos visualizar:

body
└── main
    ├── h1
    └── div
        └── p

Isso é uma árvore.

Um algoritmo de DFS poderia visitar:

body
main
h1
div
p

Isso é semelhante ao conceito utilizado quando navegamos pelo DOM.


24. Complexidade

Em todos os principais tipos de Tree Traversal, normalmente visitamos cada nó uma vez.

Se a árvore possui:

n

nós:

Time Complexity: O(n)

A complexidade espacial depende do algoritmo e da estrutura da árvore.

Para DFS recursivo:

Space: O(h)

onde h é a altura da árvore.

Para BFS:

Space: O(w)

onde w é a largura máxima de um nível.

Em uma árvore muito desbalanceada, DFS pode ter:

O(n)

de espaço.

Em uma árvore muito larga, BFS também pode chegar a:

O(n)

25. Um detalhe importante sobre DFS recursivo

A implementação recursiva é muito elegante:

function traverse(node) {
  if (!node) {
    return;
  }

  traverse(node.left);
  traverse(node.right);
}

Mas cada chamada recursiva utiliza a Call Stack.

Em árvores extremamente profundas, isso pode causar:

Maximum Call Stack Size Exceeded

Nesses casos, podemos implementar DFS iterativamente utilizando uma pilha:

function preorder(
  root: TreeNode | null
): number[] {
  if (!root) {
    return [];
  }

  const result: number[] = [];
  const stack: TreeNode[] = [root];

  while (stack.length > 0) {
    const node = stack.pop()!;

    result.push(node.value);

    if (node.right) {
      stack.push(node.right);
    }

    if (node.left) {
      stack.push(node.left);
    }
  }

  return result;
}

Colocamos o right antes do left porque a pilha funciona em modo LIFO:

Last In
First Out

Assim, o left será processado primeiro.


26. Resumo dos Traversals

Considere:

        A
       / \
      B   C
     / \
    D   E

Os resultados são:

Preorder

Root → Left → Right

A → B → D → E → C

Inorder

Left → Root → Right

D → B → E → A → C

Postorder

Left → Right → Root

D → E → B → C → A

Level Order

Level by Level

A → B → C → D → E

27. Como memorizar?

Uma forma simples:

PRE

ROOT vem PREviamente
IN

ROOT fica INtermediário
POST

ROOT vem POSTeriormente

Ou simplesmente:

Preorder

ROOT → Left → Right


Inorder

Left → ROOT → Right


Postorder

Left → Right → ROOT

Já o BFS:

Level Order

Nível 1
↓
Nível 2
↓
Nível 3

28. Qual algoritmo escolher?

Podemos pensar assim:

Preciso percorrer uma árvore
            │
            ▼
    Preciso processar por nível?
         /          \
       Sim           Não
        │             │
        ▼             ▼
       BFS           DFS
                      │
          ┌───────────┼───────────┐
          ▼           ▼           ▼
       Preorder    Inorder    Postorder

Preorder

Use quando:

Root → Left → Right

É útil quando o pai precisa ser processado antes dos filhos.


Inorder

Use especialmente em:

Binary Search Tree

para processar os valores em ordem.


Postorder

Use quando:

Filhos → Pai

precisam ser processados nessa ordem.


BFS

Use quando:

Nível por nível

é importante.


Conclusão

Tree Traversal é o conjunto de técnicas utilizadas para percorrer todos os nós de uma árvore.

As duas principais categorias são:

DFS
│
├── Preorder
├── Inorder
└── Postorder

BFS
└── Level Order

No DFS, exploramos a árvore em profundidade.

No BFS, exploramos a árvore nível por nível.

Os três principais tipos de DFS são:

Preorder

Root → Left → Right
Inorder

Left → Root → Right
Postorder

Left → Right → Root

E o BFS mais comum:

Level Order

Nível → Nível → Nível

A principal lição é entender que a mesma árvore pode ser percorrida em diferentes ordens, e a ordem escolhida depende do problema que queremos resolver.

Se você precisa explorar caminhos e subárvores, pense em DFS. Se precisa processar a árvore por níveis ou encontrar algo pela menor distância em níveis, pense em BFS.



Comments

No comments yet.