Árvores. Prof. César Melo DCC/ICE/UFAM

Documentos relacionados
Figura 13.1: Um exemplo de árvore de diretório.

Árvores. ! utilizada em muitas aplicações. ! modela uma hierarquia entre elementos. ! O conceito de árvores está diretamente ligado à recursão

Métodos Computacionais. Árvores

INF1007: Programação 2 10 Árvores Binárias. (c) Dept. Informática - PUC-Rio 1

Busca. Pesquisa sequencial

INF 1007 Programação II

Estruturas de Dados Aula 15: Árvores 17/05/2011

Estruturas de Dados. Módulo 13 - Árvores. 9/8/2005 (c) Dept. Informática - PUC-Rio 1

LISTAS ENCADEADAS OU NÃO- SEQÜENCIAIS. Estrutura de Dados

Estruturas de Dados I

Linguagem C: Árvores Binarias

Estruturas de Dados. Prof. Gustavo Willam Pereira Créditos: Profa. Juliana Pinheiro Campos

struct arv { char info; struct arv* esq; struct arv* dir; };

INF PROGRAMAÇÃO II LISTA DE EXERCÍCIOS 15

EAD Árvore árvore binária

INF1007: Programação 2 9 Tipos Abstratos de Dados. (c) Dept. Informática - PUC-Rio 1

Para entender o conceito de objetos em programação devemos fazer uma analogia com o mundo real:

UNIVERSIDADE DO TOCANTINS TECNOLOGIA EM ANÁLISE E DESENVOLVIMENTO DE SISTEMAS PRÁTICA EM PROGRAMAÇÃO DE SISTEMAS

Árvores Parte 1. Aleardo Manacero Jr. DCCE/UNESP Grupo de Sistemas Paralelos e Distribuídos

Árvore Binária de Busca

Módulo de Equações do Segundo Grau. Equações do Segundo Grau: Resultados Básicos. Nono Ano

Métodos Computacionais. Fila

ESTRUTURA DE DADOS DCC013

TECNOLOGIA EM ANÁLISE E DESENVOLVIMENTO DE SISTEMAS TURMA 2008/1 2 PERÍODO MÓDULO 3 AVALIAÇÃO MP2 DATA 2/10/2008 ESTRUTURAS DE DADOS 2008/2

Método de ordenação - objetivos:

PESQUISA OPERACIONAL -PROGRAMAÇÃO LINEAR. Prof. Angelo Augusto Frozza, M.Sc.

ALGORITMOS E ESTRUTURAS DE DADOS CES-11 CES-11 CES-11

Álgebra Linear Aplicada à Compressão de Imagens. Universidade de Lisboa Instituto Superior Técnico. Mestrado em Engenharia Aeroespacial

INF 1010 Estruturas de Dados Avançadas

/*(Atenção: Em se tratando de uma lista estaticamente alocada, temos utilizado a estratégia de passa o tamanho máximo do vetor.)*/

Pesquisa Sequencial e Binária

ESTRUTURAS DE DADOS AVANÇADAS (INF 1010) (a) Seja um TAD definido por uma lista circular implementada em um vetor.

2 Segmentação de imagens e Componentes conexas

EAD Árvore - representação usando listas ligadas

Estruturas de Dados. Árvores AVL. Cesar Tadeu Pozzer. Curso de Ciência da Computação UFSM (12/12/2007)

1. Introdução Definição Conceitos relacionados... 2

Inteligência Artificial

O Cálculo λ sem Tipos

ADMINISTRAÇÃO DE BANCOS DE DADOS MÓDULO 8

Curso C: Ponteiros e Arrays

INTRODUÇÃO À PROGRAMAÇÃO II VARIÁVEIS COMPOSTAS HOMOGÊNEAS UNIDIMENSIONAIS

UNIVERSIDADE FEDERAL DO ESPÍRITO SANTO PROGRAMA DE EDUCAÇÃO TUTORIAL - MATEMÁTICA PROJETO FUNDAMENTOS DE MATEMÁTICA ELEMENTAR

Modelo Entidade Relacionamento (MER) Professor : Esp. Hiarly Alves

SISTEMAS OPERACIONAIS. 3ª. Lista de Exercícios

Aula 5. Uma partícula evolui na reta. A trajetória é uma função que dá a sua posição em função do tempo:

Departamento de Informática - PUC-Rio INF 1005 Programação I P1 22/09/2010 Nota

Fundamentos de Bancos de Dados 3 a Prova Caderno de Questões

Orientação a Objetos

8 Crie um pequeno sistema para controle automatizado de estoque, com os seguintes registros:

ENG1000 Introdução à Engenharia

OPERAÇÕES COM FRAÇÕES

ESTRUTURAS DE DADOS I. Notas de Aula. Prof. Dr. Gilberto Nakamiti

ESTRUTURAS DE DADOS II MSc. Daniele Carvalho Oliveira

Comandos de Eletropneumática Exercícios Comentados para Elaboração, Montagem e Ensaios

tipo e tamanho e com os "mesmos" elementos do vetor A, ou seja, B[i] = A[i].

AULA 07 Distribuições Discretas de Probabilidade

UNIVERSIDADE DO VALE DO RIO DOS SINOS - UNISINOS CENTRO DE CIÊNCIAS EXATAS E TECNOLÓGICAS - CENTRO 06. Funções, variáveis, parâmetros formais

M =C J, fórmula do montante

10. Listas Encadeadas

Pesquisa em Memória Primária. Algoritmos e Estruturas de Dados II

1.2 OPERAÇÕES BÁSICAS EM ALGORITMOS E PROGRAMAS 18

Estruturas de Dados Aula 9: Listas (parte 1) 05/04/2011

Árvores Binárias. Observação: Material elaborado a partir do material do Professor Marcos Costa.

2ª Lista de Exercícios

Árvores binárias de pesquisa com balanceamento. Algoritmos e Estruturas de Dados II

Lista de Exercícios Critérios de Divisibilidade

Prova de Fundamentos de Bancos de Dados 1 a Prova

Algoritmos e Estruturas de Dados: Árvore Binária

Graphing Basic no Excel 2007

Universidade Federal de Goiás Campus Catalão Departamento de Matemática

CRIAÇÃO DE TABELAS NO ACCESS. Criação de Tabelas no Access

Pelo que foi exposto no teorema de Carnot, obteve-se a seguinte relação:

Programação 2009/2010 MEEC - MEAer Laboratório 5 Semana de 26 de outubro de 2009

Pesquisa digital. Algoritmos e Estruturas de Dados II

Árvores Binárias de Busca

Programação Linear - Parte 4

Se inicialmente, o tanque estava com 100 litros, pode-se afirmar que ao final do dia o mesmo conterá.

1 Teoria de conjuntos e lógica

Modelo Lógico: Tabelas, Chaves Primárias e Estrangeiras

a) O Word é um editor de TEXTOS. Com ele é possível digitar cartas, currículos e trabalhos escolares.

Análise Qualitativa no Gerenciamento de Riscos de Projetos

Bem-vindo ao tópico sobre conceitos de determinação de preços.

Árvores Binárias - continuação

Vantagens e desvantagens da utilização do patrimônio líquido pelo seu valor de mercado na avaliação de empresas

Introdução à orientação a objetos

Conteúdo programático

Módulo de Princípios Básicos de Contagem. Segundo ano

Estruturas de Dados Árvores

COMO VENDER MAIS USANDO FUNIL DE VENDAS. Capítulo III: Etapas do Funil de Vendas

ALGORITMOS E COMPLEXIDADE PROBLEMAS E ALGORITMOS

COBRANÇA BANCÁRIA CAIXA

Arquivos Indexados por Chaves Secundárias. Vanessa Braganholo

Trabalho Prático II - Resta 1 Data de Entrega: Conferir no calendário!

ISS Eletrônico. Formato de Arquivos para Transmissão de Documentos Declarados através do aplicativo OFFLINE. Extensão do Arquivo JUNHO2006.

Conteúdos: Debora, Edcarllos, livros! slides disponíveis!

Lógica de Predicados

Transcrição:

Árvores Prof. César Melo DCC/ICE/UFAM

Introdução As estruturas anteriores são chamadas de unidimensionais (ou lineares) Exemplo são vetores e listas Não adequadas para representar hierarquias. Exemplo: árvore de diretórios Árvore é uma estrutura adequada para representar hierarquias A forma mais natural para definirmos uma estrutura de árvore é usando recursividade

Estrutura de Árvores Uma árvore é composta por um conjunto de nós. Existe um nó r, denominado raiz, que contém zero ou mais sub-árvores, cujas raízes são ligadas a r. Esses nós raízes das sub-árvores são ditos filhos do nó pai, no caso r. Nós com filhos são comumente chamados de nós internos e nós que não têm filhos são chamados de folhas, ou nós externos.

Estrutura de Árvores Por adotarmos essa forma de representação gráfica, não representamos explicitamente a direção dos ponteiros, subentendendo que eles apontam sempre do pai para os filhos.

Tipos de Árvores O número de filhos permitido por nó é o que diferencia os diversos tipos de árvores existentes. Estudaremos dois tipos de árvores. Primeiro, examinaremos as árvores binárias, onde cada nó tem, no máximo, dois filhos. Depois examinaremos as chamadas árvores genéricas, onde o número de filhos é indefinido. Estruturas recursivas serão usadas como base para o estudo e a implementação das operações com árvores.

ÁRVORES BINÁRIAS

Árvore Binária Um exemplo de utilização de árvores binárias está na avaliação de expressões. Como trabalhamos com operadores que esperam um ou dois operandos, os nós da árvore para representar uma expressão têm no máximo dois filhos. Nessa árvore, os nós folhas representam operandos e os nós internos operadores.

Árvores Binárias Esta árvore representa a expressão (3+6)*(4-1)+5

Estrutura de uma AB Numa árvore binária, cada nó tem zero, um ou dois filhos. De maneira recursiva, podemos definir uma árvore binária como sendo: uma árvore vazia; ou um nó raiz tendo duas sub-árvores, identificadas como a sub-árvore da direita (sad) e a sub-árvore da esquerda (sae).

Estrutura de uma AB

Estrutura de uma AB Os nós a, b, c, d, e, f formam uma árvore binária da seguinte maneira: A árvore é composta do nó a, da subárvore à esquerda formada por b e d, e da sub-árvore à direita formada por c, e e f. O nó a representa a raiz da árvore e os nós b e c as raízes das sub-árvores. Finalmente, os nós d, e e f são folhas da árvore.

Descrição de AB Para descrever árvores binárias, podemos usar a seguinte notação textual: A árvore vazia é representada por <>, e árvores não vazias por <raiz sae sad>. Com essa notação, a árvore da Figura anterior é representada por: <a<b<><d<><>>><c<e<><>><f<><>>>>.

Descrição de AB Uma sub-árvore de uma árvore binária é sempre especificada como sendo a sae ou a sad de uma árvore maior, e qualquer das duas sub-árvores pode ser vazia. As duas árvores da Figura abaixo são distintas. Qual seria a representação textual dessas duas árvores? São diferentes?

Altura de uma AB Uma propriedade fundamental de todas as árvores é que só existe um caminho da raiz para qualquer nó. Podemos definir a altura de uma árvore como sendo o comprimento do caminho mais longo da raiz até uma das folhas. A altura de uma árvore com um único nó raiz é zero e, por conseguinte, dizemos que a altura de uma árvore vazia é negativa e vale -1.

Exemplos: Alturas e Níveis Nível 0 Nível 1 Nível 2 Nível 3

Tipos de árvores: Cheia Nós intermediários com dois filhos.

Tipos de árvores: Perfeita Todos os Nós folhas estão no mesmo nível

Tipos de árvores: Completa Árvore perfeita até a altura h-1; Na altura h os nós estão dispostos da esquerda para a direita;

Representação em C Podemos definir um tipo para representar uma árvore binária. Vamos considerar que a informação a ser armazenada são valores de caracteres simples. Vamos inicialmente discutir como podemos representar uma estrutura de árvore binária em C. Cada nó deve armazenar três informações: a informação propriamente dita, no caso um caractere, e dois ponteiros para as sub-árvores, à esquerda e à direita.

Representação em C/C++ typedef struct arv TArv; struct arv { char info; TArv* esq; TArv* dir; }; Da mesma forma que uma lista encadeada é representada por um ponteiro para o primeiro nó, a estrutura da árvore como um todo é representada por um ponteiro para o nó raiz.

Criando Árvores TArv* inicializa(void) { return NULL; } TArv* cria(char c, TArv* sae, TArv* sad) { TArv* p=(tarv *)malloc(sizeof(tarv)); p->info = c; p->esq = sae; p->dir = sad; return p; }

Árvore Vazia short vazia(tarv* a) { return a==null; }

Exemplo Exemplo: Usando as operações inicializa e cria, crie uma estrutura que represente a seguinte árvore.

Exemplo /* sub-árvore com 'd' */ TArv* d= cria('d',inicializa(),inicializa()); /* sub-árvore com 'b' */ TArv* b= cria('b',inicializa(),d); /* sub-árvore com 'e' */ TArv* e= cria('e',inicializa(),inicializa()); /* sub-árvore com 'f' */ TArv* f= cria('f',inicializa(),inicializa()); /* sub-árvore com 'c' */ TArv* c= cria('c', e, f); /* árvore com raiz 'a'*/ TArv* a = cria('a',b,c);

Exemplo Alternativamente, a árvore poderia ser criada recursivamente com uma única atribuição, seguindo a sua estrutura. Como isso pode ser feito?

Exemplo TArv* a = cria('a', cria('b', inicializa(), cria('d', inicializa(), inicializa()) ), cria('c', cria('e', inicializa(), inicializa()), cria('f', inicializa(), inicializa()) ) );

Exibindo Conteúdo da Árvore void imprime (TArv* a) { if (!vazia(a)){ printf("%c ", a->info); /* mostra raiz */ imprime(a->esq); /* mostra sae */ imprime(a->dir); /* mostra sad */ } } Como é chamada essa forma de exibição? E para exibir na forma in-fixada? E na pós-fixada?

Liberando Memória TArv* libera (TArv* a){ if (!vazia(a)){ libera(a->esq); /* libera sae */ libera(a->dir); /* libera sad */ free(a); /* libera raiz */ } return NULL; }

Criação e Liberação Vale a pena notar que a definição de árvore, por ser recursiva, não faz distinção entre árvores e sub-árvores. Assim, cria pode ser usada para acrescentar ( enxertar ) uma sub-árvore em um ramo de uma árvore, e libera pode ser usada para remover ( podar ) uma sub-árvore qualquer de uma árvore dada.

Criação e Liberação Considerando a criação da árvore feita anteriormente, podemos acrescentar alguns nós, com: a->esq->esq = cria('x', cria('y',inicializa(),inicializa()), cria('z',inicializa(),inicializa()) ); E podemos liberar alguns outros, com: a->dir->esq = libera(a->dir->esq); Deixamos como exercício a verificação do resultado final dessas operações.

Buscando um Elemento Essa função tem como retorno um valor booleano (um ou zero) indicando a ocorrência ou não do caractere na árvore. int busca (Arv* a, char c){ if (vazia(a)) return 0; /* não encontrou */ else return a->info==c busca(a->esq,c) busca(a->dir,c); }

Buscando um Elemento Podemos dizer que a expressão: return c==a->info busca(a->esq,c) busca(a->dir,c); é equivalente a: if (c==a->info) return 1; else if (busca(a->esq,c)) return 1; else return busca(a->dir,c);

ÁRVORES GENÉRICAS

Árvores Genéricas Como vimos, numa árvore binária o número de filhos dos nós é limitado em no máximo dois. No caso da árvore genérica, esta restrição não existe. Cada nó pode ter um número arbitrário de filhos. Essa estrutura deve ser usada, por exemplo, para representar uma árvore de diretórios.

Exemplo

Representação em C/C++ Devemos levar em consideração o número de filhos que cada nó pode apresentar. Se soubermos que numa aplicação o número máximo de filhos é 3, podemos montar uma estrutura com 3 campos apontadores, digamos, f1, f2 e f3. Os campos não utilizados podem ser preenchidos com o valor nulo NULL, sendo sempre utilizados os campos em ordem. Assim, se o nó n tem 2 filhos, os campos f1 e f2 seriam utilizados, nessa ordem, ficando f3 vazio.

Representação em C/C++ Prevendo um número máximo de filhos igual a 3, e considerando a implementação de árvores para armazenar valores de caracteres simples, a declaração do tipo que representa o nó da árvore poderia ser: typedef struct arv3 TAvr3; struct arv3 { char val; TArv3 *f1, *f2, *f3; };

Mesmo Exemplo

Problemas com Representação Como se pode ver no exemplo, em cada um dos nós que tem menos de três filhos, o espaço correspondente aos filhos inexistentes é desperdiçado. Além disso, se não existe um limite superior no número de filhos, esta técnica não se aplica. O mesmo acontece se existe um limite no número de nós, mas se esse limite for raramente alcançado, pois estaríamos desperdiçando espaço de memória com os campos não utilizados. Como contornar tais problemas?

Solução: Lista de filhos Um nó aponta apenas para seu primeiro (prim) filho, e cada um de seus filhos, exceto o último, aponta para o próximo (prox) irmão. A declaração de um nó pode ser: typedef struct arvgen TArvGen; struct arvgen { char info; TArvGen *prim; TArvGen *prox; };

Exemplo da Solução

Considerações sobre a Solução Uma das vantagens dessa representação é que podemos percorrer os filhos de um nó de forma sistemática, de maneira análoga ao que fizemos para percorrer os nós de uma lista simples. Com o uso dessa representação, a generalização da árvore é apenas conceitual, pois, concretamente, a árvore foi transformada em uma árvore binária, com filhos esquerdos apontados por prim e direitos apontados por prox.

Criação de uma ÁrvoreGen TArvGen* cria (char c) { TArvGen *a; a = (TArvGen *)malloc(sizeof(tarvgen)); a->info = c; a->prim = NULL; a->prox = NULL; return a; }

Inserção Como não vamos atribuir nenhum significado especial para a posição de um nó filho, a operação de inserção pode inserir a sub-árvore em qualquer posição. Vamos optar por inserir sempre no início da lista que, como já vimos, é a maneira mais simples de inserir um novo elemento numa lista encadeada. void insere (TArvGen* a, TArvGen* f) { f->prox = a->prim; a->prim = f; }

Exemplo Criação ÁrvoreGen Com as funções cria e insere como construir a árvore abaixo?

Exemplo Criação ÁrvoreGen /* cria nós como folhas */ ArvGen* a = cria('a'); ArvGen* b = cria('b'); ArvGen* c = cria('c'); ArvGen* d = cria('d'); ArvGen* e = cria('e'); ArvGen* f = cria('f'); ArvGen* g = cria('g'); ArvGen* h = cria('h'); ArvGen* i = cria('i'); ArvGen* j = cria('j');...... /* monta a hierarquia */ insere(c,d); insere(b,e); insere(b,c); insere(i,j); insere(g,i); insere(g,h); insere(a,g); insere(a,f); insere(a,b);

Impressão (pré-ordem) void imprime (TArvGen* a) { TArvGen* p; printf("%c\n",a->info); for (p=a->prim; p!=null; p=p->prox) imprime(p); }

Busca de Elemento int busca (TArvGen* a, char c) { TArvGen* p; if (a->info==c) return 1; else { for (p=a->prim; p!=null; p=p->prox) { if (busca(p,c)) return 1; } } return 0; }

Liberação de Memória O único cuidado que precisamos tomar na programação dessa função é a de liberar as subárvores antes de liberar o espaço associado a um nó (isto é, usar pós-ordem). void libera (TArvGen* a) { TArvGen* p = a->prim; while (p!=null) { TArvGen* t = p->prox; libera(p); p = t; } free(a); }

O FIM Perguntas???