Você está na página 1de 34

Estrutura de Dados – Árvore Binária de Busca

Prof. Lincoln Faria


lfaria@unicarioca.edu.br
Aula de hoje

Árvore Binária de Busca:


1.Definição
2.Aplicação
3.Balanceadas
4.Implementação:
a)Criação
b)Inserção
c)Busca
d)Remoção
Prof. Lincoln Faria - lfaria@unicarioca.edu.br 2
Definição

Seja S = {s1, … ,sn } o conjunto de chaves satisfazendo s1< … <


sn. Uma árvore binária de busca B é uma árvore com as
seguintes propriedades:

i) B possui n nós, onde cada nó v corresponde a uma chave


distinta sj pertencente à S e possui como rótulo o valor r(v) = sj.

ii) Seja um nó v de B. Seja também ve, pertencente à subárvore


esquerda de v. Então:
r(ve) < r(v)
Analogamente, se vd pertence à subárvore direita de v,
r(vd) > r(v)

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 3


Definição

Exemplo:

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 4


Aplicação

A aplicação principal é a busca binária em


um estrutura de dados encadeada. Visto
que a busca é uma operação muito
executada, pois até as operações de
inserção e remoção dependem de uma
busca, é muito importante e desejado um
bom desempenho em tal operação.

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 5


Aplicação

Em uma árvore binária de busca de 10.000


nós, por exemplo, o número médio de
comparações em uma busca é de apenas
14, quando tal árvore se encontra
devidamente balanceada.

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 6


Balanceada

Dependendo da sequência de inserção dos


elementos (nós) e também das operações de
inserção e remoção rotineiras, uma árvore binária
pode se tornar desbalanceada (ou seja, para algum
nó, uma diferença muito grande de altura entre as
subárvores direita e esquerda), afetando o
desempenho das operações sobre a mesma.
Exemplos de
árvores
desbalanceadas

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 7


Balanceada

Existem vários tipos de árvores de busca


binária balanceadas que diferem entre si pelas
condições de balanceamento. Algumas delas
são:
➢Árvore AVL
➢Árvore 2 – 3 – 4
➢Árvore rubro-negra

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 8


Balanceada

Por exemplo, uma árvore é do tipo AVL


quando, para qualquer nó, as alturas de suas
duas subárvores, esquerda e direita, diferem
em módulo de até uma unidade.

Exemplo de árvore AVL

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 9


Balanceada

Uma solução para manter uma árvore


balanceada, mesmo depois de algumas
inserções e remoções, é executar rotações
nas árvores (onde a posição de raiz é
assumida por outro nó). Nas árvores AVLs,
tais rotações são executadas através da
análise dos fatores de balanceamento (FB).

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 10


Balanceada

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 11


Implementação: criação

typedef struct funcionario{


int matricula; //usado como chave de cada nó
char nome[50];
float salario; Arquivo: arvore_binaria_busca.h
} Funcionario;

typedef struct arvore Arvore;

Arvore* arvore_cria(Funcionario f);


int arvore_no_de_nos(Arvore *raiz);

int arvore_inserir(Arvore *raiz, Funcionario f);


int arvore_busca(Arvore *raiz, int chave);
int arvore_remover_elemento_especif(Arvore *raiz, int chave);
void arvore_imprimir(Arvore *raiz);

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 12


Implementação: criação

#include "arvore_binaria_busca.h"

#include <stdlib.h>
#include <stdio.h>
#include <math.h> Arquivo: arvore_binaria_busca.c
struct arvore{
Funcionario dados;
struct arvore *esq;
struct arvore *dir;
};
typedef struct arvore No; /* usado quando se referir a um nó da árvore*/

Arvore* arvore_cria(Funcionario f){

Arvore *raiz=(Arvore*)malloc(sizeof(Arvore));
raiz->dados = f;
raiz->dir = NULL;
raiz->esq = NULL;

return raiz;
}

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 13


Implementação: criação
#include <stdio.h>
#include <locale.h>
Arquivo: main.c
#include "arvore_binaria_busca.h"

int main(void)
{
setlocale(LC_ALL, "Portuguese");

Arvore *raiz = NULL;


Funcionario f;
int opcao;

do{ /*Operações disponíveis na estrutura de dados*/


puts("Inserir na árvore : 1");
puts("Remover da árvore : 2");
puts("Buscar na árvore : 3");
puts("Imprimir árvore : 4");
puts("Sair : -1");
puts("Qual é a sua escolha?");
scanf("%d",&opcao);

switch(opcao){
case 1:
printf("Entre com a matrícula do funcionário: "); scanf("%d",&f.matricula);
printf("Entre o nome do funcionário: "); scanf("%s", f.nome);
printf("Entre o salário do funcionário: "); scanf("%f", &f.salario);
if(raiz==NULL)
raiz = arvore_cria(f);
else{
arvore_inserir(raiz, f);
}
Break;
.
.
.
Prof. Lincoln Faria - lfaria@unicarioca.edu.br 14
Implementação: inserção

A inserção de um novo nó em uma árvore


binária de busca, não pode transgredir a
definição, ou seja, após a inserção de um novo
nó devemos ter ainda a seguinte propriedade:
para qualquer nó, sua chave é maior do que a
chave de todos os nós de sua subárvore
esquerda e menor do que a chave de todos os
nós de sua subárvore direita.

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 15


Implementação: inserção

Exemplo:

Considere que iremos inserir os seguintes


elementos, nessa ordem:

50 60 30 40 70 20

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 16


Implementação: inserção

Exemplo:

50 60 30 40 70 20
Nó Raiz

50

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 17


Implementação: inserção

Exemplo:

50 60 30 40 70 20
Nó Raiz
60>50=SIM
50
A direita

60

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 18


Implementação: inserção

Exemplo:

50 60 30 40 70 20
Nó Raiz
30>50=Não
50 A esquerda

30 60

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 19


Implementação: inserção

Exemplo:

50 60 30 40 70 20
Nó Raiz
40>50=Não
50 40>30=Sim
A direita

30 60

40

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 20


Implementação: inserção

Exemplo:

50 60 30 40 70 20
Nó Raiz

50

70>50=Sim
30 60
70>60=Sim
A direita

40 70

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 21


Implementação: inserção

Exemplo:

50 60 30 40 70 20
Nó Raiz
20>50=Não
50 20>30=Não
A esquerda

30 60

20 40 70

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 22


Implementação: inserção
int arvore_inserir(Arvore *raiz, Funcionario f){

No *novo_no = (No*)malloc(sizeof(No)); /* Memória para um novo nó foi alocado*/


if(novo_no==NULL) return 0;
novo_no->dados=f; /*O novo nó foi preenchido com as informações do funcionário*/
novo_no->esq=NULL; /*seu ponteiro esquerdo aponta para NULL*/
novo_no->dir = NULL; /*seu ponteiro direito aponta para NULL*/

No *no_atual=raiz; /*começando percorrer a árvore pela raiz*/


No *no_anterior=NULL; /*para não se perder a referência do pai do nó atual*/
while(no_atual!=NULL){ /*Enquanto não chegar em uma folha*/
no_anterior = no_atual; /*guardando a referência do nó pai*/
if(f.matricula == no_atual->dados.matricula){
free(novo_no);
puts("Este funcionário já existe"); Arquivo: arvore_binaria_busca.c
return 0;
}
if(f.matricula>no_atual->dados.matricula)
no_atual = no_atual->dir; /*desloca nó atual para a subárvore direita*/
else
no_atual = no_atual->esq; /*desloca nó atual para a subárvore esqueda*/
}/*neste momento se chegou a uma folha*/
if(f.matricula > no_anterior->dados.matricula)
no_anterior->dir = novo_no; /*o novo no será o filho direito da folha */
else
no_anterior->esq = novo_no;/*o novo no será o filho esquerdo da folha */

return 1; /*verdadeiro*/
}
Prof. Lincoln Faria - lfaria@unicarioca.edu.br 23
Implementação: inserção
#include <stdio.h>
#include <locale.h>
Arquivo: main.c
#include "arvore_binaria_busca.h"

int main(void)
{
setlocale(LC_ALL, "Portuguese");

Arvore *raiz = NULL;


Funcionario f;
.
.
.
switch(opcao){
case 1:
printf("Entre com a matrícula do funcionário: "); scanf("%d",&f.matricula);
printf("Entre o nome do funcionário: "); scanf("%s", f.nome);
printf("Entre o salário do funcionário: "); scanf("%f", &f.salario);
if(raiz==NULL)
raiz = arvore_cria(f);
else{
arvore_inserir(raiz, f);
}
break;
.
.
.
Prof. Lincoln Faria - lfaria@unicarioca.edu.br 24
Implementação: busca

Arquivo: arvore_binaria_busca.c

int arvore_busca(Arvore *raiz, int chave){


if(raiz == NULL){ /*Se a raiz for NULL ou se chegou em uma folha*/
puts("Funcionário NÃO encontrado!");
return 0;
}
if(chave == raiz->dados.matricula){
puts("Funcionário encontrado:");
printf("Matrícula= %d, Nome= %s, Salário= %.2f \n",raiz->dados.matricula,
raiz->dados.nome, raiz->dados.salario);
return 1; /*elemento encontrado*/
}
if(chave > raiz->dados.matricula)
arvore_busca(raiz->dir, chave); /*chamada recursiva com subárvore direita*/
else
arvore_busca(raiz->esq, chave); /*chamada recursiva com subárvore esquerda*/
return 0;
}

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 25


Implementação: busca

. Arquivo: main.c
.
.

case 3:
printf("Entre com a matrícula a ser buscada: ");
int matricula;
scanf("%d",&matricula);
arvore_busca(raiz,matricula);
break;

.
.
.

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 26


Implementação: remoção

Na remoção existem 3 casos:

➢Remover um nó folha
➢Remover um nó com 1 filho
➢Remover um nó com 2 filhos

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 27


Implementação: remoção

A remoção de um nó em uma árvore binária


de busca, assim como na inserção, não pode
transgredir a definição, ou seja, após a
inserção de um novo nó devemos ter ainda a
seguinte propriedade: para qualquer nó, sua
chave é maior do que a chave de todos os nós
de sua subárvore esquerda e menor do que a
chave de todos os nós de sua subárvore
direita.

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 28


Implementação: remoção

Remover um nó folha

20 20

15 25 15 25

10 18 40 10 18 40

13
NULL

Basta fazer o pai da folha apontar para NULL.


Prof. Lincoln Faria - lfaria@unicarioca.edu.br 29
Implementação: remoção

Remover um nó com 1 filho

20 20

15 25 15

10 18 40 10 18 40

13 13

Basta fazer o seu pai apontar para o seu filho.

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 30


Implementação: remoção

Remover um nó com 2 filhos


20 18

15 25 15 25

10 18 40 10 40

13 13

Basta mover a folha mais a direita da subárvore


esquerda para a posição do nó removido.
Prof. Lincoln Faria - lfaria@unicarioca.edu.br 31
Exercício

Construa uma árvore binária de busca


considerando a seguinte ordem de inserção
dos elementos, representados pelas
respectivas chaves:

20 – 15 – 25 – 10 – 18 – 13 – 40

Em seguida, escreva sequência de nós


visitados, percorrendo a árvore formada em
pré-ordem.

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 32


Exercício

Resposta: 20

15 25

10 18 40

13

Percurso em pré-ordem:

20 – 15 – 10 – 13 – 18 – 25 – 40

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 33


FIM

Considerações finais

Prof. Lincoln Faria - lfaria@unicarioca.edu.br 34

Você também pode gostar