A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Capítulo IV – Árvores Gerais

Apresentações semelhantes


Apresentação em tema: "Capítulo IV – Árvores Gerais"— Transcrição da apresentação:

1 Capítulo IV – Árvores Gerais
4.1 – Definições e terminologia básica 4.2 – Formas de representação de árvores 4.3 – Ordenação dos nós de uma árvore 4.4 – Operadores para o TAD árvore 4.5 – Estruturas contíguas para árvores 4.6 – Estruturas encadeadas para árvores

2 4.5 – Estruturas Encadeadas para Árvores
4.6.1 – Estrutura encadeada direta Esquema:

3 Declarações: Nó: ponteiro para célula
const int maxfilhos = 5; typedef celula *noh; typedef celula *arvore; struct celula { informacao info; noh Filhos[5]; }; arvore A; Nó: ponteiro para célula Árvore: ponteiro para a célula da raiz Usa muitos ponteiros desnecessários (exemplo: folhas) Limita o número de filhos A Esquema usado em árvores balanceadas (implementação de dicionários)

4 4.6.2 – Estrutura com listas de filhos
Esquema: celula raiz 1 ncel 11 Nó: índice num vetor de células Filhos: ordenados da esquerda para a direita Estrutura das listas: encadeada, sem nó- líder

5 4.6.2 – Estrutura com listas de filhos
celula raiz 1 ncel 11 Não necessariamente a raiz fica no nó 1 Os nós podem ficar embaralhados no vetor, sem ordenação (pré-ordem, etc.) Facilita a inserção de nós

6 Declarações: typedef struct arvore arvore; struct arvore { noh raiz;
celula Espaco[51]; int ncel; }; noh n1, n2, n3; arvore A1, A2, A3; informacao x, y, z; const int nulo = 0; typedef int noh; typedef celfilho *lista; typedef celfilho *posição; typedef struct celfilho celfilho; struct celfilho { noh filho; celfilho *prox; }; typedef struct celula celula; struct celula { informacao info; noh pai; lista list; celula raiz 1 ncel 11

7 Operadores: noh FilhoEsquerdo (noh n, arvore A) {
if (A.Espaco[n].list == NULL) return nulo; else return A.Espaco[n].list->filho; } informacao Elemento (noh n, arvore A) { return A.Espaco[n].info; noh raiz (arvore A) { if (A.ncel == 0) return A.raiz; celula raiz 1 ncel 11

8 void Esvaziar (arvore *A){ Liberar todas as células de filhos;
A->raiz = nulo; A->ncel = 0; } noh Pai (noh n, arvore A) { return A.Espaco[n].pai; celula raiz 1 ncel 11

9 Observação: esta estrutura é muito usada para grafos
noh IrmaoDireito (noh n, arvore A) { noh pai; posição idir, p; if (n == A.raiz) return nulo; pai = A.Espaco[n].pai; p = A.Espaco[pai].list; while (p->filho != n) p = p->prox; idir = p->prox; if (idir == NULL) return nulo; else return idir->filho; } celula raiz 1 ncel 11 Observação: esta estrutura é muito usada para grafos

10 4.6.3 – Estrutura com encadeamento de pais e irmãos
Esquema: info pai fesq idir Célula

11 a) Declarações info pai fesq idir Célula const celula *nulo = NULL;
typedef celula *noh; typedef celula *arvore; typedef struct celula celula; struct celula { informacao info; noh pai, fesq, idir; }; arvore A1, A2, A3; info pai fesq idir Célula

12 Exemplo ilustrativo: montagem da seguinte árvore:
Foi visto em CES-10

13 A A  B C  x x E  F  G  y x y arvore A; noh x, y;
A = (noh) malloc (sizeof (celula)); A->info = 'A'; A->pai = A->idir = NULL; A->fesq = (noh) malloc (sizeof (celula)); x = A->fesq; x->info = 'B'; x->pai = A; x->fesq = (noh) malloc (sizeof (celula)); x->idir = (noh) malloc (sizeof (celula)); x->fesq->info = 'E'; x->fesq->pai = x; x->fesq->fesq = x->fesq->idir = NULL; x = x->idir; x->info = 'C'; x->pai = A; x->idir = NULL; y = x->fesq; y->info = 'F'; y->pai = x; y->fesq = NULL; y->idir = (noh) malloc (sizeof (celula)); y->idir->info = 'G'; y->idir->pai = x; y->idir->fesq = y->idir->idir = NULL; A A B C x x E F G y x y

14 Os comandos anteriores formam apenas esta árvore em particular
Ainda neste capítulo serão vistos algoritmos gerais de formação de árvores A A B C E F G

15 b) Operações elementares
FilhoEsquerdo (noh n, arvore A): n->fesq; IrmãoDireito (noh n, arvore: A): n->idir; Elemento (noh n, arvore A): n->info; Pai (noh n, arvore A): n->pai; Raiz (arvore A): A; info pai fesq idir Célula

16 c) Operador Esvaziar (&n): anula o nó n e libera todas as células que se tornam inacessíveis devido a essa anulação Por exemplo: Se n é o ponteiro A, todas as células da árvore serão liberadas Se n é o ponteiro fesq da célula que contém ‘A’, as células a serem liberadas são as de ‘B’, ‘E’, ‘C’, ‘F’, ‘G’, ‘D’, ‘H’, ‘I’, ‘J’ e ‘K’ Se n é o ponteiro idir da célula que contém ‘C’, as células a serem liberadas são as de ‘D’, ‘H’, ‘I’, ‘J’ e ‘K’ info pai fesq idir Célula Esvaziar (&A): esvazia a árvore A

17 Não deve ser aplicada ao ponteiro pai de nenhuma célula
void Esvaziar (noh *n) { if ((*n)->fesq == NULL && (*n)->idir == NULL) free (*n); else if ((*n)->idir == NULL) { Esvaziar (&(*n)->fesq)); } else { Esvaziar (&((*n)->idir)); if ((*n)->fesq != NULL) Esvaziar (&((*n)->fesq)); *n = NULL; info pai fesq idir Célula Se o argumento for &A : A = NULL n Não deve ser aplicada ao ponteiro pai de nenhuma célula Nesta função, n guarda o endereço de um ponteiro para celula

18 Esvaziar A: Esvaziar B: Esvaziar C: Esvaziar D: Esvaziar H:
void Esvaziar (noh *n) { if ((*n)->fesq == NULL && (*n)->idir == NULL) free (*n); else if ((*n)->idir == NULL) { Esvaziar (&((*n)->fesq)); } else { Esvaziar (&((*n)->idir)); if ((*n)->fesq != NULL) (*n) = NULL; Esvaziar A: Esvaziar B: Esvaziar C: Esvaziar D: Esvaziar H: Esvaziar I: Esvaziar J: Esvaziar K: Liberar K Liberar J Liberar I Liberar H Liberar D Esvaziar F: Esvaziar G: Liberar G Liberar F Liberar C Esvaziar E: Liberar E Liberar B Liberar A

19 d) arvore Criacao (informacao x, ListaArvores LA):
H G F D C E B K J I ListaÁrvores

20 Situação no início da função Criacao (x, LA):
Adota-se a estrutura contígua para a lista de árvores k x # 1 2 3 y ultimo Arvores LA a b c z

21 Aloca o nó-raiz da nova árvore e o preenche:
x k k A (a ser retornado) # 1 2 3 y Arvores LA ultimo y a b c z

22 Procura primeira árvore não-nula em LA e a faz sub-árvore esquerda da raiz:
x k k A (a ser retornado) # 1 2 3 y Arvores LA ultimo y a b c z

23 Percorre o vetor, procurando árvores não-nulas e acertando o pai e o idir de suas raizes:
x k k A (a ser retornado) # 1 2 3 y Arvores LA ultimo y a b c z

24 arvore Criacao (informacao x, ListaArvores LA) {
int i, j, ant; arvore A; A = malloc (sizeof (celula)); A->info = x; A->pai = A->fesq = A->idir = NULL; for (i = 1; i <= LA.ultimo && LA.Arvores[i] == NULL; i++); if (i <= LA.ultimo){ A->fesq = LA.Arvores[i]; for (j = i; j <= LA.ultimo; j++) if (LA.Arvores[j] != NULL) { if (j != i) LA.Arvores[ant]->idir = LA.Arvores[j]; LA.Arvores[j]->pai = A; LA.Arvores[j]->idir = NULL; ant = j; } return A; struct ListaArvores { int ultimo; arvore Arvores [51]; }

25 e) Formação de árvores: uma nova árvore pode ser formada pelos seguintes métodos (entre outros):
Função Criação: vista no item d Leitura dos pares pais-filhos Formação interativa Leitura da forma parentética

26 e.1) Leitura dos pares pais-filhos:
Usada para formar uma floresta O operador fornece todos os pares pais-filhos da floresta Por exemplo, seja uma floresta cujos nós das árvores guardam apenas um caractere cada Nessa floresta é proibido dois ou mais nós guardarem o mesmo caractere

27 O operador fornece os seguintes pares:
A ordem entre dois irmãos é estabelecida pela ordem fornecida pelo operador Um filho não pode aparecer em mais de um par Não pode haver ciclos; Exemplo: Pai-Filho C-F R-S L-M R-T A-B C-G A-C N-P L-N A-D Pai-Filho A-B B-C C-D D-A

28 Floresta formada: Pai-Filho C-F R-S L-M R-T A-B C-G A-C N-P L-N A-D A

29 e.2) Formação interativa: constrói interativamente uma nova árvore, retornando-a
Para o encadeamento de pais e irmãos é apresentada uma construção em largura A função elaborada será arvore NovaArvore (void) A seguir, uma saída típica para a execução dessa função

30 A arvore tem raiz? (s/n): s
Digite a informacao da raiz: A Quantos filhos tem A? 3 1.o filho de A: B 2.o filho de A: C 3.o filho de A: D Quantos filhos tem B? 1 1.o filho de B: E Quantos filhos tem C? 2 1.o filho de C: F 2.o filho de C: G Quantos filhos tem D? 1 1.o filho de D: H Quantos filhos tem E? 0 Quantos filhos tem F? 0 Quantos filhos tem G? 0 Quantos filhos tem H? 3 1.o filho de H: I 2.o filho de H: J 3.o filho de H: K Quantos filhos tem I? 0 Quantos filhos tem J? 0 Quantos filhos tem K? 0

31 Perguntar pela raiz, alocando-a e colocando-a em ff:
Idéia: Usar uma fila ff para guardar os nós já introduzidos na estrutura, para os quais não se indagou ainda sobre o número e o nome de seus filhos Perguntar pela raiz, alocando-a e colocando-a em ff: ff A A

32 Deletar ff, copiando sua frente no nó avulso x:
x

33 Perguntar pelo número de filhos de x, guardando-o em nf:
ff 3 nf A A x

34 Perguntar pelo 1º filho de x, alocando-o e colocando-o em ff:
3 nf A A x A alocação é a partir do filho esquerdo de x B

35 Perguntar pelos outros filhos de x, alocando-os e colocando-os em ff:
3 nf A A x A alocação é a partir do respectivo irmão esquerdo B C D

36 Deletar ff, copiando sua frente em x:
3 nf A A x B C D x

37 Perguntar pelo número de filhos de x, guardando-o em nf:
ff nf 3 1 A A B C D x

38 Perguntar pelo filho de x, alocando-o e colocando-o em ff:
1 nf A A B C D x E

39 Deletar ff, copiando sua frente em x:
1 nf A A B C D x x E

40 Perguntar pelo número de filhos de x, guardando-o em nf:
ff nf 1 2 A A B C D x E

41 Perguntar pelos filhos de x, alocando-os e colocando-os em ff:
2 nf A A B C D x E F G

42 Deletar ff, copiando sua frente em x:
2 nf A A E assim por diante B C D x x E F G

43 arvore NovaArvore () { arvore A; char c; fila ff; noh x, y; int nf, i; /* Verificacao da existencia de raiz */ write ("A arvore tem raiz? (s/n): "); read (c); while (c != 's' && c != 'n' && c != 'S' && c != 'N') read (c); if (c == 'n' || c == 'N') A = NULL; else { /* Leitura e armazenamento da raiz */ A = malloc (sizeof(celula)); write ("Digite a informacao da raiz: "); read (A->info); A->pai = A-> fesq = A->idir = NULL; InitFila (&ff); EntrarFila (A, &ff);

44 /* Leitura e armazenamento dos outros nos */
x = DeletarFila(&ff); write ("Quantos filhos tem ", x->info, "?"); read (nf); for (i = 1; i <= nf; i++) { if (i == 1) y = x->fesq = malloc(sizeof(celula)); else y = y->idir = malloc(sizeof(celula)); write (i, ".o filho de ", x->info, ":"); read (y->info); y->pai = x; y->fesq = y->idir = NULL; EntrarFila (y, &ff); } } while (FilaVazia(ff) == FALSE); } /* Fim do else */ return A; }

45 e.3) Leitura da forma parentética
Digitar a forma, armazenando-a numa string, e analisar a cadeia, armazenando-a na estrutura com encadeamento de pais e irmãos Pode-se usar a seguinte formulação recursiva: Sendo c uma letra genérica, (c) é uma forma parentética correta Sendo α1, α2, α3, ... αn, formas parentéticas corretas (n > 0), então (c α1α2α3 ... αn) também é

46 Programa para somente analisar a parentética
typedef char logic; const logic TRUE = 1, FALSE = 0; /* Prototipos de funcoes */ void Analisa (void); void Erro (char *); /* Variaveis globais */ char expr[100]; int i; char erro;

47 /* Programa principal */
int main () { write ("Forma parentetica: "); read (expr); i = 0; erro = FALSE; Analisa (); if (!erro && expr[i] != '\0') Erro("enter esperado"); if (erro) write ("\parentetica reprovada!"); else write ("parentetica valida!"); }

48 O programa para armazenar a árvore usa este programa como esqueleto
/* Funcao Analisa: Verifica se a forma parentetica digitada estah correta */ void Analisa () { if (expr[i] != '(') {Erro ("( esperado"); return;} i++; if (isalpha (expr[i]) == FALSE) { Erro("Letra esperada"); return;} for (i++; expr[i] == '('; ) Analisa (); if (expr[i] != ')') {Erro (") esperado"); return;} } /* Funcao Erro: emite mensagem de erro */ void Erro (char *s) { erro = TRUE; write (s); O programa para armazenar a árvore usa este programa como esqueleto Fica como exercício


Carregar ppt "Capítulo IV – Árvores Gerais"

Apresentações semelhantes


Anúncios Google