UNIVERSIDADE FEDERAL DE MINAS GERAIS Árvores Cristiano Arbex Valle Vinicius Fernandes dos Santos
COMPUTER SCIENCE Árvores Organizam dados de forma hierárquica – Acontecem com frequência na natureza Fáceis de representar e manipular com computadores – Úteis para várias tarefas
COMPUTER SCIENCE Exemplos Árvores de decisão (inteligência artificial) Possibilidade de jogar tênis hoje:
COMPUTER SCIENCE Exemplos Árvore de Huffman (compressão de dados) – “this is an example of a huffman tree” # ' 7 a4 e4 f3 h2 i2 m2 n2 s2 t2 l1 o1 p1 r1 u1 x1 ASCII dec binbits total
COMPUTER SCIENCE Exemplos Árvore de Huffman (compressão de dados) – “this is an example of a huffman tree” # ' 7 a4 e4 f3 h2 i2 m2 n2 s2 t2 l1 o1 p1 r1 u1 x1 ASCII dec binbits total bits
COMPUTER SCIENCE Exemplos Árvore de Huffman (compressão de dados) Exemplos: a = 010 x = 10010
COMPUTER SCIENCE Exemplos Árvore de Huffman (compressão de dados) – “this is an example of a huffman tree” # ' 7 a4 e4 f3 h2 i2 m2 n2 s2 t2 l1 o1 p1 r1 u1 x1 ASCII dec binbits total HUFFMAN bin total bits bits
COMPUTER SCIENCE Exemplos Árvore de Huffman (compressão de dados) – “this is an example of a huffman tree” # ' 7 a4 e4 f3 h2 i2 m2 n2 s2 t2 l1 o1 p1 r1 u1 x1 ASCII dec binbits total HUFFMAN binbits total bits135 bits
COMPUTER SCIENCE Árvores em AEDS2 Árvores digitais (tries)Árvore binária de busca (ABB)
COMPUTER SCIENCE Terminologia
COMPUTER SCIENCE Raiz Terminologia
COMPUTER SCIENCE Folhas Terminologia
COMPUTER SCIENCE Vértices internos Terminologia
COMPUTER SCIENCE Filhos Pai Terminologia
COMPUTER SCIENCE Descendentes Terminologia
COMPUTER SCIENCE Ancestrais Terminologia
COMPUTER SCIENCE Irmãos Terminologia
COMPUTER SCIENCE Níveis Terminologia
COMPUTER SCIENCE Caminho Terminologia
COMPUTER SCIENCE TAD árvore binária Cada vértice tem no máximo dois filhos – (obs: a árvore ao lado não impõe nenhuma ordenação dos vértices) Operações – Inserção – Remoção – Caminhamento
COMPUTER SCIENCE Árvore binária: Impl. com Arranjos Filhos de i – Esquerda: 2i + 1 – Direita: 2i + 2 Pai de i:
COMPUTER SCIENCE Árvore binária: Impl. com Arranjos Vantagens – Representação compacta – Localidade de referência Desvantagens – Desperdício de espaço em árvores incompletas – Inserção e remoção podem exigir deslocamentos
COMPUTER SCIENCE Árvore binária: Impl. com Apontadores typedef int TChave; typedef struct { TChave Chave; // outros componentes } TItem; typedef struct Vertice { TItem Item; Apontador Esq, Dir; } TVertice; typedef struct Vertice * Apontador; typedef Apontador TArvore;
COMPUTER SCIENCE TAD árvore binária de busca (ABB) Cada vértice tem no máximo dois filhos – (obs: a árvore ao lado impõe uma ordenação particular aos vértices) R ED R ED <<
COMPUTER SCIENCE TAD árvore binária de busca (ABB) Cada vértice tem no máximo dois filhos – (obs: a árvore ao lado impõe uma ordenação particular aos nodos) Operações – Inserção – Remoção – Caminhamento – Pesquisa – Ordenação
COMPUTER SCIENCE ABB: inserção void Insere(TItem x, Apontador *p) – Observação: p passado por referência (endereço contido em *p vai ser alterado dentro de Insere ) – Ideia: a partir do vértice apontado por *p, podemos encontrar o ponto de inserção para o registro x *p é nulo? – Ponto de inserção! x < registro atual? – Caminhamos para a esquerda x > registro atual? – Caminhamos para a direita x == registro atual? – Vértice já existe
COMPUTER SCIENCE ABB: inserção TArvore a; // Apontador TItem x; x.Chave = 8; Insere(x, &a); *p
COMPUTER SCIENCE ABB: inserção TArvore a; // Apontador TItem x; x.Chave = 8; Insere(x, &a); *p 8
COMPUTER SCIENCE ABB: inserção TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 4; Insere(x, &a); *p
COMPUTER SCIENCE ABB: inserção TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 4; Insere(x, &a); *p
COMPUTER SCIENCE ABB: inserção TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 4; Insere(x, &a); *p
COMPUTER SCIENCE ABB: inserção TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 4; Insere(x, &a); *p
COMPUTER SCIENCE ABB: inserção TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 4; Insere(x, &a); *p
COMPUTER SCIENCE ABB: inserção TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 4; Insere(x, &a); *p 4
COMPUTER SCIENCE ABB: inserção void Insere(TItem x, Apontador *p) { if (*p == NULL) { *p = malloc(sizeof(TVertice)); (*p)->Item = x; (*p)->Esq = NULL; (*p)->Dir = NULL; } else if (x.Chave Item.Chave) Insere(x, &(*p)->Esq); else if (x.Chave > (*p)->Item.Chave) Insere(x, &(*p)->Dir); else printf("ERRO: Item já existe\n"); }
COMPUTER SCIENCE ABB: remoção void Retira(TItem x, Apontador *p) – Observação: p passado por referência (endereço contido em *p vai ser alterado dentro de Retira ) – Ideia: a partir do vértice apontado por *p, podemos encontrar o ponto de remoção para o registro x *p é nulo? – Nada a fazer x < registro atual? – Caminhamos para a esquerda x > registro atual? – Caminhamos para a direita x == registro atual? – Encontramos vértice a ser removido
COMPUTER SCIENCE ABB: remoção Como remover um vértice? – Tem zero filhos (i.e., vértice folha)? Simplesmente remova – Tem um filho? Substitua pelo filho – Tem dois filhos? Copie item do antecessor na sub-árvore esquerda (antecessor central) e remova o antecessor, ou Copie item do sucessor na sub-árvore direita (sucessor central) e remova sucessor
COMPUTER SCIENCE ABB: remoção (caso 1) TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 4; Retira(x, &a); *p 4
COMPUTER SCIENCE ABB: remoção (caso 1) TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 4; Retira(x, &a); *p
COMPUTER SCIENCE ABB: remoção (caso 2) TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 14; Retira(x, &a); *p 4
COMPUTER SCIENCE ABB: remoção (caso 2) TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 14; Retira(x, &a); *p 4
COMPUTER SCIENCE ABB: remoção (caso 3) TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 8; Retira(x, &a); *p 4
COMPUTER SCIENCE ABB: remoção (caso 3) TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 8; Retira(x, &a); *p 4 ant
COMPUTER SCIENCE ABB: remoção (caso 3) TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 8; Retira(x, &a); *p 4 ant
COMPUTER SCIENCE ABB: remoção (caso 3) TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 8; Retira(x, &a); *p 4 ant
COMPUTER SCIENCE ABB: remoção (caso 3) TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 8; Retira(x, &a); *p 4 suc
COMPUTER SCIENCE ABB: remoção (caso 3) TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 8; Retira(x, &a); *p 4 suc
COMPUTER SCIENCE ABB: remoção (caso 3) TArvore a; // Apontador... // várias inserções TItem x; x.Chave = 8; Retira(x, &a); *p 4
COMPUTER SCIENCE ABB: remoção void Retira(TItem x, Apontador *p) { Apontador Aux; if (*p == NULL) printf("ERRO: Item não encontrado\n"); else if (x.Chave Item.Chave) Retira(x, &(*p)->Esq); else if (x.Chave > (*p)->Item.Chave) Retira(x, &(*p)->Dir);...
COMPUTER SCIENCE ABB: remoção... else if ((*p)->Dir == NULL) { Aux = *p; *p = (*p)->Esq; free(Aux); } else if ((*p)->Esq == NULL) { Aux = *p; *p = (*p)->Dir; free(Aux); } else if (rand() % < 50) Antecessor(*p, &(*p)->Esq); else Sucessor(*p, &(*p)->Dir); } Caso 1 + Caso 2 Caso 3
COMPUTER SCIENCE ABB: remoção void Antecessor(Apontador q, Apontador *r) { if ((*r)->Dir != NULL) { Antecessor(q, &(*r)->Dir); return; } Apontador aux; q->Item = (*r)->Item; aux = *r; *r = (*r)->Esq; free(aux); }
COMPUTER SCIENCE ABB: remoção void Sucessor(Apontador q, Apontador *r) { if ((*r)->Esq != NULL) { Sucessor(q, &(*r)->Esq); return; } Apontador aux; q->Item = (*r)->Item; aux = *r; *r = (*r)->Dir; free(aux); }
COMPUTER SCIENCE Caminhamento Diversas formas de percorrer ou caminhar em uma árvore listando seus vértice, as principais: Pré-ordem (pré-fixada) Central (infixada) Pós-ordem (pós-fixada) Para todas elas: – Se T é uma árvore nula, então a lista é nula – Se T é uma árvore de um único vértice então a lista contém apenas este vértice
COMPUTER SCIENCE Caminhamento pré-ordem Ideia: – Imprime – Visita sub-árvore esquerda em pré-ordem – Visita sub-árvore direita em pré-ordem void PreOrdem(Apontador p) { if (p == null) return; printf("%d\n", p->Chave); PreOrdem(p->Esq); PreOrdem(p->Dir); }
COMPUTER SCIENCE ABC 5 void PreOrdem(Apontador p) { if (p == null) return; printf("%d\n", p->Chave); PreOrdem(p->Esq); PreOrdem(p->Dir); } Caminhamento pré-ordem 1
COMPUTER SCIENCE ABC 5 void PreOrdem(Apontador p) { if (p == null) return; printf("%d\n", p->Chave); PreOrdem(p->Esq); PreOrdem(p->Dir); } Caminhamento pré-ordem 1 2
COMPUTER SCIENCE ABC 5 void PreOrdem(Apontador p) { if (p == null) return; printf("%d\n", p->Chave); PreOrdem(p->Esq); PreOrdem(p->Dir); } Caminhamento pré-ordem 1 2 4
COMPUTER SCIENCE ABC 5 void PreOrdem(Apontador p) { if (p == null) return; printf("%d\n", p->Chave); PreOrdem(p->Esq); PreOrdem(p->Dir); } Caminhamento pré-ordem
COMPUTER SCIENCE ABC 5 void PreOrdem(Apontador p) { if (p == null) return; printf("%d\n", p->Chave); PreOrdem(p->Esq); PreOrdem(p->Dir); } Caminhamento pré-ordem A
COMPUTER SCIENCE ABC 5 void PreOrdem(Apontador p) { if (p == null) return; printf("%d\n", p->Chave); PreOrdem(p->Esq); PreOrdem(p->Dir); } Caminhamento pré-ordem A B
COMPUTER SCIENCE ABC 5 void PreOrdem(Apontador p) { if (p == null) return; printf("%d\n", p->Chave); PreOrdem(p->Esq); PreOrdem(p->Dir); } Caminhamento pré-ordem A B 3
COMPUTER SCIENCE ABC A B C 9 void PreOrdem(Apontador p) { if (p == null) return; printf("%d\n", p->Chave); PreOrdem(p->Esq); PreOrdem(p->Dir); } Caminhamento pré-ordem
COMPUTER SCIENCE Caminhamento central Ideia: – Visita sub-árvore esquerda em pré-ordem – Imprime – Visita sub-árvore direita em pré-ordem void Central(Apontador p) { if (p == null) return; Central(p->Esq); printf("%d\n", p->Chave); Central(p->Dir); }
COMPUTER SCIENCE ABC 5 Caminhamento central void Central(Apontador p) { if (p == null) return; Central(p->Esq); printf("%d\n", p->Chave); Central(p->Dir); } A
COMPUTER SCIENCE ABC 5 Caminhamento central void Central(Apontador p) { if (p == null) return; Central(p->Esq); printf("%d\n", p->Chave); Central(p->Dir); } A 7
COMPUTER SCIENCE ABC 5 Caminhamento central void Central(Apontador p) { if (p == null) return; Central(p->Esq); printf("%d\n", p->Chave); Central(p->Dir); } A 7 B
COMPUTER SCIENCE ABC 5 Caminhamento central void Central(Apontador p) { if (p == null) return; Central(p->Esq); printf("%d\n", p->Chave); Central(p->Dir); } A 7 B 4
COMPUTER SCIENCE ABC 5 Caminhamento central void Central(Apontador p) { if (p == null) return; Central(p->Esq); printf("%d\n", p->Chave); Central(p->Dir); } A 7 B C 8 6 9
COMPUTER SCIENCE Caminhamento pós-ordem Idea: – Visita sub-árvore esquerda em pré-ordem – Visita sub-árvore direita em pré-ordem – Imprime void PosOrdem(Apontador p) { if (p == null) return; PosOrdem(p->Esq); PosOrdem(p->Dir); printf("%d\n", p->Chave); }
COMPUTER SCIENCE ABC A Caminhamento pós-ordem void PosOrdem(Apontador p) { if (p == null) return; PosOrdem(p->Esq); PosOrdem(p->Dir); printf("%d\n", p->Chave); } A
COMPUTER SCIENCE ABC 5 9 Caminhamento pós-ordem void PosOrdem(Apontador p) { if (p == null) return; PosOrdem(p->Esq); PosOrdem(p->Dir); printf("%d\n", p->Chave); } A B
COMPUTER SCIENCE ABC 5 9 Caminhamento pós-ordem void PosOrdem(Apontador p) { if (p == null) return; PosOrdem(p->Esq); PosOrdem(p->Dir); printf("%d\n", p->Chave); } A B 7
COMPUTER SCIENCE ABC 5 9 Caminhamento pós-ordem void PosOrdem(Apontador p) { if (p == null) return; PosOrdem(p->Esq); PosOrdem(p->Dir); printf("%d\n", p->Chave); } A B 7 4
COMPUTER SCIENCE ABC 5 9 Caminhamento pós-ordem void PosOrdem(Apontador p) { if (p == null) return; PosOrdem(p->Esq); PosOrdem(p->Dir); printf("%d\n", p->Chave); } A B 7 4 2
COMPUTER SCIENCE ABC 5 9 Caminhamento pós-ordem void PosOrdem(Apontador p) { if (p == null) return; PosOrdem(p->Esq); PosOrdem(p->Dir); printf("%d\n", p->Chave); } A B
COMPUTER SCIENCE ABC 5 9 Caminhamento pós-ordem void PosOrdem(Apontador p) { if (p == null) return; PosOrdem(p->Esq); PosOrdem(p->Dir); printf("%d\n", p->Chave); } A B C
COMPUTER SCIENCE ABC 5 9 Caminhamento pós-ordem void PosOrdem(Apontador p) { if (p == null) return; PosOrdem(p->Esq); PosOrdem(p->Dir); printf("%d\n", p->Chave); } A B C