Árvores e Mapas. Luís Lopes. Estruturas de Dados DCC-FCUP

Documentos relacionados
8. Árvores. Fernando Silva DCC-FCUP. Estruturas de Dados. Fernando Silva (DCC-FCUP) 8. Árvores Estruturas de Dados 1 / 38

8. Árvores. Fernando Silva. Estruturas de Dados DCC-FCUP. Fernando Silva (DCC-FCUP) 8. Árvores Estruturas de Dados 1 / 38

ESTRUTURAS DE DADOS E ALGORITMOS ÁRVORE BINÁRIA

LEIC-FEUP 2001/2002 Algoritmos e Estruturas de Dados 1. Árvores-1

Árvores binárias de pesquisa

Árvores. SCC-202 Algoritmos e Estruturas de Dados I. Lucas Antiqueira

Departamento de Ciência de Computadores Estruturas de Dados (CC114)

SUMÁRIO. Fundamentos Árvores Binárias Árvores Binárias de Busca

Departamento de Ciência de Computadores Estruturas de Dados (CC114)

Grupo 2 - Implementação de uma Classe Simples

Árvores Binárias de Pesquisa

Departamento de Ciência de Computadores Estruturas de Dados (CC114)

Exame de Estruturas de Dados 2010.Junho.26

5. Generics, Iterators e Comparable em Java

Árvores. Prof. Byron Leite Prof. Tiago Massoni Prof. Fernando Buarque. Engenharia da Computação. Poli - UPE

Exame de Admissão. Instituto Nacional de Pesquisas Espaciais 18 de setembro de 2018 A: GABARITO

Estrutura de Dados: Aula 3 - Linguagem C

1. Cotação de cada pergunta: / / (Total: 100 pontos) 2. Responda às questões de forma clara e concisa nas folhas de exame.

Árvores. SCC-214 Projeto de Algoritmos. Thiago A. S. Pardo. Um nó após o outro, adjacentes Sem relações hierárquicas entre os nós, em geral

Grupo 2 - Implementação de uma classe simples

Programação Orientada a Objetos

Árvores. Thiago Martins, Fabio Gagliardi Cozman. PMR2300 / PMR3201 Escola Politécnica da Universidade de São Paulo

7. Introdução à Complexidade de Algoritmos

4. Listas, Pilhas, e Filas

4. Listas, Pilhas, e Filas

Árvores. Fabio Gagliardi Cozman. PMR2300 Escola Politécnica da Universidade de São Paulo

Exercícios: Árvores. Universidade Federal de Uberlândia - UFU Faculdade de Computação - FACOM Lista de exercícios de estrutura de dados em linguagem C

Orientação a Objetos AULA 09

Programação Orientada a Objectos - P. Prata, P. Fazendeiro

Árvores de pesquisa. Árvores de pesquisa equilibradas

Ordenação e Pesquisa

PAA-DCC-UFAM. Árvores. Universidade Federal do Amazonas Departamento de Eletrônica e Computação

Aula 7 e 8 Filas e suas Aplicações. Prof. Leticia Winkler

Java Collections Framework II

Árvores. Thiago Martins, Fabio Gagliardi Cozman. PMR2300 / PMR3201 Escola Politécnica da Universidade de São Paulo

ÁRVORES E ÁRVORE BINÁRIA DE BUSCA

Prova 2 PMR3201 1o. semestre 2016 Prof. Thiago Martins

PCC104 - Projeto e Análise de Algoritmos

Filas de prioridade. Algoritmos e Estruturas de Dados AED 2005/2006 AEDA 2009/2010

Prova 2 PMR3201 1o. semestre 2015 Prof. Thiago Martins

Pesquisa em memória primária

Estruturas de Dados. Árvores. Onde Estamos? Introdução à estrutura de dados. Alocação dinâmica de memória. Pilhas. Filas.

Filas de prioridade. Marcelo K. Albertini. 3 de Dezembro de 2013

Teoria dos Grafos Aula 6

Filas de prioridade. Marcelo K. Albertini. 27 de Novembro de 2014

Algoritmos e Estrutura de Dados II. Árvore. Prof a Karina Oliveira.

Grafos: Busca. SCE-183 Algoritmos e Estruturas de Dados 2. Thiago A. S. Pardo Maria Cristina

BCC204 - Teoria dos Grafos

Pedro Vasconcelos DCC/FCUP. Programação Funcional 17 a Aula Tipos abstratos

Programação Funcional 13 a Aula Tipos abstratos

O que é uma árvore. Computadores Zen. Brasil. Internacional. Europa Asia Canada

Conceitos gerais Terminologia Forma de Representação de Árvores Árvores Binárias

Árvores & Árvores Binárias

INF1010 Lista de Exercícios 2

ESTRUTURAS DE DADOS E ALGORITMOS LISTA LIGADA

7. Introdução à Complexidade de Algoritmos

Árvores. Listas e árvores. Árvores. Árvores. Árvores. Árvores 03/11/2011. Listas lineares

Estrutura de Dados. Carlos Eduardo Batista. Centro de Informática - UFPB

Prova 2 PMR2300 1o. semestre 2015 Prof. Thiago Martins

CONCEITO DE ÁRVORE CES-11. A raiz é o único nó que não possui ancestrais. As folhas são os nós sem filhos. Exemplos:

Collections. Programação Orientada por Objetos (POO) Centro de Cálculo Instituto Superior de Engenharia de Lisboa

Linguagem C: Árvores AVL

Árvores Conceitos gerais

Árvores & Árvores Binárias

Inteligência Artificial 04. Busca Sem Informação (Cega) Capítulo 3 Russell & Norvig; Seções 3.4 e 3.5

Árvores Equilibradas. Sumário

ESTRUTURA DE DADOS E ALGORITMOS. Árvores Binárias de Busca. Cristina Boeres

Algoritmos e Estruturas de Dados 2006/2007

Pesquisa em Grafos. Pedro Ribeiro 2014/2015 DCC/FCUP. Pedro Ribeiro (DCC/FCUP) Pesquisa em Grafos 2014/ / 33

Árvores. David Menotti Algoritmos e Estruturas de Dados II DInf UFPR

Arvores binárias. Fonte: PF 14 pf/algoritmos/aulas/bint.html

Árvores. Árvores Binárias. Conceitos gerais Terminologia Forma de Representação de Árvores. Conceitos gerais Operações

Coleções. João Paulo Q. dos Santos

ESTRUTURAS DE DADOS E ALGORITMOS HEAP BINÁRIA

CES-11. Árvores. Conceito de árvore. Definição recursiva de árvore Definições associadas a árvore. Ordenação dos nós de uma árvore

Splaying Tree (Árvore espalhada) Estrutura de Dados II Jairo Francisco de Souza

Arvores, Percursos não recursivos, Arvores heterogêneas. Aula 19

Árvores, Árvores Binárias e Árvores Binárias de Pesquisa. Rui Jorge Tramontin Jr.

Informática Parte 18 Prof. Márcio Hunecke

Exemplo Árvore Binária

Aula T13 BCC202 Árvores. Túlio Toffolo

CIC 111 Análise e Projeto de Algoritmos II

Grafos: Busca. Algoritmos e Estruturas de Dados 2. Graça Nunes

API e Coleções Java. Sérgio Luiz Ruivace Cerqueira

Árvores binárias de pesquisa

Teoria dos Grafos Aula 8

Conjuntos disjuntos. Objectivo resolver eficientemente o problema da equivalência estrutura de dados simples (vector) implementação rápida

AED2 - Aula 04 Vetores ordenados e árvores de busca

Algoritmos e Tipos Abstractos de Informação

Árvore binária - definição

Departamento de Ciência de Computadores Estruturas de Dados (CC114) FCUP 2010/11. 2 o Teste: 20/Junho/2011

Filas de Prioridade e Heaps

ESTRUTURA DE DADOS. Árvores, árvores binárias e percursos. Cristina Boeres

ESTRUTURAS DE DADOS E ALGORITMOS LISTA LIGADA (ABORDAGEM RECURSIVA)

Algoritmos e Estruturas de Dados 2005/2006

Heap Sort. Algoritmos e Estruturas de Dados Verão Cátia Vaz 1

Árvores & Árvores Binárias

Árvores. Algoritmos e Estruturas de Dados I. José Augusto Baranauskas Departamento de Física e Matemática FFCLRP-USP

Transcrição:

Árvores e Mapas Luís Lopes DCC-FCUP Estruturas de Dados

Estruturas não lineares Os arrays e as listas são exemplos de estruturas de dados lineares, cada elemento tem: um predecessor único (excepto o primeiro elemento da lista); um sucessor único (excepto o último elemento da lista). Existem outros tipos de estruturas? um grafo é uma estrutura de dados não-linear, pois cada um dos seus elementos, designados por nós, podem ter mais de um predecessor ou mais de um sucessor.

Árvores Uma árvore é um grafo especial; cada elemento, designado por nó, tem zero ou mais sucessores, mas apenas um predecessor (excepto o primeiro nó, a que se dá o nome de raiz da árvore); são estruturas particularmente adequadas para representar informação organizada em hierarquias; e.g., a estrutura de directórios (ou pastas) de um sistema de ficheiros.

Terminologia Ao predecessor (único) de um nó, chama-se nó-pai; os seus sucessores são os nós-filho; o grau de um nó é o número sub-árvores (ou nós-filho) que descendem desse nó; um nó-folha não tem filhos, tem grau 0; um nó-raiz não tem pai; os arcos que ligam os nós, chamam-se ramos.

Terminologia Chama-se caminho a uma sequência de ramos entre dois nós; uma propriedade importante das árvores é que existe apenas um caminho entre dois quaisquer nós o comprimento de um caminho é o número de ramos nele contido; a profundidade de um nó é o comprimento do caminho desde a raiz até esse nó (a profundidade da raiz é zero); a profundidade de uma árvore é o comprimento do caminho desde a raiz até ao seu nó mais profundo.

Árvores Binárias Uma árvore-binária é uma árvore de aridade 2, isto é, cada nó possui no máximo dois filhos, designados por o filho-esquerdo e o filho-direito.

Tamanho da Árvore e Profundidade Como determinar o número de nós n de uma árvore binária perfeita de profundidade k? O número de nós total é a soma dos nós dos níveis de 0 a k, i.e. nível 0 2 0 = 1 nó nível 1 2 1 = 2 nós......... nível k 2 k nós n 2 0 + 2 1 + 2 2 +... + 2 k = k j=0 2 j Por indução, n = 2 k+1 1.

Tamanho da Árvore e Profundidade Conhecido o número de nós de uma árvore binária perfeita, determinar a sua profundidade k: n = 2 k+1 1 k = log 2 (n + 1) 1 nota: 10 = log 2 (1024), 20 = log 2 (1048576) portanto, apesar de uma árvore binária poder conter muitos nós, a distância da raiz a qualquer folha é relativamente pequena; isto é excelente pois significa que, com algum cuidado, podemos definir algoritmos sobre árvores (e.g., inserção, procura, remoção) que requerem apenas percorrer um caminho cujo tamanho é logarítmico no número de nós da árvore.

Árvores Binárias de Pesquisa Em inglês: Binary Search Tree (BST) Uma árvore binária T diz-se de pesquisa se: T for vazia, ou cada nó de T contém uma chave que satisfaz as condições seguintes: todas as chaves (se existirem) na sub-árvore esquerda da raiz precedem a chave da raiz; a chave da raiz precede as chaves (se existirem) na sub-árvore direita; as sub-árvores esquerda e direita da raiz também são árvores de pesquisa.

Árvores Binárias de Pesquisa Munidos da definição, podemos agora construir uma árvore binária de pesquisa: o primeiro valor fica na raiz da árvore. os seguintes são à esquerda ou direita da raiz, obedecendo à relação de ordem, como folhas e em níveis cada vez mais baixos. Sequência de valores dada: 14,18,4,9,7,16,3,5,4,17,20,15,9,5

Operações do Tipo Abstracto de Dados BSTree As operações associadas a uma árvore binária de pesquisa são: isempty(bstree<k,v>) size(bstree<k,v>) depth(bstree<k,v>) insert(bstree<k,v>, K, V) contains(bstree<k,v>, K) get(bstree<k,v>, K) remove(bstree<k,v>, K) a árvore está vazia? número de nós profundidade adiciona par chave/valor a chave está na árvore? o valor associado à chave remove o nó associado a chave

Implementação: BSTNode.java c l a s s BSTNode <K extends Comparable <? s u p e r K>,V> { K key ; V val ; BSTNode <K,V> left ; BSTNode <K,V> right ; BSTNode ( K k, V v, BSTNode <K,V> l, BSTNode <K,V> r) { key = k; val = v; left = l; right = r; BSTNode (K k, V v) { key = k; val = v; left = n u l l ; right = n u l l ;

Implementação: BSTree.java c l a s s BSTree <K extends Comparable <? s u p e r K>,V> { BSTNode <K,V> root ; BSTree ( BSTNode <K,V> node ) { root = node ; BSTree () { root = n u l l ;

Implementação: LibBSTree.java p u b l i c s t a t i c... boolean isempty ( BSTree <K,V> t) { r e t u r n (t. root == n u l l ); p u b l i c s t a t i c... i n t size ( BSTree <K,V> t) { r e t u r n size (t. root ); p r i v a t e s t a t i c... i n t size ( BSTNode <K,V> n) { i f ( n == n u l l ) r e t u r n 0; e l s e r e t u r n 1 + size (n. left ) + size (n. right ); p u b l i c s t a t i c... i n t depth ( BSTree <K,V> t) { r e t u r n depth (t. root ); p r i v a t e s t a t i c... i n t depth ( BSTNode <K,V> n) { i f ( n == n u l l ) r e t u r n 0; e l s e r e t u r n 1 + Math. max ( depth (n. left ), depth (n. right ));

Implementação: LibBSTree.java p u b l i c s t a t i c... v o i d insert ( BSTree <K,V> t, K key, V val ) { t. root = insert (t.root, key, val ); p r i v a t e s t a t i c... BSTNode <K,V> insert ( BSTNode <K,V> n, K key, V val ) { i f ( n == n u l l ) r e t u r n new BSTNode <K,V >( key, val ); e l s e i n t cmp = key. compareto (n. key ); i f ( cmp == 0 ) n. val = val ; e l s e i f ( cmp < 0) n. left = insert (n.left, key, val ); e l s e n. right = insert (n. right, key, val ); r e t u r n n;

Procura de valores Dada uma árvore binária de pesquisa t e uma chave k, pretende-se verificar se t contém k. Quando se pensa em percorrer uma árvore, deve pensar-se numa solução recursiva em que temos de lidar com três casos: 1. árvore vazia, pelo que a árvore t não contém k 2. nó corrente contém k 3. continuar a procura numa das sub-árvores, de acordo com a relação de ordem entre k e a chave do nó corrente.

Implementação: LibBSTree.java p u b l i c s t a t i c <K extends Comparable <? s u p e r K>,V> boolean contains ( BSTree <K,V> t, K key ) { r e t u r n contains (t.root, key ); p r i v a t e s t a t i c <K extends Comparable <? s u p e r K>,V> boolean contains ( BSTNode <K,V> n, K key ) { i f ( n == n u l l ) r e t u r n f a l s e ; e l s e i f ( key. compareto (n. key ) == 0 ) r e t u r n t r u e ; i f ( key. compareto (n. key ) < 0 ) r e t u r n contains (n.left, key ); e l s e r e t u r n contains (n. right, key );

Implementação: LibBSTree.java p u b l i c s t a t i c <K extends Comparable <? s u p e r K>,V> V get ( BSTree <K,V> t, K key ) { r e t u r n get (t.root, key ); p r i v a t e s t a t i c <K extends Comparable <? s u p e r K>,V> V get ( BSTNode <K,V> n, K key ) { i f ( n == n u l l ) r e t u r n n u l l ; e l s e i f ( key. compareto (n. key ) == 0 ) r e t u r n n. val ; i f ( key. compareto (n. key ) < 0 ) r e t u r n get (n.left, key ); e l s e r e t u r n get (n. right, key );

Remover valores Casos especiais para o nó a remover: nó folha (e.g. remover o 15) nó-interior com apenas um filho (e.g. remover o 3) nó interior com dois filhos (e.g. remover o 14)

Remover valores A operação de remover um nó que contém uma chave k de uma árvore t, caso tal nó exista, é um pouco mais complexa pois a árvore final tem de satisfazer as propriedades de uma árvore binária de pesquisa. 1. localizar o nó com a chave k, seja n esse nó; 2. se n é um nó-folha, simplesmente remove-se o nó; 3. se n é um nó-interior, é necessário mais cuidado para não ficarmos com 2 árvores desconexas: se n só tiver um filho, a sub-árvore pendurada nesse nó toma o lugar de n se n tiver dois filhos, então devemos procurar o nó com menor chave entre os descendentes do filho-direito (ou o maior dos descendentes do filho-esquerdo) para tomar o lugar de n.

Implementação: LibBSTree.java p u b l i c s t a t i c... v o i d remove ( BSTree <K,V> t, K key ) { t. root = remove (t.root, key ); p r i v a t e s t a t i c... BSTNode <K,V> remove ( BSTNode <K,V> n, K key ) { i f ( n!= n u l l ) i f ( key. compareto (n. key ) < 0 ) n. left = remove (n.left, key ); e l s e i f ( key. compareto (n. key ) > 0 ) n. right = remove (n. right, key ); e l s e i f ( n. left == n u l l ) n = n. right ; e l s e i f ( n. right == n u l l ) n = n. left ; e l s e n. right = removemin (n, n. right ); r e t u r n n;

Implementação: LibBSTree.java p r i v a t e s t a t i c... BSTNode <K,V> removemin ( BSTNode <K,V> n1, BSTNode <K,V> n2) { i f ( n2. left == n u l l ) { n1.key = n2.key ; n1.val = n2.val ; r e t u r n n2. right ; e l s e { n2. left = removemin (n1, n2. left ); r e t u r n n2;

Complexidade das BST Para uma árvore binária de pesquisa com n nós: o comprimento médio do caminho da raiz até uma folha é O(log n), correspondente à profundidade da árvore; verificar se v pertence à árvore é assim O(log n); os métodos insert(), contains() e remove() são O(log n); é comum que ao inserirmos n valores aleatórios, a árvore não seja completa, pode até ficar uma sequência ordenada. Neste caso cada inserção é O(n).

Complexidade das BST Uma árvore binária em média estará próxima de uma árvore completa ou de uma sequência? isto decide se o tempo médio é O(log n) ou O(n) é possível demonstrar que a complexidade amortizada é O(log n).

Visita em profundidade O método de pesquisa inorder é particularmente útil para pesquisar os nós de uma árvore de pesquisa binária em que a ordem dos valores (chaves de pesquisa) é crescente. Assim como permite listar por ordem a sequência de valores da árvore. O método de pesquisa inorder (ou depth-first) consiste em visitar a árvore do seguinte modo: 1. sub-árvore esquerda 2. raiz 3. sub-árvore direita

Visita em profundidade (depth-first) A pesquisa inorder equivale a fazer-se o seguinte percurso:

Visita em profundidade (depth-first) p u b l i c s t a t i c <K extends Comparable <? s u p e r K>,V> String tostring ( BSTree <K,V> t) { r e t u r n tostring (t. root ); p r i v a t e s t a t i c <K extends Comparable <? s u p e r K>,V> String tostring ( BSTNode <K,V> n) { i f ( n!= n u l l ) r e t u r n tostring (n. left ) + "(" + n. key + "," + n. val + ")" + tostring (n. right ); r e t u r n "";

Visitas Preorder e Postorder Método preorder: 1. visitar a raiz 2. pesquisar em preorder a sub-árvore esquerda 3. pesquisar em preorder a sub-árvore direita Método postorder: 1. pesquisar em postorder a sub-árvore esquerda 2. pesquisar em postorder a sub-árvore direita 3. visitar a raiz Exercício: implemente estes métodos de pesquisa.

Visita em profundidade não recursiva (com pilha) p u b l i c s t a t i c... v o i d visitdepthfirst ( BSTree <K,V> t) { visitdepthfirst ( t. root ); p r i v a t e s t a t i c... v o i d visitdepthfirst ( BSTNode <K,V> n) { Stack < BSTNode <K,V>> stack = new Stack < BSTNode <K,V > >(); BSTNode <K,V> np = n; w h i l e (( np!= n u l l )! stack. isempty () ) { w h i l e ( np!= n u l l ) { stack. push ( np ); np = np. left ; i f (! stack. isempty () ) { np = stack. pop (); System. out. println ("(" + n. key + "," + n. val + ")"); np = np. right ;

Visita em largura (breadth-first) Um outro método de percorrer os nós de uma árvore é fazê-lo por níveis, i.e. em largura-primeiro (ou breadth-first).

Visita em largura não recursiva (com fila) p u b l i c s t a t i c <K extends Comparable <? s u p e r K>,V> v o i d visitbreadthfirst ( BSTree <K,V> t) { visitbreadthfirst ( t. root ); p r i v a t e s t a t i c <K extends Comparable <? s u p e r K>,V> v o i d visitbreadthfirst ( BSTNode <K,V> n) { Queue < BSTNode <K,V>> queue = new LinkedList < BSTNode <K,V > >(); queue. add (n); w h i l e (! queue. isempty ()) { BSTNode <K,V> np = queue. remove (); System. out. println ("(" + np.key + "," + np.val + ")"); i f ( np. left!= n u l l ) queue. add (np. left ); i f ( np. right!= n u l l ) queue. add (np. right );

Mapas Um mapa é uma estrutura de dados que mantém uma colecção de pares (chave,valor) de tal forma que cada chave ocorre uma única vez na colecção. São também conhecidos como arrays associativos ou dicionários. Exemplo: uma agenda telefónica {(Nuno,960234576), (Clara,960112343), (Laura,919245333) Problema: como implementar de forma eficiente operações de inserção, pesquisa e remoção de elementos? Um solução: implementar o mapa usando uma árvore binária de pesquisa!

Operações do Tipo Abstracto de Dados Map As operações associadas a um mapa são: size(map<k,v>) put(map<k,v>, K, V) get(map<k,v>, K) contains(map<k,v>, K) remove(map<k,v>, K) número de elementos no mapa adiciona par com chave/valor retorna o valor associado a chave verifica se chave ocorre remove par associado a chave

Implementação: Map.java c l a s s Map <K extends Comparable <? s u p e r K>,V> { BSTree <K,V> tree ; Map () { tree = new BSTree <K,V >();

Implementação: LibMap.java c l a s s LibMap <K extends Comparable <? s u p e r K>,V> { p u b l i c s t a t i c... i n t size (Map <K,V> m) { r e t u r n LibBSTree. size (m. tree ); p u b l i c s t a t i c... v o i d put (Map <K,V> m, K key, V val ) { LibBSTree. insert (m.tree, key, val ); p u b l i c s t a t i c... V get (Map <K,V> m, K key ) { r e t u r n LibBSTree. get (m.tree, key ); p u b l i c s t a t i c... boolean contains (Map <K,V> m, K key ) { r e t u r n LibBSTree. contains (m.tree, key ); p u b l i c s t a t i c... v o i d remove (Map <K,V> m, K key ) { LibBSTree. remove (m.tree, key );

Implementação: TestMap.java p u b l i c c l a s s TestMap { p u b l i c s t a t i c v o i d main ( String [] args ) { String phonelist = " Nuno 960234576 Clara 960112343 Laura 919245333 Jorge 939122227 "; Scanner in = new Scanner ( phonelist ); Map < String, Integer > m1 = new Map < String, Integer >(); w h i l e (in. hasnext ()) LibMap. put (m1, in. next (), in. nextint ()); System. out. println (" size : " + LibMap. size (m1 )); System. out. println ( LibMap. tostring (m1 )); System. out. println (" Laura s phone is " + LibMap. get (m1, " Laura " )); System. out. println (" Keys -> " + LibMap. keys (m1 )); Map < Integer, String > m2 = LibMap. invert (m1 ); System. out. println (" the inverted map is as follows... "); System. out. println ( LibMap. tostring (m2 )); System. out. println (" Keys -> " + LibMap. keys (m2 ));