Lista 2 - PMR2300/3200

Documentos relacionados
Lista 2 - PMR2300. Fabio G. Cozman 24 de maio de 2013

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

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

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

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

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

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

Lista 1 - PMR2300. Fabio G. Cozman 3 de abril de 2013

Estruturas de Dados Pilhas, Filas, Listas

Estruturas de Dados Pilhas, Filas, Listas

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

Lista 2 - PMR2300/3200

Introdução à Computação II (Noturno) BCC Unesp Rio Claro/SP 2015 em PDF via Moodle: Escolha apenas 5 exercícios para entrega Exercício 01 (Pilhas)

Edital de Seleção 024/2017 PROPESP/UFAM. Prova de Conhecimento. Caderno de Questões

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

Prova de Recuperação PMR3201/PMR2300 1o. semestre 2015 Prof. Thiago Martins

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

Prova Substitutiva PMR3201 1o. semestre 2018 Prof. Thiago Martins

Bit (Binary Digit) é a menor unidade de armazenamento de informação dentro do computador; Byte é a união de 8 bits capaz de representar 256

Edital de Seleção 023/2018 PROPESP/UFAM. Prova de Conhecimento. Caderno de Questões

Árvores Estrutura de Dados. Universidade Federal de Juiz de Fora Departamento de Ciência da Computação

Pilhas e Filas. Nádia Félix e Hebert Coelho

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

Prova de Recuperação PMR3201 1o. semestre 2017 Prof. Thiago Martins

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

Universidade de São Paulo

Grupo 2 - Implementação de uma classe simples

Tabelas de dispersão/hash

Prof. Jesus José de Oliveira Neto

Programação II. Listas Encadeadas (Linked Lists) Bruno Feijó Dept. de Informática, PUC-Rio

Prof. Jesus José de Oliveira Neto

Lista de Exercícios sobre Listas Implementadas por Encadeamento

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

Estrutura de Dados: Aula 3 - Linguagem C

1. Faça um programa que leia uma string digitada pelo usuário e salve em um arquivo em branco.

Estruturas de Dados Algoritmos de Ordenação

UNIVERSIDADE DE SÃO PAULO ICMC SCC 202 Algoritmos e Estrutura de Dados I - 2º Semestre 2010 Profa. Sandra Maria Aluísio;

Árvores Binárias de Busca (ABB) 18/11

Árvores Binárias de Busca

Grupo 2 - Implementação de uma Classe Simples

INF 1620 P2-23/10/04 Questão 1 Nome:

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

Estruturas de Dados Filas

ESTRUTURA DE DADOS E ALGORITMOS HEAPS E LISTAS DE PRIORIDADES

Árvores. Estruturas de Dados. Prof. Vilson Heck Junior

FILAS. As coisas de que uma fila é feita serão chamadas itens. Os itens podem ser números, strings, structs, etc., etc.

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

Árvores Binárias de Busca (ABB) 18/11

B-Árvores. Siang Wun Song - Universidade de São Paulo - IME/USP. MAC Estruturas de Dados

Universidade Estadual de Mato Grosso do Sul Bacharelado em Ciência da Computação Algoritmos e Estruturas de Dados II Prof. Fabrício Sérgio de Paula

Edital de Seleção 053/2016 PROPESP/UFAM. Prova de Conhecimento. Caderno de Questões

Lista de Prioridades. Estrutura de Dados II Prof. Erinaldo

S U M Á R I O. Definição de Estrutura de Dados. Vetores. Listas Ligadas. Pilhas. Filas

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

Lista de exercícios sobre contagem de operações Prof. João B. Oliveira

Fontes Bibliográficas. Estruturas de Dados Aula 15: Árvores. Livros:

Exame de Estruturas de Dados 2010.Junho.26

ESTRUTURA DE DADOS CIÊNCIA E TECNOLOGIA DO RIO. Curso de Tecnologia em Sistemas para Internet

Estruturas de Dados. Módulo 17 - Busca. 2/6/2005 (c) Dept. Informática - PUC-Rio 1

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

Dicionários. TAD Orientado a conteúdo

Árvores de Pesquisa (Parte I)

Árvore binária - definição

ÁRVORES E ÁRVORE BINÁRIA DE BUSCA

Heaps. Estrutura de Dados. Universidade Federal de Juiz de Fora Departamento de Ciência da Computação 1 / 35

Estruturas de Dados II

ASSOCIAÇÃO PARAIBANA DE ENSINO RENOVADO FACULDADE PARAIBANA DE PROCESSAMENTO DE DADOS ESTRUTURA DE DADOS

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

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

INF1010 Lista de Exercícios 2

Árvores binárias de busca

SCC Algoritmos e Estruturas de Dados II. 6ª lista de exercícios

Lista de Exercícios 04

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

Árvores & Árvores Binárias

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

Escreva em Java a classe NumeroComplexo que represente um número complexo. A classe deverá ter os seguintes construtores:

Algoritmos e Estruturas de Dados I

Prof. Jesus José de Oliveira Neto

Prova Substitutiva PMR3201/PMR2300 1o. semestre 2015 Prof. Thiago Martins

Lista 02: Pilhas & Filas

FICHA 8 PILHAS E FILAS

Árvores de Pesquisa (Parte II)

1. Proponha algoritmos para: a. Calcular a altura dos nós de uma árvore binária dada, armazenando o valor da altura no nó.

Árvores B. Prof. Márcio Bueno. / Fonte: Material da Prof a Ana Eliza Lopes Moura

Árvores & Árvores Binárias

Atividade de laboratório listas encadeadas simples

Universidade Federal de Mato Grosso Estrutura de Dados II

ESTRUTURAS DE DADOS E ALGORITMOS ÁRVORE BINÁRIA

ESTRUTURAS DE DADOS E ALGORITMOS HEAP BINÁRIA

Árvores Binárias de Busca

INF 1010 Estruturas de Dados Avançadas

Fabio G. Cozman, Thiago Martins 2017

Implementando classes em C# Curso Técnico Integrado em Informática Fundamentos de Programação

UFJF - DCC - Estrutura de Dados e Laboratório de Programação II

INF 1010 Estruturas de Dados Avançadas

Filas. Nesta aula veremos o ADT fila Em um computador existem muitas filas esperando pela impressora, acesso ao disco ou, num sistema timesharing,

ICET CURSO: Ciência da Computação e Sistemas de Informação (Estrutura de Dados) Estudos Disciplinares Campus: Data: / / Nome:

Estruturas de Dados Encadeadas

Transcrição:

Lista 2 - PMR2300/3200 Fabio G. Cozman, Thiago Martins 19 de junho de 2015 Alguns exercícios a seguir lista tem implementações em software, com testes, nos arquivos em lista2.zip: Deque.java, ListaLigada.java, Verifique.java, ArvoreBinariaBusca. 1. Escreva uma classe chamada Complexo que opera sobre números complexos. O construtor básico deve ser: Complexo( double a, double b ). Um segundo construtor deve ser providenciado para criar o número real a: Complexo( double a ). Codifique os métodos add(complexo c), subtract(complexo c), multiply(complexo c) e divide(complexo c). 2. Considere que você comprou uma biblioteca contendo a classe Complexo, cujo manual indica: p u b l i c c l a s s Complexo : p u b l i c Complexo ( double a, double b ) ; p u b l i c Complexo add ( Complexo c ) ; p u b l i c Complexo s u b t r a c t ( Complexo c ) ; p u b l i c Complexo m u l t i p l y ( Complexo c ) ; p u b l i c Complexo d i v i d e ( Complexo c ) ; Você deseja criar uma classe como Complexo, porém com métodos adicionais que permitem somar, subtrair, dividir e multiplicar por um número real: p u b l i c Complexo add ( double d ) ; p u b l i c Complexo s u b t r a c t ( double d ) ; p u b l i c Complexo m u l t i p l y ( double d ) ; p u b l i c Complexo d i v i d e ( double d ) ; Codifique uma classe SuperComplexo que contém toda a funcionalidade indicada anteriormente usando o esquema de hierarquias de Java. 3. Considere um programa que contenha um package aeroporto. Temos a classe Pessoa, com atributo int RG, e a classe Passageiro, que é subclasse de Pessoa e tem atributo int ID e método public void access(). Temos também a classe Rota, com atributos private int ID e Aeroporto aeroporto. A classe Aeroporto tem atributo String nome. Finalmente, a classe Reserva tem atributos double valor e Passageiro pass. Escreva código para todas as classes do pacote; não é necessário escrever código no corpo das funções (deixe em branco). DICA: O código para a classe Passageiro é 1

package a e r o p o r t o ; p u b l i c c l a s s P a s s a g e i r o extends Pessoa { i n t ID ; p u b l i c void a c c e s s ( ) { 4. Considere um package denominado escola. Temos as seguintes classes. Classe Pessoa tem atributos public String nome e private int ID. Classe Aluno é subclasse de Pessoa e tem atributos private int numero. Classe Area tem atributo protected int codigo. Classe Habilitacao é subclasse de Area e tem atributo Aluno aluno. (a) Codifique uma implementação simples para cada classe. Se houver membros com acesso não indicado no diagrama de classes, assuma acesso público para esses membros. (b) É possível acessar: codigo em Area a partir de Pessoa? De Aluno? De Habilitacao? De classes em outro pacote? nome em Pessoa a partir de Pessoa? De Aluno? De Habilitacao? De classes em outro pacote? 5. Considere as seguintes classes: Tree (contém uma variável age que é protected) Deciduous extends Tree Evergreen extends Tree Pine extends Evergreen Forest Suponha que todas as classes estão no mesmo package. Desenhe um diagrama de classes simplificado, sem indicar métodos nem variáveis. Quais classes podem acessar a variável age da classe Tree? Suponha agora que todas as classes estejam em packages diferentes; quais classes podem acessar a variável age da classe Tree? 6. Suponha que você está codificando um programa para controle fiscal de uma empresa. As seguintes classes estão sendo planejadas: Classe Pessoa, contendo membros nome (String, public), rg (int, private) e id (int, protected). Classe Cliente, sub-classe de Pessoa, contendo membro categoria (int). Classe Funcionario, sub-classe de Pessoa, contendo membros posicao (int), avaliacao (double, private) e setor (int, protected). Classe Mercadoria, contendo membros nome (String, public), valor (double) e codigoreceita (int, public). Classe Parceiro, sub-classe de Pessoa, com membro codigo (int, protected). 2

As três primeiras classes compõe o pacote pessoas; as demais compõe o pacote produtos. (a) Apresente o código que define cada uma dessas classes com seus membros. [1.0] (b) Quais classes podem acessar: [1.0] Membro id de Pessoa. Membro nome de Mercadoria. Membro categoria de cliente. Membro avaliacao de Funcionario. 7. Descreva a saída da seguinte sequência de operações sobre uma pilha: push(5), push(3), pop(), push(2), push(8), pop(), pop(), push(9), push(1), pop(), push(7), push(6), pop(), pop(). 8. Descreva a saída da seguinte sequência de operações sobre uma fila: enqueue(5), enqueue(3), dequeue(), enqueue(2), enqueue(8), dequeue(), dequeue(), enqueue(9), enqueue(1), dequeue(), enqueue(7), enqueue(6), dequeue(), dequeue(). 9. Qual é o custo em notação BigOh para inserção de um elemento em uma pilha com arranjo como implementado em aula, no pior caso? Justifique. 10. Considere a árvore de expressão abaixo. Nessa árvore, qual é o nó raiz? Quais são as folhas? Qual é a altura da árvore? Qual é a profundidade do nó com dado 10? Qual é a expressão representada pela árvore, em notação infixa (justifique)? - * + + 3 * + 3 1 3 4 10 11 11. Considere a inserção dos seguintes números em uma árvore binária de busca: 30, 40, 24, 58, 48, 26, 11, 13. Desenhe a árvore após cada inserção. 12. Apresente um exemplo que contradiz a seguinte afirmação: a ordem de inserções em uma árvore binária de busca não importa; qualquer que seja a ordem de inserção dos elementos em uma árvore binária de busca, a árvore é a mesma. 13. Uma lista duplamente ligada é uma lista na qual cada nó tem uma ligação para o próximo nó e também para o nó anterior. Uma lista duplamente ligada é frequentemente referida como deque. Apresente o código para achar o nó do meio de um deque. Suponha as seguintes estruturas de classes: c l a s s Deque { Node f i r s t, l a s t ;... / / c o d i g o c o n t e n d o os metodos da c l a s s e ( a c o m p l e t a r ). 3

c l a s s Node { O b j e c t e l e m e n t ; Node next, p rev ;... / / c o d i g o c o n t e n d o os metodos da c l a s s e ( a c o m p l e t a r ). A idéia em um deque é que cada nó aponta para o próximo nó e para o nó anterior na lista. Percorremos um deque fazendo: f o r ( Node p = l i s t a. f i r s t ; p!= n u l l ; p = p. n e x t ) {... Apenas para ilustrar o funcionamento de um deque, suponha que temos um objeto e e queremos achar o nó que contém esse objeto em um deque. Suponha que o deque é o objeto lista. Então podemos fazer: f o r ( Node p = l i s t a. f i r s t ; p!= n u l l ; p = p. n e x t ) { i f ( p. e l e m e n t == e ) break ; Ao fim desse processo, p é o nó que contém e. Uma maneira bastante simple de implementar um deque é fazer o deque com sentinelas ; ou seja, montar uma lista aonde o primeiro e o último nós não contém nenhum dado e servem apenas para garantir que first e last nunca sejam null. Percorremos um deque com sentinelas fazendo: f o r ( Node p = l i s t a. f i r s t. n e x t ; p!= l i s t a. l a s t ; p = p. n e x t ) {... Retornando ao exercício, considere a solução a seguir, que primeiro varre o deque contando o número de nós, e depois vai até a metade (note que estamos usando sentinelas): / / Encontra e l e m e n t o do meio com c o n t a d o r. p u b l i c O b j e c t middleelement ( ) { i n t i = 0 ; Node p, q ; f o r ( p = f i r s t. n e x t ; p!= l a s t ; p = p. n e x t ) { i ++; i n t meio = i / 2 ; i = 0 ; f o r ( q = f i r s t. n e x t ; i < meio ; q = q. n e x t ) { i ++; return ( q. e l e m e n t ) ; 4

É fácil resolver o exercício sem usar contadores para deques com número ímpar do nós. A solução é começar a varrer o deque do início e do final, a cada passo incrementando um lado e decrementando outro, até atingir o mesmo nó (que é o nó do meio). / / Encontra e l e m e n t o do meio sem c o n t a d o r. / / Para deque com numero impar de e l e m e n t o s! p u b l i c O b j e c t middleelementodd ( ) { Node p = f i r s t. n e x t ; Node q = l a s t. prev ; while ( p. e l e m e n t!= q. e l e m e n t ) { p = p. n e x t ; q = q. prev ; return ( p. e l e m e n t ) ; 14. Crie um método para concatenar duas lista ligadas e formar uma nova lista ligada. Discussão: Vamos resolver esse problema assumindo duas listas (listas normais sem sentinelas ), tomando as estruturas: c l a s s L i s t a L i g a d a { Node f i r s t ;... c l a s s Node { O b j e c t e l e m e n t ; Node n e x t ; Então: / / Concatena s t a t i c L i s t a L i g a d a c o n c a t e n a ( L i s t a L i g a d a l i s t a 1, L i s t a L i g a d a l i s t a 2 ) { Node q = n u l l ; / / Achamos o p a i do u l t i m o no de l i s t a 1 : f o r ( Node p = l i s t a 1. f i r s t ; p!= n u l l ; p = p. n e x t ) { q = p ; / / Agora l i g a m o s o u l t i m o no de l i s t a 1 com l i s t a 2 : q. n e x t = l i s t a 2. f i r s t ; / / Montamos a nova l i s t a : L i s t a L i g a d a l = new L i s t a L i g a d a ( ) ; l. f i r s t = l i s t a 1. f i r s t ; return ( l ) ; O custo desse procedimento é O(n), onde n é o tamanho de lista1. 5

15. Apresente um fragmento de código para concatenar dois deques com as estruturas esquematizadas no Exercício 1. Supondo deques sem sentinelas, basta fazer: l i s t a 2. f i r s t. prev = l i s t a 1. l a s t ; l i s t a 1. l a s t. n e x t = l i s t a 2. f i r s t ; Deque l = new Deque ( ) ; l. f i r s t = l i s t a 1. f i r s t ; l. l a s t = l i s t a 2. l a s t ; Note que esse processo destrói os deques iniciais. Para fazer a mesma coisa sem destruir os deques iniciais, é preciso efetivamente criar novos nós para cada um dos nós em lista1 e lista2. Ou seja, é preciso criar um deque nova e varrer os outros dois deques (primeiro lista1 e depois lista2), criando um nó para cada elemento nesses deques. Faça isso como um exercício. Considere agora a concatenação de deques com sentinelas. Isso complica um pouco o código; como um exercício adicional, imagine o que deve ser feito. 16. Codifique um método que troca a posição de dois nós x e y em uma lista ligada. O método deve receber referências aos dois nós, com a seguinte chamada: void t r o q u e ( Node x, Node y ) {... Se tivéssemos que trocar apenas os conteúdos de x e y, seria fácil: O b j e c t temp = x. e l e m e n t ; x. e l e m e n t = y. e l e m e n t ; y. e l e m e n t = temp ; No entanto temos que trocar efetivamente os nós. Para isso, temos que encontrar o pai e o filho de x e y. Vamos assumir que x e y não são null. Fazemos então: / / Troca d o i s nos : void t r o q u e ( Node x, Node y ) { Node paix = n u l l ; Node paiy = n u l l ; f o r ( Node p = f i r s t ; p!= n u l l ; p = p. n e x t ) { i f ( p. n e x t == x ) paix = p ; i f ( p. n e x t == y ) paiy = p ; Node f i l h o X = x. n e x t ; Node f i l h o Y = y. n e x t ; / / Agora fazemos a t r o c a : paix. n e x t = y ; y. n e x t = f i l h o X ; paiy. n e x t = x ; 6

x. n e x t = f i l h o Y ; 17. Codifique um algoritmo para garantir que sequências de caracteres estejam balanceadas em relação a parênteses, colchetes e chaves. O método deve receber uma String contendo uma sequência de caracteres, e verificar o balanceamento dos parênteses, colchetes e chaves. Discussão: O problema aqui é garantir que cada parênteses (ou colchete ou chave) que seja aberto seja também fechado, e que não haja problema na ordem de abertura e fechamento. A solução mais simples é através de uma pilha. Suponha que a entrada do algoritmo seja um arranjo contendo caracteres. Assuma que uma classe Pilha como vista em aula esteja disponível, porém assuma que esta classe manipule diretamente caracteres (ou seja, dê push e pop em caracteres). Assuma que pop retorna um espaço quando a pilha está vazia. Então, colocamos cada abertura na pilha, e retiramos uma abertura quando encontramos um fechamento. Os erros possíveis são: uma abertura nunca é fechada (pilha não está vazia no final), uma abertura não casa com um fechamento, ou um fechamento não tem abertura. / / R e t o r n e f a l s e se ha erro, t r u e se nao ha e r r o : s t a t i c boolean v e r i f i q u e ( char a r r a n j o [ ] ) { P i l h a p i l h a = new P i l h a ( ) ; char t e s t e ; f o r ( i n t i =0; i < a r r a n j o. l e n g t h ; i ++) { i f ( ( a r r a n j o [ i ] == ( ) ( a r r a n j o [ i ] == [ ) ( a r r a n j o [ i ] == { ) ) p i l h a. push ( a r r a n j o [ i ] ) ; / / I n s e r e c a r a c t e r na p i l h a. / / Se fechamento, v e r i f i q u e ; / / lembre que espaco s i g n i f i c a p i l h a v a z i a! i f ( a r r a n j o [ i ] == ) ) { t e s t e = p i l h a. pop ( ) ; i f ( ( t e s t e == ) ( t e s t e!= ( ) ) { return ( f a l s e ) ; / / D e t e c t o u e r r o! i f ( a r r a n j o [ i ] == ] ) { t e s t e = p i l h a. pop ( ) ; i f ( ( t e s t e == ) ( t e s t e!= [ ) ) return ( f a l s e ) ; / / D e t e c t o u e r r o! i f ( a r r a n j o [ i ] == ) { t e s t e = p i l h a. pop ( ) ; i f ( ( t e s t e == ) ( t e s t e!= { ) ) return ( f a l s e ) ; / / D e t e c t o u e r r o! / / P i l h a tem que e s t a r v a z i a! 7

i f ( p i l h a. pop ( )!= ) return ( f a l s e ) ; / / Se chegou a t e aqui, nao ha e r r o : return ( t rue ) ; 18. Codifique um método que inverte uma fila. O método recebe um objeto do tipo FilaAr e deve retornar uma fila invertida. Discussão: Uma solução simples: crie uma pilha; coloque todos os elementos da fila na pilha, em ordem; depois retire todos os elementos da pilha e coloque na fila. Esse procedimento inverte a fila. Escreva o código para praticar. 19. Considere a seguinte expressão em notação pós-fixa (notação polonesa reversa): ABC +C D+ Se A = 2, B = 3, C = 4, D = 5, qual o valor da expressão? Suponha que a expressão é avaliada através de uma pilha; desenhe o conteúdo da pilha ao encontrar cada operando. Solução: A sequência abaixo mostra a pilha em vários momentos do algoritmo, indicando as operações que levam a mudanças na pilha: C B A B C A + C A + B C D C (A + B C) Para os valores indicados, temos 5 + 4(2 + 3 4) = 61. + D + C (A + B C) 20. Escreva um método que recebe uma lista ligada lista, um objeto e e um nó x da lista, e insere um novo nó contendo e antes de x. Solução: A solução é o seguinte método que pode ser inserido na classe ListaLigada: void i n s e r e ( Node x, O b j e c t e ) { / / P r i m e i r o e n c o n t r a p a i de x. f o r ( Node p = f i r s t ; p!= n u l l ; p = p. n e x t ) i f ( p. n e x t == x ) break ; i f ( p == n u l l ) return ; / / Cria novo no. Node novo = new Node ( ) ; 8

novo. e l e m e n t = e ; / / I n s e r e novo no. p. n e x t = novo ; novo. n e x t = x ; 21. Modifique a implementação de fila com arranjo para que o método dequeue reduza o comprimento do arranjo (pela metade) sempre que apenas um quarto do arranjo esteja ocupado. 22. Escreva uma classe que implementa uma fila com arranjo circular, com os métodos enqueue, dequeue (como visto em aula) e com o novo método enqueuefirst, que coloca um objeto como primeiro da fila. Pede-se que o método enqueuefirst tenha custo O(1), exceto nos casos em que o arranjo está cheio (resolva essa situação por amortização). 23. Esquematize um procedimento não recursivo para imprimir uma árvore binária em ordem anterior. Use uma pilha: (a) Inicialize uma pilha e push a raiz na pilha. (b) Repita até que a pilha esteja vazia e não haja mais nenhum nó na árvore: i. Retire o nó que está no topo da pilha, com pop, e imprima esse nó. ii. Tome os filhos do nó que foi retirado e coloque-os na pilha; coloque primeiro o nó direito e depois o nó esquerdo. Esse procedimento garante que todo nó será impresso antes de seus filhos, e todo filho esquerdo de um nó será processado antes do filho direito do nó. Considere como exemplo a seguinte árvore: J C I B D G H A E F A pilha será inicializada e o nó J será colocado na pilha. A partir daí: 9

(a) J será retirado e impresso; I e C serão colocados. (b) C será retirado e impresso; D e B serão colocados. (c) B será retirado e impresso; A será colocado. (d) A será retirado e impresso; nenhum nó será colocado. (e) D será retirado e impresso; F e E serão colocados. (f) E será retirado e impresso; nenhum nó será colocado. (g) F será retirado e impresso; nenhum nó será colocado. (h) I será retirado e impresso; H e G seráo colocados. (i) G será retirado e impresso; nenhum nó será colocado. (j) H será retirado e impresso; nenhum nó será colocado. (k) o processo termina. A ordem de impressão é ABDEHCFG, justamente a ordem anterior. 24. Demonstre que o número máximo de elementos em uma árvore binária de altura h é 2 h 1. Solução: A raiz está na profundidade 0, seus filhos na profundidade 1, e assim por diante. A altura da árvore é igual à maior profundidade de um nó na árvore mais 1. O número máximo de nós ocorre quando todos os nós tem 2 filhos; nesse caso, o número de nós é: h 1 2 i = 2h 1 2 1 = 2h 1. i=0 25. Em uma árvore binária, um nó com 2 filhos é dito completo. Demonstre que o número de nós completos mais um é igual ao número de folhas. Solução: Denote por C o número de nós completos e por F o número de folhas. A maneira mais simples de demonstrar isso é por indução finita. Considere uma árvore com um único nó; nesse caso C = 0 e F = 1 (portanto a afirmação C + 1 = F é verdadeira). Considere agora uma árvore qualquer com n nós e suponha que C + 1 = F vale para essa árvore. Suponha agora que um nó seja adicionado a essa árvore. O pai desse nó tem que ter zero ou um filho (pois a árvore é binária). Se o pai tem zero filhos, o pai é uma folha; a adição do novo nó não muda nem C nem F e portanto C + 1 = F por hipótese. Se o pai tem um filho, agora o pai ficou completo (portanto C foi incrementado) e o novo nó é uma folha nova (portanto F foi incrementado) e o resultado é que C + 1 = F. 26. Considere uma árvore binária de busca (ou seja, todo nó tem uma chave maior que a chave do filho esquerdo e menor que a chave do filho direito). Sabemos que em tal estrutura, uma ordem interior produz uma sequência de nós com chaves em ordem crescente. Suponha que uma árvore binária de busca seja implementada de forma que todo nó mantenha um valor inteiro sizeofsubtree, que 10

armazena o número de nós na sub-árvore com raiz no próprio nó. Por exemplo, se um nó tem dois filhos e esses filhos não tem filhos, então sizeofsubtree é igual a 3. A estrutura básica seria: p u b l i c c l a s s SpecialNode { i n t key ; SpecialNode l e f t, r i g h t ; i n t s i z e O f S u b t r e e ; Codifique um método kth na classe SpecialNode que encontra o k-ésimo elemento na sub-árvore com raiz no nó de chamada o k-ésimo elemento alcançado em ordem interior. Ou seja, se n é um SpecialNode e chamarmos n.kth(3), então o método deve retornar o conteúdo de key no terceiro nó (em ordem crescente) na sub-árvore cuja raiz é n. Assuma que o usuário sempre chama n.kth(j) com um valor de j que é maior ou igual a 1 e menor ou igual ao número de nós na sub-árvore com raiz em n. Para encontrar a solução, imagine um nó A com dois filhos B e C. Suponha que B tenha sizeofsubtree igual a n e C tenha size OfSubtree igual a m. Ou seja, existem n nós antes de A na árvore que começa em A, e m nós depois de A na árvore que começa em A. Ou seja, A é o (n + 1)-ésimo nó. Portanto se tivermos A.kth(j), temos três opções: (a) Se j = n + 1, então A é o nó procurado. (b) Se j < n + 1, então o j-ésimo nó está na sub-árvore com raiz em B. (c) Se j > n + 1, então o j-ésimo nó está na sub-árvore com raiz em C. Temos: p u b l i c c l a s s SpecialNode { i n t key ; SpecialNode l e f t, r i g h t ; i n t s i z e O f S u b t r e e ;... / / E n c o n t r e k esimo e l e m e n t o na ordem i n t e r i o r : i n t k t h ( i n t j ) { i n t n = 0 ; i f ( l e f t!= n u l l ) n = l e f t. s i z e O f S u b t r e e ; i f ( j == ( n + 1 ) ) return ( key ) ; i f ( j < ( n + 1 ) ) return ( l e f t. k t h ( j ) ) ; i f ( j > ( n + 1 ) ) return ( r i g h t. k t h ( j ( n +1) ) ) ; return ( 1); / / Essa u l t i m a l i n h a nunca / / e a t i n g i d a ( apenas para c o m p i l a r ). 11

... Note que o problema assume que kth nunca é chamado com um valor menor que um ou maior que o número total de nós, portanto não é preciso verificar essas condições. Tente imaginar o que mudaria se essas condições tivessem que ser verificadas; seria preciso verificar o número de nós no filho direito para evitar estouro. 27. Dada a árvore abaixo, imprima os nós em ordem interior, ordem anterior, e ordem posterior. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Solução: Ordem posterior: 4, 15, 12, 8, 18, 16, 13, 9, 5, 2, 6, 10, 17, 14, 11, 7, 3, 1. Ordem interior: 4, 2, 8, 15, 12, 5, 9, 16, 18, 13, 1, 6, 3, 10, 7, 17, 14, 11. Ordem anterior: 1, 2, 4, 5, 8, 12, 15, 9, 13, 16, 18, 3, 6, 7, 10, 11, 14, 17. 28. Considere uma estrutura de pilha como visto em aula na classe PilhaAr (ou seja, uma pilha implementada com arranjo). Temos um arranjo básico de armazenamento chamado arranjo e um inteiro topo que indica o topo da pilha; se topo é igual a -1, a pilha está vazia. Codifique um método insira(object e, int i) que insere o objeto e na pilha na posição i. O objeto e deve ser inserido apenas se i for maior ou igual a zero ou menor ou igual à posição do topo da pilha. Solução: Um possível método a ser inserido na classe PilhaAr é: p u b l i c void i n s i r a ( O b j e c t e, i n t i ) { i f ( ( i <0) ( i > t o p ) ) / / Condicoes em que nada a c o n t e c e. return ; 12

/ / I n s e r e : topo ++; i f ( topo == a r r a n j o. l e n g t h ) d o u b l e A r r a y ( ) ; / / Metodo que d u p l i c a a r r a n j o, / / v i s t o em aula. f o r ( i n t j = t opo ; j > i ; j ) a r r a n j o [ j ] = a r r a n j o [ j 1] a r r a n j o [ i ] = e ; 29. Considere uma linguagem onde os caracteres tem a seguinte distribuição (indicamos espaço por [ ] ): D E M O R A [ ] 10 18 9 20 12 23 8 Para essa linguagem, monte o código de Huffman. Codifique a palavra DE- MORA no código obtido. Usando o código obtido, qual seria o tamanho médio de um texto com 100 caracteres? 30. Suponha que uma árvore binária contém um caracter em cada nó. A ordem interior de visita aos nós produz a sequência ABCEDFJGIH. A ordem anterior de visita aos nós produz a sequência JCBADEFIGH. Desenhe uma árvore binária que produza essas ordens. Para resolver, note que a ordem anterior de uma árvore sempre começa pela raiz, enquanto que a ordem interior tem a sub-árvore esquerda antes da raiz, e a sub-árvore direita depois da raiz. Assim: 13

J C I B D G H A E F 31. Uma classe que implementa árvores binárias tem a seguinte definição: p u b l i c c l a s s N o A r vorebinaria { p r i v a t e i n t dado ; p r i v a t e N o A r v o rebinaria esquerdo, d i r e i t o ; p u b l i c N o A r v o r ebinaria ( i n t d ) { dado = d ; e s q u e r d o = n u l l ; d i r e i t o = n u l l ;... / / I n s e r i r, remover, e t c. Deseja-se incluir nessa classe um método que faça busca por nível em árvore, a partir de um nó que chama o método: p u b l i c i n t b u s c a P o r N i v e l ( i n t d ) {. / / Retorna 1 se e n c o n t r o u d ; r e t o r n a 0 caso c o n t r a r i o. Descreva um algoritmo que realiza busca por nível e escreva a função buscapornivel. Qual é a complexidade da busca implementada no pior caso, para árvore contendo N nós, em notação BigOh? Discussão: use uma estrutura de dados auxiliar; recursão direta na árvore não resolve essa questão. 14

32. Considere a árvore binária de busca abaixo, onde estão indicadas as chaves em cada nó. 10 5 40 2 6 30 50 1 3 7 45 4 9 41 46 47 O que acontece se a raiz é removida? Discussão: Existem duas alternativas: ou substituímos 10 pelo maior elemento à sua esquerda (no caso, 9) e removemos esse elemento, ou substituímos 10 pelo menor elemento à sua direita (no caso, 30) e removemos esse elemento. 33. Considere o seguinte algoritmo de ordenação de um vetor no qual todos os itens são distintos: Adicione os elementos do vetor sequencialmente a uma árvore binária de busca Percorra a árvore na ordem interior e escreva os valores dos nós sequencialmente ao vetor. (a) Mostre que este algoritmo termina em tempo finito e efetivamente produz uma ordenação do vetor. (b) Qual o complexidade deste algoritmo em termos do tamanho do vetor N? Item a): Esta demonstração usa propriedades conhecidas de árvores binárias de busca. A primeira parte realiza um número finito (N) inserções na árvore binária. Cada inserção pode ser feita em um tempo finito, logo a primeira parte é concluída em tempo finito. A segunda parte percorre a árvore na ordem interior, outra operação que leva tempo finito. Assim, todo o algoritmo é concluído em tempo finito. Finalmente, percorrer uma árvore binária de busca produz uma ordenação de seus elementos. Ora, estes elementos são elementos originais do vetor, assim, o algoritmo efetivamente produz uma ordenação dos elementos do vetor. Item b): A complexidade é resultado da soma da complexidade das duas operações. A segunda parte é feita em tempo O(N), pois ela percorre cada nó da árvore, que tem no final a mesma quantidade de nós que o vetor original. A primeira parte depende da estrutura da árvore, e consequentemente da ordem original dos elementos do vetor. Uma operação de inserção em uma árvore leva 15

no pior caso O(H), onde H é a altura da árvore. A árvore, no pior caso, tem uma altura que é O(n), onde n é o número de elementos já inseridos (por exemplo, uma árvore na qual todas as subárvores esquerdas estão ausentes). Assim, cada inserção tem complexidade O(n). A complexidade total é: N O(n) = O(N 2 ) n=1 34. Repita o item b) do exercício anterior considerando agora o uso de uma árvore AVL: Item b): Novamente, a complexidade é resultado da soma da complexidade das duas operações, e novamente a segunda parte pode ser feita em tempo O(N). A primeira parte, no entanto, tem uma complexidade diferente. De fato, agora a árvore tem no pior caso uma altura que é O(log n), onde n é o número de elementos já inseridos. A complexidade total é: N O(log n) = O(N log N) n=1 35. Considere que um texto foi codificado usando os caracteres na tabela abaixo. A tabela indica a frequência com que cada caracter apareceu no texto: a d i m n o q r x espaço 27 10 18 3 4 5 2 7 1 23 Obtenha o código de Huffman para esse texto. Codifique a mensagem adiado o dia do xaxa no código gerado. Se o texto original continha 10.000 caracteres, qual o tamanho do texto em bits após a compressão usando o código gerado? 36. Considere o heap formado pelo vetor de números {10, 7, 9, 5, 3, 2, 8, 4, 3, 2, 2, 0. Mostre o heap resultante da remoção do seu elemento de maior valor. O processo de remoção consiste em substituir temporariamente o elemento da primeira posição com o da última (único removível sem movimentação no vetor). Em seguida, reparar o heap de cima para baixo (com a função FixHeapDown vista em sala). Antes do reparo o heap é: 0 7 9 5 3 2 8 4 3 2 2 O reparo no nível, que troca o 0 pelo 9, produz o heap: 9 7 0 5 3 2 8 4 3 2 2 16

No nível 2 o reparo troca o 8 pelo 0: 9 7 8 5 3 2 0 4 3 2 2 Finalmente, não há mais descendentes do nó 0, e este é o resultado final. 37. Em um heap, quais são as possíveis posições para o menor elemento? Escreva um algoritmo para encontrar o menor elemento em um heap. Qual a complexidade deste algoritmo em função do número total de elementos N? Em um heap, o menor elemento necessariamente não possui descendentes. Assim, qualquer posição na qual ele não possui nenhum descendente é válida para ele. Deste modo, a primeira posição válida para o menor elemento é imediatamente após o pai da última subárvore do heap. Em uma linguagem com índices baseados em zero, os índices legais para um vetor de tamanho N vão de 0 a N 1. O índice do último elemento válido é assim N 1. O endereço de seu pai é (N 2)/2. Finalmente, o endereço do primeiro elemento sem descendentes é (N 2)/2 + 1. Assim, o menor elemento pode estar em qualquer posição de (N 2)/2 + 1 a N 1. O algoritmo em java varreria o espaço de (N 2)/2 + 1 a N 1 a busca do seu menor elemento. Não há como melhorar este algoritmo, visto que qualquer posição neste intervalo é válida para o menor elemento. A complexidade é O(N/2) que é O(N). 38. Um resultado fundamental para a análise da construção de um heap de baixo para cima (com FixHeapDown) é o de que no heap o número de nós no nível h é no máximo N/2 h, onde N é o número total de elementos da árvore. Demonstre este resultado. Sabe-se que o número total de nós na altura h do heap é de no máximo 2 H h, onde H é a altura de todo o heap. Ora, mas o número total de elementos de um heap de altura H é limitado superiormente por 2 H 1. Assim, N/2 h é o limite superior para elementos no heap com altura h. 39. Um algoritmo de ordenação é dito estável se ele não altera a posição relativa de elementos de valor de comparação igual. Por exemplo, considere a ordenação alfabética de caracteres, independentemente da letra ser maiúscula ou minúscula. Um algoritmo estável produziria a seguinte ordenação da cadeia cbhebhbhje: bbbceehhhj. Um algoritmo não-estável poderia, por exemplo, produzir a seguinte ordenação: BbbcEehhHj. O heapsort é um algoritmo de ordenação estável? Justifique. 17

O heapsort não é um algoritmo estável. Para demonstrálo, basta um contraexemplo (naturalmente, exemplos não são suficientes para demonstrar a estabilidade de um algoritmo). Tomemos o exemplo do enunciado, e consideremos o heap construído com a função FixHeapDown: Após a construção do heap o vetor é: jhheehbbcb. Após a ordenação o vetor é: BbbcEehHhj. Nota-se que a ordem relativa dos elementos b, b e B é distinta da original (entre outras alterações). 40. Escreva, usando como molde a classe FilaAr (presente no pacote br.usp.poli.pmr2300.aulas2015.e no arquivo pmr3200demo.zip) uma class FilaPrioritariaAr. Esta classe recebe objetos que implementam a interface comparavel descrita a seguir: public interface comparavel { public boolean menorque(comparavel x); Implemente os métodos public void enqueue(comparavel x) e public comparavel dequeue(). A função dequeue() deve retornar o maior elemento enfileirado em tempo log N, onde N é o número de elementos armazenados. A função enqueue(comparavel x) deve inserir um novo elemento em tempo amortizado log N. O caso em que o vetor base está cheio e deve ser duplicado para permitir inserção de novos elementos deve consumir tempo N. Discussão: A estrutura base é um vetor, como na classe FilaAr. Este vetor deve formar um heap. A função FixHeapUp pode ser usada para adicionar um novo elemento, adicionando-o ao final do vetor e consertando-o levando o elemento para cima na hierarquia até o local apropriado. A função FixHeapDown pode ser usada para retirar o maior elemento, substituindo-o pelo último e consertando-o levando o último elemento para baixo na hierarquia até o local apropriado. 41. Considere uma hashtable de encadeamento separado, na qual são inseridas árvores binárias de busca. Cada árvore contém N nós, e cada nó contém um dado. Suponha que N árvores foram inseridas na hashtable, e que todos os dados em uma determinada árvore sejam mapeados no mesmo elemento (bucket) da hashtable. Suponha primeiro que houve espalhamento perfeito, ou seja, cada posição da hashtable contém apenas uma árvore. Assuma que toda árvore inserida na hashtable está balanceada. Qual é a complexidade de encontrar um dado nessa estrutura, no pior caso, em notação BigOh? Agora abandone a suposição que as árvores estão balanceadas. Qual é a complexidade de encontrar um dado nessa estrutura, no pior caso, em notação BigOh? Agora suponha que não houve espalhamento perfeito. 18

Assuma que toda árvore inserida na hashtable está balanceada. Qual é a complexidade de encontrar um dado nessa estrutura, no pior caso, em notação BigOh? Agora abandone a suposição que as árvores estão balanceadas. Qual é a complexidade de encontrar um dado nessa estrutura, no pior caso, em notação BigOh? 19