Princípios de Desenvolvimento de Algoritmos MAC122pmiranda/mac122_2s11/aulas/arvbin.pdf ·...
Transcript of Princípios de Desenvolvimento de Algoritmos MAC122pmiranda/mac122_2s11/aulas/arvbin.pdf ·...
Princípios de Desenvolvimento de Algoritmos
MAC122Prof. Dr. Paulo Miranda
IME-USP
Árvores Binárias
Árvores
● Árvores representam estruturas de dados caracterizadas por uma relação hierárquica da informação:
– árvore genealógica,
– organização hierárquica de uma empresa,
– classificação biológica de espécies.
● Em particular, uma árvore binária T é caracterizada por:
● Ou T não tem elemento algum (árvore vazia).
● Ou T consiste de um elemento distinto, denominado raiz, e de duas árvores binárias disjuntas, denominadas sub-árvore esquerda e sub-árvore direita de T.
Árvores binárias● Convenções e terminologia:
– Grau de um nó: número de sub-árvores não vazias deste nó.
● Nós internos (grau maior que zero, 1 ou 2).● Nós terminais ou folhas (grau igual a zero).
– Relações de parentesco:
● Pai, filhos, irmãos, tio, antepassado e descendente.
A
B C
D E F
G H
h
nível 2
nível 1
nível 3
nível 4
typedef struct _RegArvBin{ TipoInfo info; struct _RegArvBin *esq; struct _RegArvBin *dir;} RegArvBin;
typedef RegArvBin* ArvBin;
Árvores binárias● Definição típica da estrutura utilizada.
RegArvBin *AlocaRegArvBin(){ RegArvBin* q; q = (RegArvBin*)calloc(1, sizeof(RegArvBin)); if(q==NULL) exit(-1); return q;}
void InsereArvBinEsq(ArvBin p, TipoInfo x){
RegArvBin *q;
q = AlocaRegArvBin(); q->info = x; q->esq = p->esq; q->dir = NULL; p->esq = q;}
Árvores binárias● Procedimento de inserção:
– O novo nó é inserido à esquerda do nó indicado por p.
– A sub-árvore esquerda de p torna-se a sub-árvore esquerda do novo nó.
void PreOrdem(ArvBin p){ if(p!=NULL){ ImprimeInfo(p->info); PreOrdem(p->esq); PreOrdem(p->dir); }}
Árvores binárias● Percursos (travessia) em profundidade.
A
B C
D E F
G H
p
Saída: A,B,D,E,G,C,F,H
void PosOrdem(ArvBin p){ if(p!=NULL){ PosOrdem(p->esq); PosOrdem(p->dir); ImprimeInfo(p->info); }}
Árvores binárias● Percursos (travessia) em profundidade.
A
B C
D E F
G H
p
Saída: D,G,E,B,H,F,C,A
void InOrdem(ArvBin p){ if(p!=NULL){ InOrdem(p->esq); ImprimeInfo(p->info); InOrdem(p->dir); }}
Árvores binárias● Percursos (travessia) em profundidade.
A
B C
D E F
G H
p
Saída: D,B,G,E,A,F,H,C
void Largura(ArvBin p){ RegArvBin *q; Fila f = CriaFila(); InsereFila(&f, p); do{ q = RemoveFila(&f); if(q!=NULL){ ImprimeInfo(q->info); InsereFila(&f, q->esq); InsereFila(&f, q->dir); } }while(!FilaVazia(f)); LiberaFila(f);}
Árvores binárias● Percurso em largura.
A
B C
D E F
G H
p
Saída: A,B,C,D,E,F,G,H
void DescricaoParentetica(ArvBin p){ printf("("); if(p!=NULL){ DescricaoParentetica(p->esq); ImprimeInfo(p->info); DescricaoParentetica(p->dir); } printf(")");}
Árvores binárias● Descrição parentética.
A
B C
D E F
G H
p
Saída: (((()D())B((()G())E()))A((()F(()H()))C()))
ArvBin LerDescrParentetica(char *descr){ ArvBin p; int i=0; p = LerDescrParenteticaAux(descr, &i); return p;}
Árvores binárias● Descrição parentética (leitura).
int main(){ char descr[]="(((()D())B((()G())E()))A((()F(()H()))C()))"; ArvBin p; p = LerDescrParentetica(descr);
...
return 0;}
ArvBin LerDescrParenteticaAux(char *descr, int *i){ ArvBin e,d; RegArvBin *q; char c; if(descr[*i]!='(') Erro(); (*i)++; if(descr[*i]==')'){ (*i)++; q = NULL; } else{ e = LerDescrParenteticaAux(descr, i); c = descr[*i]; if(c<'A' || c>'Z') Erro(); (*i)++; d = LerDescrParenteticaAux(descr, i); if(descr[*i]!=')') Erro(); (*i)++; q = AlocaRegArvBin(); q->info = c; q->esq = e; q->dir = d; } return q;}
Árvores binárias
typedef enum chamadas {chamada1,chamada2} chamada;
typedef struct _elemPilha{ chamada ch; RegArvBin *q;} ElemPilha;
typedef enum Acoes {entrada,retorno,saida} Acao;
Árvores binárias● Percursos em profundidade com pilha explícita.
– Definição da estrutura de pilha utilizada.
void PreOrdem_PilhaExpl(ArvBin p){ Pilha s; ElemPilha ep; Acao acao;
s = CriaPilha(); acao = entrada; do{ switch(acao){ case entrada: if(p==NULL) acao = retorno; else{ ImprimeInfo(p->info);
ep.q = p; ep.ch = chamada1; Empilha(s, ep); p = p->esq; } break; case retorno: if(PilhaVazia(s)) acao = saida;
Pilha explícita else{ ep = Desempilha(s); p = ep.q; switch(ep.ch){ case chamada1:
ep.q = p; ep.ch = chamada2; Empilha(s, ep); p = p->dir; acao = entrada; break; case chamada2:
break; } } break; case saida: break; } }while(acao!=saida); LiberaPilha(s);}
void PosOrdem_PilhaExpl(ArvBin p){ Pilha s; ElemPilha ep; Acao acao;
s = CriaPilha(); acao = entrada; do{ switch(acao){ case entrada: if(p==NULL) acao = retorno; else{
ep.q = p; ep.ch = chamada1; Empilha(s, ep); p = p->esq; } break; case retorno: if(PilhaVazia(s)) acao = saida;
Pilha explícita else{ ep = Desempilha(s); p = ep.q; switch(ep.ch){ case chamada1:
ep.q = p; ep.ch = chamada2; Empilha(s, ep); p = p->dir; acao = entrada; break; case chamada2: ImprimeInfo(p->info); break; } } break; case saida: break; } }while(acao!=saida); LiberaPilha(s);}
void InOrdem_PilhaExpl(ArvBin p){ Pilha s; ElemPilha ep; Acao acao;
s = CriaPilha(); acao = entrada; do{ switch(acao){ case entrada: if(p==NULL) acao = retorno; else{
ep.q = p; ep.ch = chamada1; Empilha(s, ep); p = p->esq; } break; case retorno: if(PilhaVazia(s)) acao = saida;
Pilha explícita else{ ep = Desempilha(s); p = ep.q; switch(ep.ch){ case chamada1: ImprimeInfo(p->info); ep.q = p; ep.ch = chamada2; Empilha(s, ep); p = p->dir; acao = entrada; break; case chamada2:
break; } } break; case saida: break; } }while(acao!=saida); LiberaPilha(s);}
Árvores binárias● Percurso em Pré-ordem com pilha explícita (otimizado).
void PreOrdemPilha(ArvBin p){ RegArvBin *q; Pilha s;
s = CriaPilha(); Empilha(s, p); do{ q = Desempilha(s); if(q!=NULL){ ImprimeInfo(q->info); Empilha(s, q->dir); Empilha(s, q->esq); } }while(!PilhaVazia(s)); LiberaPilha(s);}
Árvores binárias● Percurso em Pós-ordem com pilha explícita (otimizado).
void PosOrdemPilha(ArvBin p){ RegArvBin *ultimo; RegArvBin *q = p; Pilha s = CriaPilha(); bool sobe;
do{ while(q!=NULL){ Empilha(s, q); q = q->esq; }
sobe = true; ultimo = NULL;
while(sobe && !PilhaVazia(s)){ q = Desempilha(s); if(q->dir!=ultimo){ Empilha(s, q); q = q->dir; sobe = false; }
else{ ImprimeInfo(q->info); ultimo = q; } }
}while(!PilhaVazia(s)); LiberaPilha(s);}
Árvore binária de busca● Uma árvore binária de busca é uma árvore onde para
cada nó são válidas as propriedades:
– o seu valor segue o valor de todos os nós da sub-árvore esquerda,
– e precede todos os valores dos nós da sub-árvore direita.
void BuscaInsere(ArvBin *p, TipoInfo x, bool *pertence){ ArvBin q = *p; if(q==NULL){ *pertence = false; *p = AlocaRegArvBin(); (*p)->esq = NULL; (*p)->dir = NULL; (*p)->info = x; } else{ if(x==q->info) *pertence = true; else if(x<q->info) BuscaInsere(&q->esq, x, pertence); else BuscaInsere(&q->dir, x, pertence); }}
Árvore binária de busca● Procedimento de busca & inserção:
Árvore binária de busca● Procedimento de busca & inserção:
● Número de operações executadas é proporcional, no pior caso, à profundidade da árvore.
– Ou seja, entre ⌈log2(n+1)⌉ e n, para árvores com n nós.
– Em MAC323 sao vistas formas de manter sempre as árvores de busca “balanceadas”.
Árvore binária completa● Dizemos que uma árvore binária de altura h é completa
se ela contiver o número máximo de nós (2 – 1).h
A
B
E
J K
D
H I
C
G
N O
F
L M
1
2 3
4 5 6 7
8 9 10 11 12 13 14 15
A B C D E F G H I J K L M N O1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Pai(i) = ⌊ i/2⌋ , FilhoEsq(i) = 2i, FilhoDir(i) = 2i + 1