Árvore binária Índice Definições para árvores binárias | Definições em teoria dos grafos | Inserção | Percursos em árvore | Contagem dos nós | Transformação de uma árvore n-ária | Métodos para representação de árvores binárias | Ver também | Menu de navegação

Estruturas de dados


estrutura de dadosrecursivaárvoreárvores binárias de buscateoria dos grafosfunção recursivaCJavaC#algoritmoalgoritmoJavaalgoritmoCalgoritmoJavaalgoritmoalgoritmoJavaClinguagens de programaçãoHeapspascalCapontadores






Uma simples árvore binária de tamanho 9 e altura 3, com um nó raiz de valor 2. A árvore acima não está balanceada (elemento 5 possui 2 filhos a direita e nenhum a esquerda), nem está ordenada - notar que não é uma árvore binária de procura.


Uma árvore binária é uma estrutura de dados caracterizada por:


  • Ou não tem elemento algum (árvore vazia).

  • Ou tem um elemento distinto, denominado raiz, com dois ponteiros para duas estruturas diferentes, denominadas sub-árvore esquerda e sub-árvore direita.

Perceba que a definição é recursiva e, devido a isso, muitas operações sobre árvores binárias utilizam recursão. É o tipo de árvore mais utilizado na computação. A principal utilização de árvores binárias são as árvores binárias de busca




Índice





  • 1 Definições para árvores binárias


  • 2 Definições em teoria dos grafos


  • 3 Inserção


  • 4 Percursos em árvore

    • 4.1 Ordem simétrica


    • 4.2 Pré-ordem


    • 4.3 Pós-ordem



  • 5 Contagem dos nós


  • 6 Transformação de uma árvore n-ária


  • 7 Métodos para representação de árvores binárias


  • 8 Ver também




Definições para árvores binárias |


Os nós de uma árvore binária possuem graus zero, um ou dois. Um nó de grau zero é denominado folha.


Em uma árvore binária, por definição, cada nó poderá ter até duas folhas, sendo que ela se compara com a ABB (árvore binária de busca), apesar de não ter a propriedade da mesma ("na abb, existe uma regra na inserção").


A profundidade de um nó é a distância deste nó até a raiz. Um conjunto de nós com a mesma profundidade é denominado nível da árvore. A maior profundidade de um nó, é a altura da árvore.


Uma árvore "estritamente binária" é uma árvore na qual todo nó tem zero ou duas folhas.


Existem autores, porém, que adotam essa definição para o termo quase completa, e utilizam o termo completa apenas para árvores em que todos os níveis têm o máximo número de elementos.



Definições em teoria dos grafos |


Em teoria dos grafos, uma árvore binária é definida como um grafo acíclico, conexo, dirigido e que cada nó não tem grau maior que 2. Assim sendo, só existe um caminho entre dois nós distintos.


E cada ramo da árvore é um vértice dirigido, sem peso, que parte do pai e vai para o filho.



Inserção |


O algoritmo da inserção em árvores binárias são facilmente implementadas através de função recursiva.


Algoritmo da inserção em C:


 void inserir(struct No **pRaiz, int numero)
if(*pRaiz == NULL)
* pRaiz = (struct No *) malloc(sizeof(struct No));
(*pRaiz)pEsquerda = NULL;
(*pRaiz)pDireita = NULL;
(*pRaiz)numero = numero;
else
if(numero <(*pRaiz)numero)
inserir(&(*pRaiz)pEsquerda, numero));
else
inserir(&(*pRaiz)pDireita, numero));



Algoritmo da inserção em Java:


public class Arvore 

public No raiz;

class No
Integer valor;
No filhoEsquerdo;
No filhoDireito;

public No(Integer valor)
this.valor = valor;



public No inserir(Integer valor)
return this.inserir(new No(valor), raiz);


private No inserir(No novo, No anterior)
if (raiz == null)
raiz = novo;
return raiz;


if (anterior != null)
if (novo.valor <= anterior.valor)
anterior.filhoEsquerdo = this.inserir(novo, anterior.filhoEsquerdo);
else if (novo.valor > anterior.valor)
anterior.filhoDireito = this.inserir(novo, anterior.filhoDireito);
else
return null;

else
anterior = novo;


return anterior;



Algoritmo da inserção em C#:


public class Node
public Node(int value)
Value = value;

public decimal Value get; set;
public Node Esq get; set;
public Node Dir get; set;


class Tree
private Node root;
public Tree(int value)
root = new Node(value);

public void Add(int value)
Add(null, value);

protected virtual void Add(Node node, int value)
if (node == null)
node = root;
if (value < node.Value)
if (node.Esq == null)
node.Esq = new Node(value);
else
Add(node.Esq, value);
else
if (node.Dir == null)
node.Dir = new Node(value);
else
Add(node.Dir, value);





Percursos em árvore |


Existem três tipos de percursos: Percurso em ordem simétrica(em-ordem), pré-ordem e pós-ordem.



Ordem simétrica |


O algoritmo recursivo desse percurso em C é:


 void emOrdem(struct No *pNo) 
if(pNo != NULL)
emOrdem(pNopEsquerda);
visita(pNo);
emOrdem(pNopDireita);



O algoritmo recursivo desse percurso em Java é:


public void emOrdem(No no) 
if (no != null)
emOrdem(no.filhoEsquerdo);
System.out.println(no.valor);
emOrdem(no.filhoDireito);



Para a árvore acima, o percurso seria: 2, 7, 5, 6, 11, 2, 5, 4, 9. Veja a linha de execução:


  • emOrdem(2→esq)
    • emOrdem(7→esq)
      • emOrdem(2→esq)

      • visita(2)

      • emOrdem(2→dir)


    • visita(7)

    • emOrdem(7→dir)
      • emOrdem(6→esq)
        • emOrdem(5→esq)

        • visita(5)

        • emOrdem(5→dir)


      • visita(6)

      • emOrdem(6→dir)
        • emOrdem(11→esq)

        • visita(11)

        • emOrdem(11→dir)




  • visita(2)

  • emOrdem(2→dir)
    • emOrdem(5→esq)

    • visita(5)

    • emOrdem(5→dir)
      • emOrdem(9→esq)
        • emOrdem(4→esq)

        • visita(4)

        • emOrdem(4→dir)


      • visita(9)

      • emOrdem(9→dir)




Pré-ordem |


O algoritmo recursivo desse percurso em C é:


 void preOrdem(Struct No *pNo)
if(pNo != NULL)
visita(pNo);
preOrdem(pNopEsquerda);
preOrdem(pNopDireita);



O algoritmo recursivo desse percurso em Java é:


public void preOrdem(No no) 
if (no != null)
System.out.println(no.valor);
preOrdem(no.filhoEsquerdo);
preOrdem(no.filhoDireito);



Para a árvore acima, o percurso seria: 2, 7, 2, 6, 5, 11, 5, 9 e 4. Veja a linha de execução:


  • visita(2)

  • preOrdem(2→esq)
    • visita(7)

    • preOrdem(7→esq)
      • visita(2)

      • preOrdem(2→esq)

      • preOrdem(2→dir)


    • preOrdem(7→dir)
      • visita(6)

      • preOrdem(6→esq)
        • visita(5)

        • preOrdem(5→esq)

        • preOrdem(5→dir)


      • preOrdem(6→dir)
        • visita(11)

        • preOrdem(11→esq)

        • preOrdem(11→dir)




  • preOrdem(2→dir)
    • visita(5)

    • preOrdem(5→esq)

    • preOrdem(5→dir)
      • visita(9)

      • preOrdem(9→esq)
        • visita(4)

        • preOrdem(4→esq)

        • preOrdem(4→dir)


      • preOrdem(9→dir)




Pós-ordem |


O algoritmo recursivo desse percurso em C é:


 void posOrdem(Struct No *pNo)
if(pNo != NULL)
posOrdem(pNopEsquerda);
posOrdem(pNopDireita);
visita(pNo);



O algoritmo recursivo desse percurso em Java é:


public void posOrdem(No no) 
if (no != null)
posOrdem(no.filhoEsquerdo);
posOrdem(no.filhoDireito);
System.out.println(no.valor);



Para a árvore acima, o percurso seria: 2, 5, 11, 6, 7, 4, 9, 5 e 2. Veja a linha de execução:


  • posOrdem(2→esq)
    • posOrdem(7→esq)
      • posOrdem(2→esq)

      • posOrdem(2→dir)

      • visita(2)


    • posOrdem(7→dir)
      • posOrdem(6→esq)
        • posOrdem(5→esq)

        • posOrdem(5→dir)

        • visita(5)


      • posOrdem(6→dir)
        • posOrdem(11→esq)

        • posOrdem(11→dir)

        • visita(11)


      • visita(6)


    • visita(7)


  • posOrdem(2→dir)
    • posOrdem(5→esq)

    • posOrdem(5→dir)
      • posOrdem(9→esq)
        • posOrdem(4→esq)

        • posOrdem(4→dir)

        • visita(4)


      • posOrdem(9→dir)

      • visita(9)


    • visita(5)


  • visita(2)


Contagem dos nós |


Uma árvore binária que tenha todas as suas folhas completas possui o número de nós (N)displaystyle (N), em relação ao total de níveis da árvore (n)displaystyle (n), dado pela seguinte expressão:


Nº de nós (N)=2n−1displaystyle textNº de nós (N)=2^n-1

Exemplos a partir de programação


Em Java


public int contagem(No no)
return (no == null) ? 0 : 1 + contagem(no.filhoEsquerdo) + contagem(no.filhoDireito);


Em C


 int contagem(struct node *tree) 
return (tree != NULL) ? (contagem(tree->left) + contagem(tree->right) + 1) : 0;



Transformação de uma árvore n-ária |


Uma árvore n-ária qualquer (árvore cujos nós possuem graus menores ou iguais a n) podem ser representados por uma árvore binária. Um exemplo dessa transformação pode ser vista na imagem abaixo:


Um exemplo de conversão de uma árvore n-ária para uma árvore binária.


Métodos para representação de árvores binárias |


Uma das maneiras mais simples de representar árvores binárias em linguagens de programação é por meio de arranjos unidimensionais (vetores). Caso a raiz esteja na posição zero, dado um nó de índice i qualquer, os seus filhos terão índices 2i+1displaystyle 2i+1 e 2i+2displaystyle 2i+2 e o seu pai terá índice piso((i - 1)/2). Caso a raiz esteja na posição um, os filhos terão índices 2idisplaystyle 2i e 2i+1displaystyle 2i+1 e o pai terá índice piso(i/2). Essa implementação é utilizada para representar árvores completas ou quase completas. Heaps, que são árvores binárias quase completas são implementadas na forma de um vetor de uma maneira bastante eficiente.


Apesar da simplicidade, essa representação requer uma grande quantidade de memória contígua para o armazenamento de árvores grandes, o crescimento desta é díficil de implementar e manter e pode haver grande quantidade de desperdício de memória.



Uma pequena árvore binária com raiz na posição 0, representada como um vetor.


Em uma linguagem que possua suporte a estruturas e referências (por exemplo pascal e C), as árvores podem ser implementadas a partir de nós, com um, ou mais, campos para a(s) informação(ões) principal(is) e dois campos apontadores especiais, denominados esquerda e direita, que fazem referência às sub-árvores esquerda e direita, respectivamente. Algumas vezes, há um apontador para o pai. Em um nó do tipo folha, os campos apontadores possuem valores especiais (nil em Pascal e "NULL" em C).



Ver também |


  • Árvore AVL

  • Árvore B

  • Árvore B+

  • Árvore binária de busca

  • Árvore binária com costura


Popular posts from this blog

Are there any AGPL-style licences that require source code modifications to be public? Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern) Announcing the arrival of Valued Associate #679: Cesar Manara Unicorn Meta Zoo #1: Why another podcast?Force derivative works to be publicAre there any GPL like licenses for Apple App Store?Do you violate the GPL if you provide source code that cannot be compiled?GPL - is it distribution to use libraries in an appliance loaned to customers?Distributing App for free which uses GPL'ed codeModifications of server software under GPL, with web/CLI interfaceDoes using an AGPLv3-licensed library prevent me from dual-licensing my own source code?Can I publish only select code under GPLv3 from a private project?Is there published precedent regarding the scope of covered work that uses AGPL software?If MIT licensed code links to GPL licensed code what should be the license of the resulting binary program?If I use a public API endpoint that has its source code licensed under AGPL in my app, do I need to disclose my source?

2013 GY136 Descoberta | Órbita | Referências Menu de navegação«List Of Centaurs and Scattered-Disk Objects»«List of Known Trans-Neptunian Objects»

Button changing it's text & action. Good or terrible? The 2019 Stack Overflow Developer Survey Results Are Inchanging text on user mouseoverShould certain functions be “hard to find” for powerusers to discover?Custom liking function - do I need user login?Using different checkbox style for different checkbox behaviorBest Practices: Save and Exit in Software UIInteraction with remote validated formMore efficient UI to progress the user through a complicated process?Designing a popup notice for a gameShould bulk-editing functions be hidden until a table row is selected, or is there a better solution?Is it bad practice to disable (replace) the context menu?