CES11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Prticas

  • Slides: 32
Download presentation
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas - 2020 Capítulo IV Árvores

CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas - 2020 Capítulo IV Árvores

O programa a ser desenvolvido neste capítulo irá: ■ Formar uma floresta através da

O programa a ser desenvolvido neste capítulo irá: ■ Formar uma floresta através da digitação de todos os pares pais-filhos; cada nó da árvore deve armazenar um caractere ■ Formar uma nova árvore em que a informação da raiz é digitada e as sub-árvores da raiz serão as árvores da floresta formada anteriormente ■ A estrutura de dados para árvores é o encadeamento de pais e irmãos ■ A floresta deve ser uma lista linear encadeada de

Exemplo: o operador fornece os seguintes pares: Pai-Filho Pai-Filho C-F R-S L-M R-T A-B

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

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

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

Exercício 4. 1: Formar uma lista linear com todos os nós de uma floresta

Exercício 4. 1: Formar uma lista linear com todos os nós de uma floresta n Seja uma floresta na qual cada nó armazena como informação apenas um caractere n O caractere de um nó só pode ser letra (maiúscula ou minúscula) ou dígito decimal n Não pode haver na floresta dois nós com o mesmo caractere

O exercício consiste em: n Ler uma string com os caracteres de todos os

O exercício consiste em: n Ler uma string com os caracteres de todos os nós de uma floresta n Armazenar cada caractere válido numa célula de árvore conforme o encadeamento de pais e irmãos n Formar uma lista linear encadeada de ponteiros para cada célula criada acima (é uma lista de nós) n Na realidade, formar-se-á uma floresta de árvores unitárias

Exemplo: O operador fornece a seguinte string: A 7 b; H*bk n Deve ser

Exemplo: O operador fornece a seguinte string: A 7 b; H*bk n Deve ser formada a seguinte lista linear: F ● # árvores A ● 7 ● b ● H ● k ● ● ● n Na realidade, F será uma floresta de 5 árvores unitárias n Para este exercício, completar o esqueleto de

#include #include <stdio. h> <stdlib. h> <conio. h> <string. h> <ctype. h> typedef char

#include #include <stdio. h> <stdlib. h> <conio. h> <string. h> <ctype. h> typedef char logic; const logic TRUE = 1, FALSE = 0; /* Declaracoes de tipos para encadeamento de pais e irmaos para arvores */ typedef struct celula; celula const celula *nulo = NULL; info pai typedef char informacao; typedef celula *noh; fesq idir typedef celula *arvore; struct celula {informacao info; noh pai, fesq, idir; };

/* Declaracoes de tipos para estrutura encadeada de filas de nohs de arvores */

/* Declaracoes de tipos para estrutura encadeada de filas de nohs de arvores */ Cada elemento da fila é um noh (ponteiro typedef struct celfila; para celula) typedef struct fila; struct celfila {noh elem; celfila *prox; }; struct fila {celfila *fr, *tr; }; Filas de nós são usadas: Na função para escrever a árvore por ordem de nível (Escrever. Niveis) Em eventuais funções que façam busca em largura na árvore A função Escrever. Niveis é fornecida logo a seguir

/* Declaracoes de tipos para floresta, que eh uma lista encadeada de arvores, com

/* Declaracoes de tipos para floresta, que eh uma lista encadeada de arvores, com elemento-lider */ typedef char string[100]; typedef struct celfloresta { arvore elem; celfloresta }; celfloresta; *posicfloresta; Para guardar a string digitada pelo operador Cada elemento da lista é uma arvore (ponteiro para celula) *prox; F ● # A ● 7 ● b ● H ● k ● ● ●

/* Variaveis globais floresta F; string Str. Floresta; /* */ // guarda os caracteres

/* Variaveis globais floresta F; string Str. Floresta; /* */ // guarda os caracteres digitados Prototipos das funcoes dependentes da estrutura para arvores */ void Formar. Lista. Nohs (void); void Escrever. Floresta (void); /* Estas funções deverão ser programadas Prototipos das funcoes operadoras de arvores logic Arv. Vazia (arvore); informacao Elemento (noh, arvore); void Escrever. Noh (informacao); noh Raiz (arvore); noh Pai (noh, arvore); noh Filho. Esquerdo (noh, arvore); noh Irmao. Direito (noh, arvore); */ Estas funções foram dadas em aulas teóricas e são fornecidas mais adiante

/* Prototipos das funcoes independentes da estrutura para arvores */ void Escrever. Niveis (arvore);

/* Prototipos das funcoes independentes da estrutura para arvores */ void Escrever. Niveis (arvore); /* Prototipos das funcoes operadoras de filas */ void Init. Fila (fila *); void Entrar. Fila (noh, fila *); noh Deletar. Fila (fila *); char Fila. Vazia (fila); Todas estas funções foram dadas em aulas teóricas e são fornecidas mais adiante

/* Programa principal: le, forma e escreve uma floresta */ int main () {

/* Programa principal: le, forma e escreve uma floresta */ int main () { printf ( "Leitura e armazenamento dos nohs da floresta F: nn" ); Formar. Lista. Nohs (); printf ("nn. Arvores da floresta F: nn"); Escrever. Floresta (); printf ("nn"); system ("pause"); return 0; } n As funções Formar. Lista. Nohs e Escrever. Floresta devem ser dependentes da estrutura de dados para florestas e árvores

/* Funcao Formar. Lista. Nohs: le as informacoes dos nohs de uma floresta armazenando-as

/* Funcao Formar. Lista. Nohs: le as informacoes dos nohs de uma floresta armazenando-as em celulas; forma uma lista linear de nohs ponteiros para essas celulas; essa lista eh a floresta F (global) */ void Formar. Lista. Nohs () { - - - } n A função deve pedir ao operador que digite uma string com os caracteres de todos os nós da floresta n A string digitada deve ser guardada na variável Str. Floresta

/* Funcao Formar. Lista. Nohs: le as informacoes dos nohs de uma floresta armazenando-as

/* Funcao Formar. Lista. Nohs: le as informacoes dos nohs de uma floresta armazenando-as em celulas; forma uma lista linear de nohs ponteiros para essas celulas; essa lista eh a floresta F (global) */ void Formar. Lista. Nohs () { - - - } n A lista deve ter um elemento-líder (para facilitar a deleção de uma celfloresta) # ● F A ● 7 ● b ● H ● k ● ● ●

/* Funcao Formar. Lista. Nohs: le as informacoes dos nohs de uma floresta armazenando-as

/* Funcao Formar. Lista. Nohs: le as informacoes dos nohs de uma floresta armazenando-as em celulas; forma uma lista linear de nohs ponteiros para essas celulas; essa lista eh a floresta F (global) */ void Formar. Lista. Nohs () { - - - } n Os caracteres não-letras, não-dígitos e os repetidos devem ser descartados; não precisa de mensagem de erro # ● F A ● 7 ● b ● H ● k ● ● ●

/* Funcao Escrever. Floresta: escreve os nos de todas as arvores da floresta F

/* Funcao Escrever. Floresta: escreve os nos de todas as arvores da floresta F em ordem de nivel */ void Escrever. Floresta () { - - - } n Para cada árvore da floresta, chamar a função Escrever. Niveis n Neste exercício, as árvores só terão o nó-raiz, mas no próximo exercício poderão ter mais nós # ● F A ● 7 ● b ● H ● k ● ● ●

void Escrever. Niveis (arvore A) { fila fp, fs; noh x, y, pai; if

void Escrever. Niveis (arvore A) { fila fp, fs; noh x, y, pai; if (Arv. Vazia (A) == TRUE) printf (" Arvore vazia"); else { Init. Fila (&fs); Função Escrever. Niveis: escreve os Entrar. Fila (Raiz (A), &fs); nos da árvore A em ordem de nível do { fp = fs; Init. Fila (&fs); Já foi apresentada while (Fila. Vazia(fp) == FALSE) { em slides teóricos x = Deletar. Fila(&fp); Escrever. Noh (Elemento (x, A)); pai = Pai (x, A); printf ("("); if (pai == nulo) Escrever. Noh ('#'); else Escrever. Noh (Elemento (pai, A)); printf (") "); for (y = Filho. Esquerdo (x, A); y != nulo; y = Irmao. Direito(y, A)) Entrar. Fila (y, &fs); } printf ("n"); } while (Fila. Vazia(fs) == FALSE); } printf ("nn"); }

/* Funcoes operadoras de arvores logic Arv. Vazia (arvore A) { if (A ==

/* Funcoes operadoras de arvores logic Arv. Vazia (arvore A) { if (A == NULL) return TRUE; else return FALSE; } */ Já foram apresentadas em slides teóricos informacao Elemento (noh n, arvore A) {return n->info; } void Escrever. Noh (informacao info) {printf ("%c", info); } noh Raiz (arvore A) {return A; } noh Pai (noh n, arvore A) {return n->pai; } noh Filho. Esquerdo (noh n, arvore A) {return n->fesq; } noh Irmao. Direito (noh n, arvore A) {return n->idir; }

/* Funcoes operadoras de filas de nos de arvores void Init. Fila (fila *f)

/* Funcoes operadoras de filas de nos de arvores void Init. Fila (fila *f) { f->fr = malloc (sizeof(celfila)); f->tr = f->fr; f->fr->prox = NULL; } */ Também já foram apresentadas em slides teóricos void Entrar. Fila (noh x, fila *f) { f->tr->prox = malloc (sizeof(celfila)); f->tr = f->tr->prox; f->tr->elem = x; f->tr->prox = NULL; } noh Deletar. Fila (fila *f) { noh x; celfila *p; p = f->fr->prox; x = p->elem; if (f->tr == p) f->tr = f->fr; f->fr->prox = p->prox; free (p); return x; } char Fila. Vazia (fila f) { char c; if (f. fr == f. tr) c = TRUE; else c = FALSE; return c; } Os elementos das filas serão noh’s (ponteiros para celula)

Exercício 4. 2: Fazer as ligações de todos os pais e filhos da floresta

Exercício 4. 2: Fazer as ligações de todos os pais e filhos da floresta n Alterar o programa anterior, para que ele leia todos os pares pais-filhos da floresta n Para cada par válido, a célula do filho deve ser ligada à do pai e deve ser colocada como caçula dos filhos desse pai n Manter na lista formada no exercício anterior apenas os nós que forem raízes de árvores n A floresta terá menos árvores, porém maiores

Exemplo: seja a seguinte floresta obtida no exercício anterior: F # n B ●

Exemplo: seja a seguinte floresta obtida no exercício anterior: F # n B ● C ● G ● E ● F ● ● ● Supondo que o operador forneça os seguintes pares pais-filhos: BE, CF, CG Par válido Deve ter somente 2 caracteres (diferentes entre si) Pai e filho devem estar em alguma célula da floresta O filho aparece pela 1ª vez como filho O filho não é um ancestral do pai

F # B ● C ● G ● E ● F ● ● ●

F # B ● C ● G ● E ● F ● ● ● n Supondo que o operador forneça os seguintes pares pais-filhos: BE, CF, CG n Deverão ser feitas as seguintes ligações:

F # B ● ● C ● G ● ● E ● ● F

F # B ● ● C ● G ● ● E ● ● F ● ● n Os nós que não forem raízes (ou seja, aqueles que tiverem pai) devem ser retirados da floresta F n Desenhando de outra forma:

F ● # B ● C ● E ● ● A floresta F passou

F ● # B ● C ● E ● ● A floresta F passou de 5 árvores unitárias para 2 árvores, uma com 2 e outra com 3 nós ● ● F G ● ● ●

Novo programa principal: int main () { printf ( "Leitura e armazenamento dos nohs

Novo programa principal: int main () { printf ( "Leitura e armazenamento dos nohs da floresta F: nn" ); Formar. Lista. Nohs (); if (F->prox != NULL) { printf ( "n. Leitura e ligacao dos pares pais-filhos: nn"); Ligar. Pais. Filhos (); } printf ("nn. Arvores da floresta F: nn"); Escrever. Floresta (); printf ("nn"); system ("pause"); return 0; }

A função Ligar. Pais. Filhos deverá ler vários pares paisfilhos e, para cada par:

A função Ligar. Pais. Filhos deverá ler vários pares paisfilhos e, para cada par: n Checar se o par é válido n Se for válido, ligar a célula do filho à do pai n Inserir a célula do filho como caçula do pai No final, a função deverá retirar da lista linear (floresta F) todos os nós que não forem raízes

Exercício 4. 3: Formar uma nova árvore em que as sub-árvores da raiz deverão

Exercício 4. 3: Formar uma nova árvore em que as sub-árvores da raiz deverão ser as árvores da floresta F n Alterar o programa anterior, para que ele: – – – Leia uma nova informação (caractere) Guarde essa informação numa célula Faça um ponteiro para essa célula ser a raiz de uma nova árvore Faça as árvores da floresta F serem sub-árvores dessa raiz Escreva na tela essa nova árvore em ordem de nível

Exemplo: seja a floresta anterior F ● # B ● C ● E ●

Exemplo: seja a floresta anterior F ● # B ● C ● E ● ● F G ● ● ●

int main () { Novo programa principal informacao c; arvore A; printf ( "Leitura

int main () { Novo programa principal informacao c; arvore A; printf ( "Leitura e armazenamento dos nohs da floresta F: nn“); Formar. Lista. Nohs (); if (F->prox != NULL) { printf ( "n. Leitura e ligacao dos pares pais-filhos: nn"); Ligar. Pais. Filhos (); } printf ("nn. Arvores da floresta F: nn"); Escrever. Floresta (); printf ("nn. Criacao de nova arvore: nnt"); printf ("Digite a informacao da raiz: "); c = getche (); A = Criacao (c, F); printf ("nn"); Escrever. Niveis (A); printf ("nn"); system ("pause"); return 0; } A função Criacao deve ser dependente das estruturas de dados para árvores e florestas

Exercício 4. 4: Forma parentética, altura, largura e número de nós das árvores n

Exercício 4. 4: Forma parentética, altura, largura e número de nós das árvores n Alterar o programa anterior, para que ele escreva, para cada árvore da floresta e para a árvore final: – – Sua forma parentética Sua altura, largura e número de nós n Largura de uma árvore é o máximo entre os números de nós de seus níveis n Para cada um desses 4 itens, fazer uma função independente da estrutura de dados para árvores