Você está na página 1de 15

rvores Binrias de Busca

MAC122 Marcilio Revisado 31Out113

rvores Binrias de Busca


0. Um breve comentrio sobre os algoritmos de busca em tabelas
De uma maneira geral, realizam-se operaes de busca, insero e remoo de elementos
numa tabela.
A busca sequencial tradicional O(N). No eficiente, mas permite inseres e remoes
rpidas. A insero pode ser feita no final da tabela, pois a ordem no precisa ser
preservada. A remoo pode ser feita simplesmente pela substituio do elemento removido
por um valor especial que no faz parte da tabela. Entretanto, importante notar que uma
insero ou remoo quase sempre precedida por uma busca.
A busca binria O(logN). muito eficiente, mas a tabela deve estar em ordem crescente
ou decrescente. Portanto inseres e remoes so muito ineficientes. Para inserir ou
remover mantendo a ordem, necessrio deslocar parte da tabela.
A busca em tabela hash sequencial depende da funo de hash e da variedade dos dados.
Uma vantagem que permite insero de novos elementos. A remoo no permitida,
pois altera a estrutura da tabela.
No caso geral, pouco se pode afirmar sobre a eficincia do hash em tabela sequencial. No
pior caso O(N).
Outro inconveniente que no hash a tabela ocupa mais espao que a quantidade de
elementos.
No caso do hash com lista ligada, insero e remoo so facilitadas com a ocupao ideal
de memria. Entretanto no pior caso continua sendo O(N).
A situao ideal seria um algoritmo que tivesse a eficincia da busca binria O(logN),
permitisse inseres e remoes rpidas e que a tabela ocupasse somente o espao
necessrio.
Isso conseguido quando a tabela tem uma estrutura em rvore de busca.
Dentre os vrios tipos de rvores de busca, as mais simples so as rvores binrias de busca
que veremos a seguir.
1. rvores binrias
Chamamos de rvores Binrias (AB), um conjunto finito T de ns ou vrtices, onde existe
um n especial chamado raiz e os restantes podem ser divididos em dois subconjuntos
disjuntos, chamados de sub-rvores esquerda e direita que tambm so rvores Binrias.
Em particular T pode ser vazio.

rvores Binrias de Busca


MAC122 - Marcilio

rvores Binrias de Busca


MAC122 Marcilio Revisado 31Out113

Exemplos:

Cada n numa AB pode ter ento 0, 1 ou 2 filhos. Portanto, existe uma hierarquia entre os
ns. Com exceo da raiz, todo n tem um n pai.
Dizemos que o nvel da raiz 1 e que o nvel de um n o nvel de seu pai mais 1. A altura
de uma AB o maior dos nveis de seus ns.
Dizemos que um n folha da AB se no tem filhos.
2. rvores binrias de busca
Seja T uma AB. Se v um n de T, chamamos de info(v) a informao armazenada
em v.
Chamamos T de rvore Binria de Busca (ABB) quando:
Se v1 pertencente sub-rvore esquerda de v ento info(v1) < info(v).
Se v2 pertencente sub-rvore direita de v ento info(v2) > info(v).
Exemplos:

rvores Binrias de Busca


MAC122 - Marcilio

rvores Binrias de Busca


MAC122 Marcilio Revisado 31Out113

Os exemplos acima mostram que podemos ter vrias ABB com os mesmos elementos.
Conforme veremos frente o objetivo sempre termos uma ABB de menor altura. Nesse
sentido a primeira ABB melhor que a segunda.
Um exemplo de AB de muitos nveis e poucos elementos:

O exemplo abaixo no ABB. O 2 est direita do 4.

Uma ABB pode ter elementos repetidos. Podemos coloc-los na sub-rvore esquerda ou
direita. Nos algoritmos abaixo vamos consider-los preferencialmente direita. Podemos
coloc-los tambm tanto esquerda quanto direita, mas neste caso os algoritmos para
se procurar todos os elementos v onde info(v) so iguais a um determinado valor, ficam
mais complicados.

rvores Binrias de Busca


MAC122 - Marcilio

rvores Binrias de Busca


MAC122 Marcilio Revisado 31Out113

3. rvores binrias como listas ligadas


Podemos representar uma ABB com uma lista ligada, onde cada elemento tem os seguintes
campos:

info
eprox

dprox

info - campo de informao


eprox - apontador para a sub-rvore esquerda
dprox - apontador para a sub-rvore direita
Como simplificao, vamos supor que o campo de info um int (lembre-se que pode
ser qualquer coisa: vrias variveis simples, vetores, structs, etc...) e definir as
structs correspondentes:
struct item {
int info;
struct item * eprox, * dprox;
}
struct item raiz;
Uma outra forma com typedef:
typedef struct item * link;
struct item {
int info;
link eprox, dprox;
}
link raiz;

4. Algoritmos de busca
A1
Funo que procura um determinado elemento numa ABB.
Chamada: k = busca(raiz, x). Retorna x se encontrou elemento com info
igual a x, ou -1 se no encontrou.
int busca(link h, int v) {
int t;
if (h == NULL) return -1;
t = h->info;
if (t == v) return t;
rvores Binrias de Busca
MAC122 - Marcilio

rvores Binrias de Busca


MAC122 Marcilio Revisado 31Out113

if (v < t) return busca(h->eprox), v);


else return busca(h->dprox, v)
}
A2
Outra verso retornando ponteiro para o elemento encontrado ou NULL se no encontrou.
link busca(link h, int v) {
int t;
if (h == NULL) return NULL;
t = h->info;
if (v == t) return h;
if (v < t) return busca(h->eprox, v);
else return busca(h->dprox, v);
}
Complexidade da busca
No pior caso, o nmero de comparaes igual ao nmero de ns da rvore, no caso em
que os elementos da rvore formam uma lista ligada num s sentido. Portanto a
complexidade O(N).
A complexidade a altura da rvore, portanto conveniente que a rvore tenha sempre
altura mnima.
A rvore que possui tal propriedade uma AB dita completa (todos os ns com filhos
vazios esto no ltimo ou penltimo nvel). Neste caso a complexidade O(log N) ou seja:
Se T uma AB completa com n>0 ns ento T possui altura h mnima e h = 1+log2 n
(considerando o valor de log2 n truncado).
O lema a seguir d a relao entre altura e nmero de ns de uma AB completa:
Lema:
Seja T uma AB completa com N ns e altura h.
Ento 2(h-1) N 2h - 1.
Prova:
Se a AB completa possui apenas 1 n no seu nvel inferior ento N = 2(h-1).
Se a AB completa est cheia N = 2h - 1.
A3
Vejamos agora a verso no recursiva para a busca. A chamada buscaNR(raiz, x)
procura elemento com info igual a x devolvendo um ponteiro para o mesmo ou NULL
caso no encontre:
link buscaNR(link h, int v){
link p; int t;
rvores Binrias de Busca
MAC122 - Marcilio

rvores Binrias de Busca


MAC122 Marcilio Revisado 31Out113

p = h;
while (p != NULL) {
t = p->info;
if (v == t) return p;
if (v < t) p = p->eprox;
else p = p->dprox;
}
return NULL;
}
5. Outros algoritmos
A4
A funo a seguir conta o nmero de ns de uma AB com determinado valor de info. A
chamada conta(raiz, x) devolve o nmero de elementos iguais a x da AB apontada
por raiz.
int conta(link h, int c) {
int a;
if (h == NULL) return 0;
if (c == h->info) a = 1 else a = 0;
return a + conta(h->eprox,c) + conta(h->dprox,c);
}
Estamos supondo neste caso que os elementos iguais podem estar direita ou esquerda.
O algoritmo acima percorre toda a AB.
Refaa, supondo que se houver elementos iguais, estaro direita.
A5
Transformar um vetor de n elementos, j ordenado, numa ABB mais ou menos equilibrada.
A idia sempre pegar um elemento mdio como raiz da sub-rvore. Para facilitar as
chamadas recursivas vamos fazer a funo de modo que a mesma se aplique a qualquer
trecho contguo do vetor. Assim, a chamada raiz = monta(a, 0, n-1) faz a
montagem da rvore com os elementos a[0] at a[n-1], devolvendo um ponteiro para a
raiz da rvore. A chamada raiz = monta(a, n1, n2) faz o mesmo para os
elementos a[n1] at a[n2].
link monta(int a[], int left, int right) {
int m = (left+right)/2; /* escolhe elemento mdio */
link h;
if (left > right) return NULL; /* sem elementos */
/* insere o novo elemento */
h = (link) malloc (sizeof(struct item));
h->info = a[m];
/* preenche os ponteiros */
h->eprox = monta(a, left, m-1);
rvores Binrias de Busca
MAC122 - Marcilio

rvores Binrias de Busca


MAC122 Marcilio Revisado 31Out113

h->dprox = monta(a, m+1, right);


return h;
}
A6
Funo que conta o nmero de ns de uma AB. A chamada conta(raiz), devolve o
nmero de ns da AB apontada por raiz.
int contaNN(link h) {
if (h == NULL) return 0;
return 1 + contaNN(h->eprox) + contaNN(h->dprox);
}
Exerccios
Baseado na soluo acima escreva as seguintes funes:
1. Funo conta1(link h) que conta o nmero de folhas de uma AB cuja raiz h.
2. Funo conta2(link h) que conta o nmero de ns com pelo menos um filho de
uma AB cuja raiz h.
3. Funo conta3(link h,int x) que conta nmero de elementos com info>= x
de uma ABB cuja raiz h.
4. Idem ao problema A4 acima, considerando uma ABB onde elementos iguais ficam
direita.
6. Algoritmos de insero numa ABB
Um novo elemento inserido sempre como uma folha de uma ABB. necessrio descer na
ABB at encontrar o n que ser o pai deste novo n.
A6
Uma verso no recursiva para a insero numa ABB. Supondo raiz como uma varivel
global.
void insere(int x) {
link p, q;
int z;
/* verifica rvore vazia */
if (raiz == NULL)
{raiz = new(x, NULL, NULL); return;}
/* procurar lugar e inserir */
p = raiz; q = p;
while (q != NULL) {
z = q->info;
if (x < z) {p = q; q = q->eprox;}
else {p = q; q = q->dprox;}
}
rvores Binrias de Busca
MAC122 - Marcilio

rvores Binrias de Busca


MAC122 Marcilio Revisado 31Out113

/* p o pai do n a ser inserido, mas temos que verificar


novamente se insere a esquerda ou direita de p */
q = new(x, NULL, NULL);
if (x < p->info) p->eprox = q;
else p->dprox = q;
return;
}
link new(int x, link left, link right) {
/* cria novo n com info x e links left e right */
link q;
q = (link) malloc (sizeof(struct item));
q->info = x; q->eprox = left; q->dprox = right;
return q;
}
Observe que se o elemento j estiver na ABB, ser inserido na parte direita.

A6.1
Vejamos uma variao da funo anterior usando ponteiro para ponteiro:
void insere(int x) {
link p, *t;
int z;
/* verifica rvore vazia */
if (raiz == NULL)
{raiz = new(x, NULL, NULL); return;}
/* procurar lugar e inserir */
p = raiz;
while (p != NULL) {
z = p->info;
if (x < z) {t = &(p->eprox); p = p->eprox;}
else {t = &(p->dprox); p = p->dprox;}
}
/* t apontador para o pai do n a ser inserido */
*t = new(x, NULL, NULL);
return;
}

rvores Binrias de Busca


MAC122 - Marcilio

rvores Binrias de Busca


MAC122 Marcilio Revisado 31Out113

A6.2
Outra variao, supondo agora que a raiz da ABB seja um parmetro de entrada e sada da
funo. Note que a raiz pode ser alterada pela funo quando a mesma vazia, por isso o
parmetro tem que vir por endereo:
void insere(link *r, int x) {
link p, q;
int z;
/* verifica rvore vazia */
if (*r == NULL)
{*r = new(x, NULL, NULL); return;}
/* procurar lugar e inserir */
p = *r; q = p;
while (q != NULL) {
z = q->info;
if (x < z) {p = q; q = q->eprox;}
else {p = q; q = q->dprox;}
}
/* p o pai do n a ser inserido */
q = new(x, NULL, NULL);
if (x < p->info) p->eprox = q;
else p->dprox = q;
return;
}

A6.3
A verso recursiva abaixo devolve a cada chamada, o prprio n se diferente de NULL ou
um apontador para um novo n que ser inserido. A chamada raiz = insere(raiz,
x) insere elemento com info igual a x na ABB apontada por raiz. A atribuio
raiz porque a rvore pode estar vazia.
link insere(link h, int x) {
int z;
/* verifica rvore vazia */
if (h == NULL) return new(x, NULL, NULL);
/* procurar lugar e inserir */
z = h->info;
if (x < z) h->eprox = insere(h->eprox, x)
else h->dprox = insere(h->dprox, x)
/* devolve o prprio n para no alterar os ponteiros */
return h;
}

rvores Binrias de Busca


MAC122 - Marcilio

rvores Binrias de Busca


MAC122 Marcilio Revisado 31Out113

Complexidade da construo de uma ABB por inseres sucessivas


Para inserir elemento necessrio achar o seu lugar. Portanto a complexidade a mesma da
busca.
Complexidade da construo de uma ABB por inseres sucessivas
Usando-se o algoritmo acima e inserindo-se um a um, podemos no pior caso (ABB com um
s elemento por nvel - tudo esquerda, tudo direita ou ziguezague) chegar a:
1+2+3+...+n = n.(n+1)/2 acessos para construir toda a rvore. Portanto O(n2).
Se os elementos a serem inseridos estiverem ordenados, usando o algoritmo A5, a
complexidade O(N). Mas necessrio ordenar antes.
Entretanto, supondo a rvore completa, para inserir o novo elemento (folha da rvore)
teremos que percorrer os nveis que sero 1+log n. Portanto temos um algoritmo
O(log n).
7. Algoritmo de remoo numa ABB
A remoo um pouco mais complexa que a busca ou insero. O problema da remoo
fsica de um n que necessrio encontrar outro n para substituir o removido, caso o n
a ser removido tenha filhos.

rvores Binrias de Busca


MAC122 - Marcilio

rvores Binrias de Busca


MAC122 Marcilio Revisado 31Out113

Dois casos a considerar:


1) O n a ser removido no tem filhos esquerdo e/ou direito.
remover

remover

substituto

no h substituto
substituto

remover

s alterar o ponteiro para o n a substituir e remover fisicamente o n. Se no h filhos,


basta mudar o ponteiro do pai para NULL.
2) O n a ser removido tem filhos direito e esquerdo:
remover

Novo link
Novo link

Candidatos a substitutos

rvores Binrias de Busca


MAC122 - Marcilio

rvores Binrias de Busca


MAC122 Marcilio Revisado 31Out113

Os candidatos a substituto so obtidos percorrendo-se a ABB:


Um esquerda e tudo a direita at achar n com dprox NULL . Ou um a direita e tudo
esquerda at achar n com eprox NULL.
Alm de alterar o ponteiro para o n que vais substituir, necessrio mover o contedo
deste n para o n a remover e fisicamente remover o substituto. O pai do substituto
assume os seus filhos.
Nos algoritmos de remoo, vamos usar ponteiros para ponteiros. S recordando, considere
a declarao:
link *pp;
**pp do tipo struct item
*pp do tipo ponteiro para struct item
pp do tipo ponteiro para ponteiro para struct item
A7
O primeiro passo procurar o n a remover. Em seguida verificar os dois casos:
A funo abaixo procura n com info x, devolvendo ponteiro para o ponteiro deste n,
isto , devolvendo o ponteiro para o ponteiro que ser alterado para eliminar este elemento:
link *search(link *r, int x) {
link *q;
q = r; /* inicia q com a raiz */
/* procura na ABB */
while (*q != NULL) {
if ((*q)->info == x) return q;
/* esquerda ou direita */
if (x < (*q)->info) q = &((*q)->eprox);
else q = &((*q)->dprox)
}
/* se chegou aqui porque no encontrou o x e q aponta
para um ponteiro que NULL ou ainda para um ponteiro
aonde ser inserido um elemento */
return q;
}
A8
Vamos agora remoo usando search acima. A funo abaixo remove um n cujo
ponteiro apontado por *pp.
void delnode(link *pp) {
link p, *qq, q;
/* se *pp NULL nada a fazer */
if (*pp == NULL) return;
rvores Binrias de Busca
MAC122 - Marcilio

rvores Binrias de Busca


MAC122 Marcilio Revisado 31Out113

/* verifica qual o caso - sem filho esquerdo ou direito */


p = *pp;
if (p->dprox) == NULL) {
/* muda o pai e libera */
*pp = p->eprox;
free(p);
}
else if (p->eprox == NULL) {
/* muda pai e libera */
*pp = p->dprox;
free(p);
}
else {/* um para esquerda e tudo direita */
qq = &(p->eprox);
/* procura primeiro dprox NULL */
while ((*qq)->dprox != NULL)
qq = &((*qq)->dprox;
/* achamos o substituto */
q = *qq;
/* altera ponteiro do pai de q */
*qq = q->eprox;
/* move as info */
p->info = q->info;
free(q); // libera o tal n
return;
}
}
Para eliminar um n fazemos a seguinte seqncia:
link *t;
...
/* elimina n com info igual a x */
t = search(&raiz, x);
delnode(t);
/* outra forma */
delnode(search(&raiz, x));
Complexidade da remoo
O pior caso quando a rvore tem um s elemento por nvel.
Como search O(n) e delnode O(n), o total O(n).

rvores Binrias de Busca


MAC122 - Marcilio

rvores Binrias de Busca


MAC122 Marcilio Revisado 31Out113

A9
Outra soluo para a insero usando search. A chamada seria insert(&raiz, x).
void insert(link *r, int x) {
link *qq;
qq = search(r, x);
if (*qq == NULL) {
/* no encontrou ento pode inserir */
/* note que qq aponta para o pai */
*qq = (link) malloc (sizeof(struct item));
(*qq)->info = x;
(*qq)->eprox = (*qq)->dprox = NULL;
}
}

8. rvores Binrias de Busca Completas


J vimos que o problema das ABB que ela pode ficar desbalanceada com a insero e
remoo de novos elementos. A situao ideal em uma ABB que ela se j completa
(como o menor nmero possvel de nveis).
Como seria possvel mant-la completa?
Isso pode ser feito de 2 maneiras:
1) Toda vez que um elemento inserido ou removido, rearranja-se a ABB para a
mesma continue completa.
2) Inserir e remover elementos da maneira usual e de tempos em tempos executar um
algoritmo que reconstri a ABB deixando-a completa.
Existem vrios algoritmos com esses objetivos. No sero vistos neste curso.
Apenas citamos 2 tipos mais comuns abaixo. Nessas ABBs, os algoritmos de insero e
remoo j o fazem deixando a ABB completa ou balanceada.
Com uma ABB completa, chegamos a situao ideal de busca, pois temos uma algoritmo
equivalente ao da busca binria O(log N), em uma tabela que permite inseres rpidas
(O(log N)) e remoes to rpidas quanto possvel (O(N) no pior caso). Alm disso, s usa
a quantidade de memria necessria.
9. Outras rvores Binrias
Apenas citando os tipos mais importantes:
9.1 rvores Binrias de Busca AVL (Adelson-Vesky e Landis (1962))
Cada n mantm uma informao adicional, chamada fator de balanceamento que indica a
diferena de altura entre as sub-rvores esquerda e direita.
As operaes de insero e remoo mantm o fator de balanceamento entre -1 e +1.

9.2 rvores Binrias de Busca Rubro-Negras


rvores Binrias de Busca
MAC122 - Marcilio

rvores Binrias de Busca


MAC122 Marcilio Revisado 31Out113

uma ABB com as seguintes propriedades:


1.
2.
3.
4.

Todo n vermelho ou preto.


Toda folha preta.
Se um n vermelho ento seus filhos so pretos.
Todo caminho da raiz at qualquer folha tem sempre o mesmo nmero de ns
pretos.

Com essas propriedades, possvel manter a ABB mais ou menos balanceada aps
inseres e remoes.
10. Outras rvores de Busca
rvores de Busca, no precisam ser necessariamente binrias. Podemos construir rvores
com vrios elementos em cada n (n-rias). Cada elemento possui um ramo esquerdo
(menores) e um ramo direito (maiores ou iguais).
Este o caso das chamadas B-rvores. Tambm no sero vistos neste curso.
So usadas principalmente para arquivos em banco de dados.
No caso de arquivos interessa muito diminuir a quantidade de acessos a disco. Assim, a
cada leitura, vrios ns estaro disponveis na memria. A quantidade de nveis da rvore
diminui e, portanto a quantidade de acessos para se procurar um elemento.

rvores Binrias de Busca


MAC122 - Marcilio