Em Ciência da Computação, uma árvore binária de busca (ou árvore binária de pesquisa) é uma estrutura de dados de árvore binária baseada em nós, onde todos os nós da subárvore esquerda possuem um valor numérico inferior ao nó raiz e todos os nós da subárvore direita possuem um valor superior ao nó raiz. O objetivo desta árvore é estruturar os dados de forma flexível, permitindo pesquisa binária.

- Nós - são todos os itens guardados na árvore;
- Raiz - é o nó do topo da árvore (no caso da figura acima, a raiz é o nó 8);
- Filhos - são os nós que vem depois dos outros nós (no caso da figura acima, o nó 6 é filho do 3);
- Pais - são os nós que vem antes dos outros nós (no caso da figura acima, o nó 10 é pai do 14);
- Folhas - são os nós que não têm filhos; são os últimos nós da árvore (no caso da figura acima, as folhas são 1, 4, 7 e 13).
A operação de busca em uma árvore binária por um determinado valor, pode ser feita de maneira recursiva ou interativa. (fiz a abordagem recursiva).
A busca inicia-se no nó raiz, se o valor contido na raiz não for o desejado, verificamos se o valor é maior ou menor que o nó raiz. Caso o valor seja menor que o nó raiz, a busca continua pelo seu filho menor, ou seja, pelo filho da esquerda, mas, caso o valor seja maior a busca continua pelo filho da direita, até que se encontre o valor desejado ou a busca chegue em um nó folha (valor não encontrado).
A inserção de um novo valor é praticamente uma busca na árvore pois, precisamos percorrer toda a árvore até chegarmos em um nó folha correspondente. Se o valor a ser inserido for maior que o raiz, seguimos pelo filho da direita, se for menor seguimos pelo filho da esquerda, até chegarmos em um nó que mantenha a ordenação da árvore.
A operação remoção começa a complicar um pouco. Temos 3 casos diferentes:
- Exclusão de um nó folha;
- Exclusão de um nó com 1 filho;
- Exclusão de um nó com 2 filhos;
Para a exclusão de um nó folha, precisamos somente removê-lo da árvore.

Para a exclusão de um nó com 1 filho, o filho apenas sobe para a posição do pai.

Para a remoção de um nó com 2 filhos, temos duas maneiras diferentes de trabalhar:
- Usando o maior nó da sub-árvore à esquerda;
- Usando o menor nó da sub-árvore à direita;
Estas duas maneiras são apenas definições de projeto, possuem a mesma complexidade e tempo de busca.
No exemplo abaixo, para remover o 3 usando a definição do menor nó da sub-árvore à direita, pesquisamos pelo menor nó à partir do 6 que no caso será o 4.

Agora, usando a definição do maior nó da subárvore à esquerda, removeremos o 8, o resultado será o seguinte:

Apresentando alguns códigos, lembrando que ao final desta postagem você poderá fazer o download de um projeto que foi desenvolvido utilizando o Dev-C++, com a linguagem C.
Função Inserir em árvore binária:
- void inserir(tArv *t, int dado){
- int ok;
-
- if (*t == NULL) {
- *t = (tnoarv *) malloc(sizeof(tnoarv));
- if (*t == NULL) return;
- (*t)->esq = NULL;
- (*t)->dir = NULL;
- (*t)->info = dado;
- }
-
- if (dado < (*t)->info) {
- inserir(&((*t)->esq), dado);
- }
- else{
-
- if (dado > (*t)->info) {
- inserir(&((*t)->dir), dado);
- }
- }
- }
void inserir(tArv *t, int dado){
int ok;
// se t aponta para null, a inserção é na raiz...
if (*t == NULL) {
*t = (tnoarv *) malloc(sizeof(tnoarv));
if (*t == NULL) return;
(*t)->esq = NULL;
(*t)->dir = NULL;
(*t)->info = dado;
}
// Se o dado a ser inserido for menor que o nó atual, recursividade à esquerda
if (dado < (*t)->info) {
inserir(&((*t)->esq), dado);
}
else{
// Se o dado a ser inserido for menor que o nó atual, recursividade à direita
if (dado > (*t)->info) {
inserir(&((*t)->dir), dado);
}
}
}
Função remover da árvore binária:
- void remover(tArv *raiz, int valor){
- tArv aux;
- if(!arvore_vazia(*raiz)){
-
- if(valor < (*raiz)->info){
- remover(&((*raiz)->esq), valor);
- }else{
-
- if(valor > (*raiz)->info){
- remover(&((*raiz)->dir), valor);
- }else{
-
- if( !arvore_vazia((*raiz)->esq) && !arvore_vazia((*raiz)->dir) ){
-
-
- aux = minimo((*raiz)->dir);
- (*raiz)->info = (aux->info);
- remover(&(*raiz)->dir, (*raiz)->info);
- }else{
-
-
- aux = *raiz;
-
- if(arvore_vazia((*raiz)->esq)){
-
-
- *raiz = (*raiz)->dir;
- }
- else {
-
-
- *raiz = (*raiz)->esq;
- }
- free(aux);
- }
- }
- }
- }
- }
void remover(tArv *raiz, int valor){
tArv aux;
if(!arvore_vazia(*raiz)){
// se o valor que será removido for menor que o nó atual,
if(valor < (*raiz)->info){
remover(&((*raiz)->esq), valor); // faz recursividade á esquerda
}else{
// se o valor que será removido for menor que o nó atual,
if(valor > (*raiz)->info){
remover(&((*raiz)->dir), valor); // faz recursividade á direita.
}else{ // encontrou
// quando o nó a ser removido for encontrado,
if( !arvore_vazia((*raiz)->esq) && !arvore_vazia((*raiz)->dir) ){
// verificamos se os nós filhos da esquerda e direita não são null.
// se não forem null, buscamos o menor nó a artir do nó da direita.
aux = minimo((*raiz)->dir);
(*raiz)->info = (aux->info);
remover(&(*raiz)->dir, (*raiz)->info);
}else{
// caso os nó da direita e da esqueda, ou somente o da direita,
// precisamos apenas remover
aux = *raiz;
// o nó atual e fazer ajustar os ponteiros
if(arvore_vazia((*raiz)->esq)){
// se o nó da esquerda for vazio
// o nó pai do atual, apontará para o filho da direita do nó atual.
*raiz = (*raiz)->dir;
}
else {
// se o nó da esquerda não for vazio.
// o nó pai do atual, apontará para o filho da esquerda do nó atual.
*raiz = (*raiz)->esq;
}
free(aux);
}
}
}
}
}
Função minimo, retorna o nó com valor minímo:
- tArv minimo(tArv T){
- if(arvore_vazia(T)){
- return NULL;
- }else{
- if( arvore_vazia(T->esq) ){
- return T;
- }else{
- return minimo(T->esq);
- }
- }
- }
tArv minimo(tArv T){// procura o nó com valor mínimo
if(arvore_vazia(T)){
return NULL;
}else{
if( arvore_vazia(T->esq) ){
return T;
}else{
return minimo(T->esq);
}
}
}
Função maximo, retorna o nó com o valor máximo:
- tArv maximo(tArv T){
- if( !arvore_vazia(T) ){
- while( !arvore_vazia(T->dir) ){
- T = T->dir;
- }
- }
- return T;
- }
tArv maximo(tArv T){// procura o nó com valor máximo
if( !arvore_vazia(T) ){
while( !arvore_vazia(T->dir) ){
T = T->dir;
}
}
return T;
}
Função para buscar elemento na árvore binária:
-
-
-
- tArv busca_elemento(tArv t, int dado){
-
- tArv achou;
- if (arvore_vazia(t)) return NULL;
- if (t->info == dado) return t;
- achou = busca_elemento(t->esq, dado);
- if (arvore_vazia(achou))
- achou = busca_elemento(t->dir, dado);
- return achou;
- }
//=======================================================================
// A função pesquisa nos nós da árvore o valor passado como parâmetro,
// caso o valor esteja na árvore, ela retorna este nó que está o valor.
tArv busca_elemento(tArv t, int dado){
tArv achou;
if (arvore_vazia(t)) return NULL;
if (t->info == dado) return t;
achou = busca_elemento(t->esq, dado);
if (arvore_vazia(achou))
achou = busca_elemento(t->dir, dado);
return achou;
}
Caso você queira realizar o download deste projeto (árvore binária em C) -> Árvore.zip (13.07 kb).
Fico por aqui e até a próxima.
Lança o teu cuidado sobre o SENHOR, e ele te susterá; não permitirá jamais que o justo seja abalado. (Salmos 55:22)
Tags: arvore, arvore binaria de busca, arvore binaria de pesquisa, c, nós, raiz