PMR 2300 - Computação para Automação

101
PMR 2300 - Computação para Automação Fabio Gagliardi Cozman 15 de abril de 2011

Transcript of PMR 2300 - Computação para Automação

Page 1: PMR 2300 - Computação para Automação

PMR 2300 - Computação para Automação

Fabio Gagliardi Cozman

15 de abril de 2011

Page 2: PMR 2300 - Computação para Automação

Prefácio

O objetivo da disciplina PMR2300 é apresentar um conjunto deferramentas usa-das para programação profissional: programação orientada aa objetos, algoritmos,análise de complexidade, estruturas de dados. O curso utiliza a linguagem de pro-gramação Java para programação. Esta apostila segue a sintaxe da linguagem Javaem seus exemplos.

O curso aborda os seguintes tópicos:

• Linguagem Java e orientação a objetos.

• Algoritmos (busca, ordenação).

• Estruturas de dados (listas, pilhas, filas, árvores, hashtables, grafos).

O uso de material adicional sobre a linguagem Java é recomendado; existeconsiderável quantidade de material sobre esta linguagem em livros e em formatoeletrônico. O restante deste capítulo faz um breve resumo deaspectos importantesda linguagem Java.

Esta apostila foi produzida a partir de notas de aulas, e contou com contribui-ções de vários alunos monitores do curso de Engenharia Mecatrônica da EPUSP.Em particular, agradecimentos a Marcos Tsuchie, Geraldo Gobitsch Bisneto, ZhaoQiyan, André Emil Getschko, Cassio Bertrand Gasparian Colello, Isabela Fernan-des Lauletta, Ricardo pereira Beato Júnior, Henrique Borsatti Lisboa.

1

Page 3: PMR 2300 - Computação para Automação

Capítulo 1

Linguagem Java: aspectosprocedurais

A linguagem Java foi criada a partir de um projeto conduzido pela empresa SunMicrosystems entre 1990 e 1995. Em 1995 a linguagem foi distribuída como fer-ramenta para programação na World-Wide-Web e ganhou grandepopularidade.

A linguagem tem sintaxe básica bastante similar à linguagemC, com adição deelementos de programação orientada a objetos. Além da linguagem em si, existetambém uma padronização da linguagem de execução (denominadabytecode), dasbibliotecas e das ferramentas de programação; toda essa estrutura é denominadaplataforma Java. A plataforma é neutra a arquiteturas, pois o código fonte é com-pilado para bytecodes que são então interpretados por uma máquina Java virtual(JVM) instalada no computador de interesse.

Considere o exemplo abaixo, cujo objetivo é indicar como a linguagem Java separece com C.

/∗ Classe Echo para t e s t e .∗ /pub l i c c l a s s Echo {

/ / Esse é o metodo p r i n c i p a l .pub l i c s t a t i c void main ( S t r i n g [ ] a r gs ) {

f o r ( i n t i = 0 ; i < a r gs . l e n g t h ; i ++)System . ou t . p r i n t l n ( a r gs [ i ] ) ;

System . e x i t ( 0 ) ;}

}

1.1 Aspectos básicos da linguagem

Os tipos de dados primitivos são:

• boolean (valores true ou false).

2

Page 4: PMR 2300 - Computação para Automação

• char (caracteres em Unicode, usando 2 bytes).

• byte, short, int, long (inteiros usando respectivamente 1,2, 4 e 8 bytes).

• float, double (reais em formato IEEE usando respectivamente4 e 8 bytes).

Uma variável cujo tipo é um tipo primitivo está armazenada noStack do programaem execução.

Além desses tipos primitivos existem os tipos criados por recursos de orienta-ção a objetos. Um desses tipos é especial: o tipo String permite o uso do operador“+” para concatenação. Ou seja,

“oi” + “ pessoal” resulta na String “oi pessal”.

Além disso, Java conta com os operadores usados na linguagemC:

• Incremento e decremento (avaliação anterior):expr++ expr--

• Incremento e decremento (avaliação posterior):++expr --expr

• Unários:+expr -expr ~ !

• Aritméticos (maior precedência):* / %

• Aritméticos:+ -

• Movimentação:<< >> >>>

• Relações:< > <= >= instanceof

• Igualdade:== =!

• Bits: & ^ |

• Lógicos:&& ||

• Atribuição:= += -= *= /=%= &= ^= |= <<= >>= >>>=

O fluxo de um programa em Java é controlado através das seguintes palavrasreservadas, cuja sintaxe e semântica são iguais à linguagemC:

• if, else.

• for

• while

• do, while

• switch, break

3

Page 5: PMR 2300 - Computação para Automação

Um aspecto importante da linguagem Java é que todo arranjo deve ser primeirodeclarado e então alocado. A variável que representa um arranjo é umareferênciae mantém o endereço do conteúdo do arranjo. As referências são armazenadas noStack e o conteúdo dos arranjos são armazenados no Heap.

Considere a linha de código:

i n t [ ] a= new i n t [ 1 0 ] ;

Temos:

• int[] → tipo;

• a→ nome;

• new→ necessário para reservar memória;

• [10] → tamanho.

Uma sintaxe alternativa, mais próxima da sintaxe da linguagem C, é:

i n t a [ ] = new i n t [ 1 0 ] ;

Outros exemplos:

i n t b [ ] ; / / apenas de c l a r a .b= new i n t [ 2 0 ] ; / / a loca .double c [ ] [ ] = new double [ 2 ] [ 2 ] ; / / de c l a r a e a loca .double d [ ] [ ] = new double [ 2 ] [ ] ; / / de c l a r a e a loca .c [0 ]= new double[ 2 0 ] ; / / a loca .c [1 ]= new double[ 3 0 ] ; / / a loca .

Todo arranjoa é automaticamente associado a uma variávela.length queretorna o tamanho do arranjo. O primeiro elemento de um arranjo a tem índice 0 eo último elemento dea tem índicea.length.

Exemplos:

a [ i ]=138 ;a [ i ] [ i +1 ]=2.3 + x [ i ] [ i ] ;i =a . l e n g t h ;j =x [ 4 ] . l e n g t h ;s=new s t r i n g [ 5 ] ;y=s [ ( s . l e n g t h − 1 ) ] ;

O seguinte exemplo inicialize um arranjo bidimensional:

i n t t [ ] [ ] = new i n t [ 1 0 ] [ ] ;f o r ( i n t i =0; i < t . l e n g t h ; i ++) {

t [ i ]= new i n t [ i + 1 ] ;f o r ( i n t j =0; j <( i + 1 ) ; j ++)

t [ i ] [ j ]= i + j ;}

4

Page 6: PMR 2300 - Computação para Automação

STACK

HEAP

Figura 1.1: Stack e Heap, indicando o armazenamento de referências e do conteúdode arranjos.

O seguinte exemplo copia o conteúdo de um arranjo em outro:

i n t a [ ] = new i n t [ b . l e n g t h ] ;f o r ( i n t i =0; i <b . l e n g t h ; i ++)

a [ i ]= b [ i ] ;

Como já indicado, as variáveis que denotam arranjos sãoreferências; estasvariáveis apenas guardam endereços de memória. Portanto, se fizermos:

i n t x [ ] = new i n t [ 1 0 ] ;

temos quex guarda o endereço de um arranjo com 10 elementos.

Obs.:

• Na linguagem C, referências são chamadasponteiros.

• Uma referência sem memória reservada tem valornull.

A organização da memória de um programa é controlada pelo sistema operacional(S.O.). De forma bastante geral e esquematizada, temos:

S.O. Programa Stack Heap︸ ︷︷ ︸

Memória

Toda alocação de memória para arranjos é feita de formadinâmicaem Java; ouseja, a quantidade de memória alocada é determinada duranteexecução. A memó-ria alocada por um programa sempre é liberada pelo S.O. quando o programa chegaao fim. Existem linguagens que têm mecanismos para permitir que o programadorlibere a memória. Em Java essa liberação é feita automaticamente (denominadagarbage collection).

5

Page 7: PMR 2300 - Computação para Automação

1.2 Plataforma Java: pontos importantes

1.2.1 Pacotes importantes

1. java.beans

2. java.io

3. java.lang

(a) ref

(b) reflect

4. java.math

5. java.net

6. java.security

(a) acl

(b) cert

(c) interfaces

(d) spec

7. java.text

8. java.util

(a) jar

(b) zip

9. java.awt

Além disso, SWING(interface gráfica) e criptografia, conectividade, bases dedados, etc.

1.2.2 Classes importantes

String

String S = “exemplo” + “!”;Método toString() em todo objeto→ usado para imprimir.

1. s.length();

2. s.substring(4); // de 4 ao final

3. s.substring(4,6); // caracteres 4 e 5

6

Page 8: PMR 2300 - Computação para Automação

4. s.charAt(3);

5. s.toCharArray();

6. s.toUpperCase();

7. s.toLowerCase();

8. s.startsWith(“ab”);

9. s.endsWith(“ab”);

10. s.compareTo(“ab”);

(a) < 0 ses < “ab′′

(b) = 0 ses = “ab′′

(c) > 0 ses > “ab′′

11. s.compareToIgnoreCase();

12. s.indexOf(“ab”);

Byte, Short, Integer, Float, Double (extends Number)

Métodos: X.parseX(s)→ transforma String s em tipo primitivo; Integer.toBinaryString(intx); Integer.toOctalString(int x).

Math

Métodos: Math.cos,sin,tan,acos,atan,exp,log,pow,ceil,floor,round,toDegrees.(Em java.math: BigInteger, BigDecimal).

System

Métodos:

1. exit(x);

2. currentTimeMillis();

3. arrayCopy(a1, p1, a2, p2, n).

Membros:

1. PrintStream out, err;

2. InputStream in.

7

Page 9: PMR 2300 - Computação para Automação

Arrays e Collections

A partir de Java 1.2 foram adicionados à linguagem classes e métodos para realizar:

• busca e ordenação em arranjos

• manipulação de estruturas de dados

– listas ligadas

– árvores

1.2.3 Rede: pacote java.net

Conexão com rede em vários protocolos.

1.2.4 Arquivos

Pacote java.io

• Classe File→ permite manipular diretórios e arquivos (descobrir tamanhos,datas, permissões, listas).

• InputStream e OutputStream→ ler e escrever sequências de bytes.

• Reader e Writer→ ler e escrever sequências de caracteres.

1.2.5 Ler console

import j a va . i o .∗ ;

B u f f e r e d Reader c =newB u f f e r e d Reader (new I npu tS t reamRea de r ( System . i n ) ) ;

S t r i n g n ;

t r y {n = c . r e a dL i ne ( ) ;

} catch ( IOExcept ion e ) {}

1.2.6 Ler de arquivo

S t r i n g f i l e na m e = " hey . t x t " ;t r y {

B u f f e r e d Reader br =new B u f f e r e d Reader (new F i l e R e a de r ( f i l e na m e ) ) ;S t r i n g l i n e = br . r e a dL i ne ( ) ; / / A l t e r n a t i v a parawhi le ( l i n e != n u l l ) / / e s t e t r e c h o

8

Page 10: PMR 2300 - Computação para Automação

System . ou t . p r i n t l n ( l i n e ) ; / / em segu idabr . c l o s e ( ) ;

} catch ( IO Excep t ion e ) {}

/∗ A l t e r n a t i v a∗ /S t r i n g l i n e ;whi le ( ( l i n e = br . r e a dL i ne ( ) ) != n u l l )

System . ou t . p r i n t l n ( l i n e ) ;br . c l o s e ( ) ;

1.2.7 Escrever em arquivo

t r y {F i l e f = new F i l e ( " hey . t x t " ) ;P r i n t W r i t e r pw = new P r i n t W r i t e r (new F i l e W r i t e r (A ) ) ;pw . p r i n t l n ( "Hey ! " ) ;pw . c l o s e ( ) ;

} catch ( IO Excep t ion e ) {}

1.2.8 Outros Métodos

Existem muitos outros métodos para:

1. ler de arquivos binários

2. ler de strings

3. ler da rede

4. ler dados comprimidos

5. ler dados criptografados

6. escrever nas mesmas condições

1.2.9 Collections

Até Java 1.1, tínhamos na plataforma Java:

• Vector: sequência de itens com tamanho variável, implementada com ar-ranjo;

• Stack: implementação de Pilha;

• Hashtable: implementação de Hashtable.

Após Java 1.1 foram introduzidas várias classes:

9

Page 11: PMR 2300 - Computação para Automação

Set

HashSet TreeSet

List

Vector

Collection

SequentialList

Stack LinkedList

Map

HashMap TreeMap

Figura 1.2: Classes em Java.

10

Page 12: PMR 2300 - Computação para Automação

Capítulo 2

Análise de Algoritmos,Ordenação, Busca, e Recursão

Um algoritmo é um procedimento descrito passo a passo para resolução de umproblema em tempo finito. Algoritmos são julgados com base emvários fatores:

• tempo necessário para seu entendimento e codificação;

• dificuldade de manutenção;

• consumo de memória;

• eficiência de execução.

Quanto à eficiência de execução, vários fatores se inter-relacionam:

• qualidade do código;

• tipo do processador;

• qualidade do compilador;

• linguagem de programação.

Conside um exemplo onde queremos encontrar o máximo valor emum arranjode inteiros. Um algoritmo simples é varrer o arranjo, verificando se cada elementoé o maior até o momento (e caso seja, armazenando esse elemento). A seguintefunção implementa esse algoritmo:

i n t arrayMax (i n t a [ ] ) {i n t cur rentMax =a [ 0 ] ;f o r ( i n t i =1; i <a . l e n g t h ; i ++) {

i f ( cur rentMax < a [ i ] )cur rentMax =a [ i ] ;

}re tu rn ( cur rentMax ) ;

}

11

Page 13: PMR 2300 - Computação para Automação

Uma questão importante é como definir a complexidade de uma algoritmo.Qual é a “complexidade” da funçãoarrayMax? Suponha que queiramos contaras operações. Denote porn o tamanho do arranjoa.Temos:

(2 + (n− 1)) atribuição(1 + 2n) referência(2(n − 1)) comparação(n− 1) incremento(6n− 1)→ total

Se cada operação tem custo unitário,(6n−1) é o custo total. Porém, na práticanão sabemos o custo de cada operação, que depende do processador e seus peri-féricos, bem como das características do compilador utilizado. Seria interessanteusar um método de análise de complexidade menos dependente do ambiente deprogramação. Ou seja, a complexidade seria uma propriedadedo algoritmo e nãoda implementação.

Consideremos outro exemplo no qual temos dois métodos para resolver o mesmoproblema, cada um dos quais com uma complexidade diferente.Suponha que te-nhamos um arranjox e que queiramos calcular outro arranjoa tal que:

a[i] =

∑ij=0 x[j]

i+ 1.

Uma solução é:

double [ ] medias (double x [ ] ) {double a [ ] = new double[ x . l e n g t h ] ;f o r ( i n t i =0; i <x . l e n g t h ; i ++) {

double temp = 0 . 0 ;f o r ( i n t j =0; j <= i ; j ++)

temp=temp+x [ j ] ;a [ i ]= temp / ( (double ) ( i + 1 ) ) ;

}re tu rn ( a ) ;

}

Qual é o custo desta função?Note que o loop interno rodan vezes, onden é o tamanho dex. Em cada uma

dessas vezes, temos um número de operações proporcional a

1 + 2 + 3 + · · ·+ (n− 1) + n,

ou seja,n−1∑

i=0

(i+ 1) =n(n+ 1)

2=

n2 + n

2.

Portanto o custo total deverá ser aproximadamente quadrático em relação ao tama-nho dex.

12

Page 14: PMR 2300 - Computação para Automação

Uma outra solução para o mesmo problema é:

double [ ] med iasL inear (i n t x [ ] ) {double a [ ] = new double[ x . l e n g t h ] ;double temp = 0 . 0 ;f o r ( i n t i =0; i <x . l e n g t h ; i ++) {

temp=temp+x [ i ] ;a [ i ]= temp / ( (double ) ( i + 1 ) ) ;

}re tu rn ( a ) ;

}

Essa solução envolve basicamenten operações (há um custo fixo e um custopara cada elemento dex); o custo total é proporcional an.

Como capturar a “essência” da complexidade de um algoritmo?Precisamos dealgum método qualitativo que capture essa essência sem se perder em detalhes ir-relevantes. Na próxima seção vamos continuar a discussão, usando como exemploo problema de ordenação.

2.1 Ordenação

A ordenação de sequências é um dos mais importantes problemas em computação,dado o enorme número de aplicações que a empregam.

Consideraremos dois algoritmos para ordenar sequências. Em primeiro lugar,ordenaçãopor seleção(em ordem decrescente).

pub l i c s t a t i c void ordena (i n t a [ ] ) {f o r ( i n t i =0; i <a . l e n g t h ; i ++) {

i n t jmax= i ;i n t max =a [ i ] ;

f o r ( i n t j = i +1; j <a . l e n g t h ; j ++) {i f ( a [ j ] >max ) {

max=a [ j ] ;jmax= j ;

}}i n t temp=a [ i ] ;a [ i ]=max ;a [ jmax ]= temp ;

}}

A complexidade desse algoritmo é quadrática no tamanhon dea, pois é pro-porcional a

(n− 1) + (n− 2) + · · ·+ 2 + 1 =(n− 1)n

2=

n2 − n

2.

13

Page 15: PMR 2300 - Computação para Automação

Em segundo lugar, consideraremos ordenaçãopor inserção(em ordem cres-cente):

pub l i c s t a t i c void ordena (i n t a [ ] ) {f o r ( i n t i =1; i <a . l e n g t h ; i ++) {

i n t temp = a [ i ] ;i n t j = i ;/ / V o l t a para e nc on t r a r l uga r .whi le ( ( j >0)&&( temp <a [ j −1]) ) {

a [ j ] = a [ j −1];j −−;

}a [ j ] = temp ;

}}

O seguinte sequência ilustra o funcionamento de ordenação por inserção emordem crescente:

6 | 3 4 5 9 83 6 | 4 5 9 83 4 6 | 5 9 83 4 5 6 | 9 83 4 5 6 9 | 83 4 5 6 8 9

Note que a complexidade de ordenação por inserção varia com aentrada! Opior caso é aquele em que o arranjo está ordenado em ordem decrescente; o melhor,aquele em que o arranjo já está ordenado em ordem crescente. No melhor caso, ocusto é proporcional an. No pior caso, o custo é proporcional a

1 + 2 + · · ·+ (n− 1) + n =n(n+ 1)

2=

n2 + n

2.

2.2 Análise assintótica (“BigOh”) e complexidade polino-mial

Para quantificar a complexidade de um algoritmo, vamos usar a“ordem” de cres-cimento do tempo de processamento em função do tamanho da entrada.

Vamos assumir que todo algoritmo tem uma única entrada crítica cujo tamanhoéN (por exemplo, o comprimento do arranjo a ser ordenado).

A notação para indicar a “ordem” de um algoritmo é denominada“BigOh”.Temos:

• O(N): ordem linear;

• O(N2): ordem quadrática;

14

Page 16: PMR 2300 - Computação para Automação

• O(2N ): ordem exponencial;

• O(logN): ordem logarítmica.

A definição básica é a seguinte: O custoT (N) de um algoritmo com entradade tamanhoN éO({(N )) se existem constantesK > 1 eM tal que:

T (N) ≤ K · f(N), ∀N ≥M.

Ou seja, se uma algoritmo éO(f(N)), então há um pontoM a partir do qualo desempenho do algoritmo é limitado a um múltiplo def(N).

IMPORTANTE: SeT (N) éO(N), entãoT (N) éO(N2) e tambémO(Nα)para todoα ≥ 1. Usamossempreo menor valor possível para o expoenteα.

Algumas consequências da definição deO(f(N)) são:

• O(N3) +O(N2) = O(N3);

• O(N2) +N = O(N2);

• O(∑ki=1 aiN

i) = O(Nk).

O custo de um segmento de um programa que é executado uma únicavez éconstante e indicado porO(1).

As diversas ordens de algoritmos podem ser esquematizadas como segue:

2^NN^3 N^2

NlogN

NlogN

Custoem

de N

N

função

Figura 2.1: Desempenho de algoritmos

Algumas observações importantes:

1. Um algoritmoA1 pode ser mais rápido que outro algoritmoA2 para peque-nos valores deN , e no entanto ser pior para grandes valores deN . A análisepor notação “BigOh” se preocupa com o comportamento paragrandesvalo-res deN , e é por isso denominadaanálise assintótica.

2. Um algoritmo pode ter comportamentos diferentes para diferentes tipos deentradas; por exemplo, ordenação por inserção depende da entrada estar or-denada ou não. Em geral a complexidade é consideradano pior caso. Usa-remos sempre essa convenção neste curso.

15

Page 17: PMR 2300 - Computação para Automação

3. A análise assintótica ignora o comportamento paraN pequeno e ignora tam-bém custos de programação e manutenção do programa, mas esses fatorespodem ser importantes em um problema prático.

O custo de um algoritmo é sempre “dominado” pelas suas partescom maiorcusto. Em geral, as partes de um algoritmo (ou programa) que consomem maisrecursos são os laços, e é neles que a análise assintótica se concentra. Note que sedois ou mais laços se sucedem, aquele que tem maior custo “domina” os demais.

Exemplos:

f o r ( i n t i =0; i <n ; i ++)} / / Custo O(N ) .sum ++;

f o r ( i n t i =0; i <( n∗n ) ; i ++) / / Custo O(N ^ 2 ) .f o r ( i n t j = i ; j <n ; j ++)

sum ++;

A mensagem básica é:

Para encontrar a complexidade de um algoritmo, verifiquea complexidade das operações repetidas em laços.

Consideremos um exemplo, a procura da subsequência máxima (o problema éencontrar uma subsequência de um arranjo de inteiros, tal que a soma de elementosdessa subsequência seja máxima). Por exemplo:

−2, 11,−4, 13︸ ︷︷ ︸

subseq máx

,−5, 2,

Podemos codificar soluções cúbicas, quadráticas e linearespara esse problema.Considere uma solução cúbica:

/∗ ∗∗ Subsequenc ia maxima ( Cubica )∗ Fonte : Data S t r u c t u r e s and Problem∗ S o l v i n g us i ng Java , Weiss .∗ /

pub l i c c l a s s MaxSumTest {/ / s e q S t a r t , seqEnd : b e s t sequence .s t a t i c p r i va t e i n t s e q S t a r t = 0 ;s t a t i c p r i va t e i n t seqEnd = 0 ;

pub l i c s t a t i c i n t maxSubSum ( i n t a [ ] ) {i n t maxSum = 0 ;f o r ( i n t i = 0 ; i < a . l e n g t h ; i ++)

f o r ( i n t j = i ; j < a . l e n g t h ; j ++) {i n t th isSum = I n t e g e r .MIN_VALUE;

16

Page 18: PMR 2300 - Computação para Automação

f o r ( i n t k = i ; k <= j ; k++)th isSum += a [ k ] ;

i f ( th isSum > maxSum ) {maxSum = thisSum ;s e q S t a r t = i ;seqEnd = j ;

}}

re tu rn ( maxSum ) ;}

}

Essa solução tem custo:

O

N−1∑

i=0

N−1∑

j=i

j∑

k=i

1

= O

N−1∑

i=0

N−1∑

j=i

(j − i+ 1)

= O(

N−1∑

i=0

1

2(N − i)(N + i− 1) + i(i−N) + (N − i)

)

= O(N3)

Para fazer esse tipo de análise, é importante nos lembrarmosde algumas fór-mulas:

N∑

i=1

i =N(N + 1)

2;

N−1∑

i=0

i =N(N − 1)

2

N∑

i=1

i2 =N3

3+

N2

2+

N

6;

N−1∑

i=0

i2 =N3

3− N2

2+

N

6

N∑

i=1

i3 =N4

4+

N3

2+

N2

4;

N−1∑

i=0

i3 =N4

4− N3

2+

N2

4

Considere agora a solução quadrática (faça a análise e conclua que este algo-ritmo éO(N2)):

/∗ ∗∗ Subsequenc ia maxima ( Quadrat i ca )∗ Fonte : Data S t r u c t u r e s and Problem· ∗ S o l v i n g us i ng Java , Weiss .∗ /

pub l i c c l a s s MaxSumTest {/ / s e q S t a r t and seqEnd : b e s t sequence .s t a t i c p r i va t e i n t s e q S t a r t = 0 ;

17

Page 19: PMR 2300 - Computação para Automação

s t a t i c p r i va t e i n t seqEnd = 0 ;

pub l i c s t a t i c i n t maxSubSum2 ( i n t a [ ] ) {i n t maxSum = I n t e g e r .MIN_VALUE;f o r ( i n t i =0; i < a . l e n g t h ; i ++) {

i n t th isSum = 0 ;f o r ( i n t j = i ; j <a . l e n g t h ; j ++ ) {

th isSum += a [ j ] ;i f ( th isSum > maxSum) {

maxSum = thisSum ;s e q S t a r t = i ;seqEnd = j ;

}}

}re tu rn maxSum ;

}}

Na prática:

1. saiba avaliar a complexidade e identificar pontos críticos, principalmente fo-cando em laços;

2. concentre otimizações em pontos críticos, somente após se certificar que oalgoritmo funciona.

2.3 Complexidade logarítmica

Vimos até agora exemplos de complexidade polinomial, ou seja,O(Nα). Um tipoimportante de algoritmo é o que tem complexidade logarítmica, ou seja,O(logN).

IMPORTANTE: a base do logaritmo não importa, pois

O(logα N) = O(logβ N

logβ α

)

= O(logβ N).

Existem duas situações que levam à complexidade logarítmica:

• Considere que uma variávelx é inicializada com1 e depois é multiplicadapor 2 um certo númeroK de vezes. Qual é o númeroK∗ tal quex é maiorou igual aN?

Esse problema pode ser entendido como uma análise do seguinte laço:

i n t x =1;whi le ( x<N) {

. . .

18

Page 20: PMR 2300 - Computação para Automação

x=2∗x ;. . .

}

A questão é quantas iterações serão realizadas. Note que se ointerior do laçotem custo constanteO(1), então o custo total éO(K∗).

A solução é simples: queremos encontrarK tal que:

2K ≥ N ⇒ K ≥ log2 N,

e portantoK∗ = ⌈logN⌉ garante quex é maior ou igual aN .1

• Considere agora que uma variávelx é inicializada comN e depois é divididapor 2 um certo númeroK de vezes. Qual é o númeroK∗ tal quex é menorou igual a 1?

De novo podemos entender esse problema como o cálculo do número deiteraçoes de um laço:

i n t x=N;whi le ( x >1) {

. . .x=x / 2 ;. . .

}

A solução é dada por:

N

(1

2

)K

≤ 1⇒ N ≤ 2K ⇒ 2K ≥ N ⇒ K ≥ log2N.

De novo, temos queK∗ = ⌈logN⌉ é a solução.

Nessas duas situações a complexidade total éO (⌈logN⌉), supondo que ocusto de cada iteração é constante.

Note que⌈logN⌉ ≤ logN + 1 e portanto:

O (⌈logN⌉) = O (logN + 1) = O (logN) .

Nos dois casos, a complexidade é logarítmica.Um exemplo de algoritmo com complexidade logarítmica é o algoritmo de

busca binária, que vemos a seguir.

1A notação⌈α⌉ indica arredondamento para cima.

19

Page 21: PMR 2300 - Computação para Automação

2.4 Busca sequencial e busca binária

Considere um arranjo de tamanhoN e suponha que queremos encontrar o índicede um elementox. O algoritmo debusca sequencialsimplesmente varre o arranjodo início ao fim, até encontrar o elemento procurado:

i n t bus c a S e que n c i a l (i n t a [ ] , i n t x ) {f o r ( i n t i =0; i <a . l e n g t h ; i ++)

i f ( a [ i ]== x )re tu rn ( i ) ;

}

O custo desse algoritmo no pior caso éO(N). Em média, podemos imaginarquex está em qualquer posição com igual probabilidade, e temos umcusto médioproporcional aN2 , ainda de ordemO(N).

Suponha agora que o arranjo está ordenado. Nesse caso podemos dividir oproblema em dois a cada passo, verificando se o elemento está na metade superiorou inferior do arranjo em consideração. O algoritmo pode sercodificado comosegue (assumindo que o arranjo de entrada está ordenado de forma crescente):

i n t b u s c a B i n a r i a (i n t a [ ] , i n t x ) {i n t low =0;i n t high =a . l e ng t h−1;i n t mid ;whi le ( low <= high ) {

mid =( low + high ) / 2 ;i f ( a [ mid ] <x )

low=mid +1;e l s e {

i f ( a [ mid ] >x )h igh =mid−1;

e l s ere tu rn ( mid ) ;

}}re tu rn (−1); / / Nao encon t rou

}

Esse programa faz uma iteração que recebe um arranjo de tamanho N , de-pois N

2 , depoisN4 , e assim sucessivamente; no pior caso isso prossegue até queo

tamanho seja 1. Portanto o número de iterações éO (⌈logN⌉) e o custo total éO (logN), já que o custo de cada iteração é constante.

20

Page 22: PMR 2300 - Computação para Automação

2.5 Recursão

Um procedimento recursivo é um procedimento que chama a si mesmo durante aexecução. Recursão é uma técnica importante e poderosa; algoritmos recursivosdevem ter sua complexidade assintótica analisada com cuidado.

Considere como exemplo um programa que calcula fatorial:

long f a t o r i a l ( i n t x ) {i f ( x <=1)

re tu rn ( 1 ) ;e l s e

re tu rn ( x∗ f a t o r i a l ( x−1) ) ;}

O método funciona parax = 1; além disso, funciona parax ≥ 1 se funcionapara(x−1). Por indução finita, o método calcula os fatoriais corretamente. O casox = 1, em que ocorre a parada do algoritmo, é chamadocaso baseda recursão.

As várias chamadas da função podem ser indicadas naárvore de recursão:

fat. x↓

fat.(x-1)↓

fat.(x-2)↓...↓

fat. 2↓

fat. 1

Um outro exemplo de recursão é a seguinte implementação de busca binária:

i n t b u s c a B i n a r i a (i n t a [ ] , i n t x , i n t low , i n t high ) {i f ( low > high )

re tu rn (−1);i n t mid =( low+ high ) / 2 ;i f ( a [ mid ] <x )

re tu rn ( b u s c a B i n a r i a ( a , x , ( mid +1) , h igh ) ) ;e l s e

i f ( a [ mid ] >x )re tu rn ( b u s c a B i n a r i a ( a , x , low , ( mid−1 ) ) ) ;

e l s ere tu rn ( mid ) ;

}

21

Page 23: PMR 2300 - Computação para Automação

Um procedimento recursivo cria várias “cópias” de suas suasvariáveis locaisno Stack à medida que suas chamadas são feitas. Sempre é necessário avaliar acomplexidade de um procedimento recursivo com cuidado, pois um procedimentorecursivo pode “esconder” um laço bastante complexo.

Consideremos a função recursiva fatorial. Uma execução típica seria:

fatorial(3)→fatorial(2)→fatorial(1)

∣∣∣∣∣∣

12 2 2

3 3 3 3 3

∣∣∣∣∣∣

︸ ︷︷ ︸

Stack

O custo para uma chamadafatorial(N) éO(N). Uma solução iterativaequivalente seria:

long f a t o r i a l ( i n t N) {long f a t =1;f o r ( i n t i =2; i <=N; i ++)

f a t = f a t∗ i ;re tu rn ( f a t ) ;

}

Essa solução tem claramente custoO(N). Para ilustrar uma situação consi-deravelmente mais complexa, consideremos o algoritmo deordenação por união(mergesort).

Considere um arranjoa de tamanhoN . Para ordená-lo, divida o arranjo em2 partes, ordene cada uma e una as duas partes (com custoO(N)). O algoritmocompleto é o seguinte:

void m e r ge s o r t (i n t a [ ] ) {i n t temp [ ] =new i n t [ a . l e n g t h ] ;m e r ge s o r t ( a , temp , 0 , a . l e n g t h ) ;

}

void m e r ge s o r t (i n t a [ ] , i n t temp [ ] ,i n t l e f t , i n t r i g h t ) {

i f ( l e f t < r i g h t ) {i n t c e n t e r =( l e f t + r i g h t ) / 2 ;m e r ge s o r t ( a , temp , l e f t , c e n t e r ) ;m e r ge s o r t ( a , temp , ( c e n t e r +1) , r i g h t ) ;merge ( a , temp , l e f t ,

c e n t e r , ( c e n t e r +1) , r i g h t ) ;}

}

22

Page 24: PMR 2300 - Computação para Automação

void merge (i n t a [ ] , i n t temp [ ] ,i n t l e f t S t a r t , i n t l e f t E nd ,i n t r i g h t S t a r t , i n t r i gh t E nd ) {i n t s t a r t = l e f t S t a r t ;i n t aux= s t a r t ;whi le ( ( l e f t S t a r t <= l e f t E n d ) &&

( r i g h t S t a r t <= r i gh t E nd ) ) {i f ( a [ l e f t S t a r t ] < a [ r i g h t S t a r t ] )

temp [ aux ++]= a [ l e f t S t a r t ++ ] ;e l s e

temp [ aux ++]= a [ r i g h t S t a r t ++ ] ;}whi le ( l e f t S t a r t <= l e f t E n d )

temp [ aux ++]= a [ l e f S t a r t ++ ] ;whi le ( r i g h t S t a r t <= r i gh t E nd )

temp [ aux ++]= a [ r i g h t S t a r t ++ ] ;f o r ( i n t i = s t a r t ; i <= r i gh t E nd ; i ++)

a [ i ]= temp [ i ] ;}

Com um arranjo de tamanhoN , temos a seguinte árvore de recursão (estamosassumindo queN é uma potência de 2):

N

N/2 N/2

N/4 N/4 N/4 N/4

Custo O(N)

Custo O(N)

Custo O(N)

Figura 2.2: Árvore de recursão para ordenação por união.

O custo em cada nó,O(N), é o custo da combinação das soluções. SuponhaqueN seja uma potência de 2. Nesse caso teremoslog2 N níveis, cada um comcustoO(N). O custo total éO(N logN).

Uma maneira geral de calcular esse custo é considerar que o custo totalT (N)é regulado pela seguinte relação de recorrência:

T (N) = 2 · T(N

2

)

+ C ·N.

23

Page 25: PMR 2300 - Computação para Automação

Podemos escrever:

T

(N

2

)

= 2 · T(N

4

)

+ C ·(N

2

)

=⇒ T (N) = 2 ·(

2 · T(N

4

)

+ C ·(N

2

))

+ C ·N

= 4 · T(N

4

)

+ 2 · C ·N.

Seguindo esse raciocínio, chegamos a

T (N) = 2K · T(

N

2K

)

+K · C ·N

para uma recursão deK níveis. Sabemos que o número total de níveis élog2 N(paraN potência de 2),

T (N) = 2log2 N · T(

N

2log2 N

)

+ C ·N · log2N

= N · T(N

N

)

+ C ·N · logN

= C ′ ·N + C ·N · logN = O(N · logN),

pois temosT (1) = O(1) nesse algoritmo.Se a suposição queN é uma potência de 2 for removida, teremos um custo de

no máximoO(N) em cada nível, e um número máximo de (log2 N + 1) níveis.Nesse pior caso,

T (N) = 2log2 N+1 · T(

N

2log2 N

)

+ C ·N · log2N + 1

= 2 ·N · T (1) +C ·N · logN + C ·N= O(N logN),

se considerarmos queT (1) é uma constante (já que esse custo nunca é realmenteatingido, pois todas as recursões “param” quandoN = 1).

2.6 Divisão e conquista

Existem muitos problemas que podem ser resolvidos pelo método genérico de“divisão-e-conquista”, no qual o problema é dividido em partes que são resolvi-das independentemente e depois combinadas. Esquematicamente temos:

Qual é o custo desse esquema?Podemos em geral obter uma relação de recorrência:

T (N) = A · T(N

B

)

+ C · f(N),

24

Page 26: PMR 2300 - Computação para Automação

N

N/B

N/BN/B N/B

N/B

A sub−problemas

Figura 2.3: Árvore geral de recursão - “Divisão-e-conquista”

ondef(N) é o custo de combinar os subproblemas.Um resultado geral é o seguinte: A relaçãoT (N) = A · T

(NB

)+ O

(NL),

comT (1) = O(1), tem solução

T (N) =

O(N logB A

)seA > BL

O(NL logN

)seA = BL

O(NL)

seA < BL(2.1)

Considere um exemplo. Suponha que uma recursão resolve a cada nível 3subproblemas, cada um com metade do tamanho de chamada, e comcusto linearpara combinar subproblemas. Ou seja,A = 3, B = 2 eL = 1. ComoA > BL,sabemos que

T (N) = O(

N log2 3)

= O(N1.59).

Um cálculo mais detalhado pode ser feito como segue. SupondoqueN épotência de 2, temos no primeiro nível um custo≤ c · N ; no segundo nível umcusto≤ 3 · c · N2 ; no terceiro nível um custo≤ 32 · c · N

22.

N/2 N/2

N

N/2

Custo < cN

Custo < (3^2)cN/(2^2)

logN níveisCusto < 3cN/2

Figura 2.4: Custos da árvore de recursão em cada nível

Note que estamos substituindo a complexidadeO(N) por uma indicação ex-plícita c · N , para uma constantec > 0 e para umN maior que algumM . Issoé necessário, pois não podemos “ignorar” todas as constantes. Note também queO(N2

)= O

(N22

)= O(N), mas os resultados intermediáriosN

2 e N22

têm que sersomados sem modificação para o resultado final ser coerente. Com essas conside-

25

Page 27: PMR 2300 - Computação para Automação

rações, chegamos a

T (N) = (custo total das3log2 N folhas= 3log2 N ) +

(c ·N + 3 · c · N2

+ 32 · c · N22

+ · · · )

= N log2 3 + c ·Nk−1∑

i=0

(3

2

)i

,

ondek é o número de níveis da recursão, igual alog2 N . Ou seja:

⇒ T (N) = N log2 3 + c ·N ·log2 N−1∑

i=0

(3

2

)i

= N log2 3 + cN

(32

)log2 N − 132 − 1

= N log2 3 + (cN)

(

23log2 N

2log2 N− 2

)

= N log2 3 +cN2

NN log2 3 − 2cN

= N log2 3 + 2cN log2 3 − 2cN

= O(

N log2 3)

,

onde usamosk∑

i=0,a>0,a6=1

ai =ak+1 − 1

a− 1.

Essa solução assume queN é potência de 2; se isso não ocorre, o número deníveis é menor que (log2 N + 1) e a complexidade ainda éO

(N log2 3

).

Podemos resumir o procedimento usado nesse exemplo como:

1. dado um programa recursivo, determine a relação de recorrência que rege oprograma;

2. substitua os custos assintóticos em notaçãoO(.) por funções;

3. obtenha expressões paraT (N), resolvendo somatórios ou produtórios.

Retornemos então ao resultado geral, dado pela Expressão (2.1):

T (N) = A · T(N

B

)

+O(NL)=

O(N logB A

)seA > BL,

O(NL logN

)seA = BL,

O(NL)

seA < BL.

Temos:

T (N) = O(NL)+A · O

(NL

BL

)

+A2 · O(NL

B2L

)

+ · · ·

26

Page 28: PMR 2300 - Computação para Automação

Portanto:

T (N) = (custo total das folhas= AlogB N ) + cNL +AcNL

BL+A2c

NL

B2L+ · · ·

= cNLk−1∑

i=0

(A

BL

)i

+N logB A

ondek = logB N é o número de níveis de recursão. Temos então:

SeA

BL< 1⇒ T (N) = cNL 1

1−(

ABL

) = O(NL)

SeA

BL= 1 ⇒ T (N) = cNL

logB N∑

i=0

1 = O(NL logB N

)

SeA

BL> 1 ⇒ T (N) = cNL

(ABL

)logB N − 1(

ABL

)− 1

= cNL ·(

1(

ABL

)− 1

)

· AlogB N

BL logBN− cNL

(ABL

)− 1

= c

(

1(

ABL

)− 1

)

NLN logB A

NL− cNL

(ABL

)− 1

= c

(

1(

ABL

)− 1

)

N logB A − cNL

(ABL

)− 1

= O(

N logB A)

,

dado queN logBA > NL, pois A

BL > 1.

2.7 Alguns exemplos adicionais

2.7.1 Inversão de matrizes

O algoritmo de Strassen para inversão de matrizesN×N divide o número de linhaspela metade, mas realiza sete chamadas recursivas por vez, com custoO(N2) decombinação; portanto o custo de inversão de uma matriz éO(N log2 7).

2.7.2 Quicksort

O algoritmo mais usado para ordenação é o quicksort, que tem pior casoO(N2) ecaso médioO(N logN), além de não exigir armazenamento adicional. Na práticao quicksort é muito rápido para arranjos não ordenados.

Uma implementação em Java é:

27

Page 29: PMR 2300 - Computação para Automação

void q u i c k s o r t (i n t s [ ] , i n t a , i n t b ) {i f ( a>=b ) re tu rn ;i n t p=s [ b ] ; / / p i v o ti n t l =a ;i n t r =b−1;whi le ( l <= r ) {

whi le ( ( l <= r )&&( s [ l ]<=p ) ) l ++;whi le ( ( l <= r )&&( s [ l ]>=p ) ) r −−;i f ( l < r ) {

i n t temp=s [ l ] ;s [ l ]= s [ r ] ;s [ r ]= temp ;

}}s [ b ]= s [ l ] ;s [ l ]= p ;q u i c k s o r t ( s , a , ( l−1) ) ;q u i c k s o r t ( s , ( l +1) , b ) ;

}

2.7.3 Criptografia

Considere que codificamos uma mensagem como um número primop. Podemostransmitir um númeror = p · q, em quep é a mensagem eq é um número primomaior quep, conhecido como a “chave”. Se temosr e q, podemos obterp facil-mente. Porém se temosr mas não temosq, temos que fatorarr para obterp.

O problema é que fatorar um número inteiro grande é muito difícil. Existemapenas algoritmos com custo assintótico exponencial para fatorar inteiros ( uminteiro deN bits toma um esforço deO

(2N)

para fatoração).O problema de fatoração de inteiros está na base de muitos métodos de crip-

tografia atuais. Se um algoritmo polinomial para fatoração for descoberto, muitossistemas de segurança atuais poderão ser violados.

2.8 Formulário

• blogc a = alogc b;

• logb a = logc alogc b

;

• ∑ni=1 f(i)− f(i− 1) = f(n)− f(0);

• ∑Ni=1 i =

N(N+1)2 ;

• ∑N−1i=0 i = N(N−1)

2 ;

28

Page 30: PMR 2300 - Computação para Automação

• ∑Ni=1 i

2 = N3

3 + N2

2 + N6 ;

• ∑N−1i=0 i2 = N3

3 − N2

2 + N6 ;

• ∑Ni=1 i

3 = N4

4 + N3

2 + N2

4 ;

• ∑N−1i=0 i3 = N4

4 − N3

2 + N2

4 ;

• ∑ki=0,a>0,a6=1 a

i = ak+1−1a−1

• ∑∞i=0,a∈[0,1] a

i = 11−a

• ∑ni=0,a>0,a6=1 i · ai =

a−(n+1)an+1+nan+2

(1−a)2

2.9 Exercícios

1. Qual String é impressa pelo programa:

pub l i c c l a s s What {pub l i c s t a t i c void f ( i n t x ) {

x = 2 ;}pub l i c s t a t i c void main ( S t r i n g a r gs [ ] ) {

i n t x = 0 ;f ( x ) ;System . ou t . p r i n t l n ( "Hey : " + x ) ;

}}

2. Considere o seguinte exemplo de alteração de um arranjo passado por refe-rência para um método chamadodoIt:

pub l i c s t a t i c void d o I t ( i n t h [ ] ) {i n t k [ ] = new i n t [2 ∗ h . l e n g t h ] ;f o r ( i n t i =0; i <h . l e n g t h ; i ++) {

k [ i ] = h [ i ] ;k [ i +h . l e n g t h ] = h [ i ] ;

}h = k ;k [ 0 ] = 2 ;

}

Esse código contém um erro. Reescreva-o de forma a garantir que o arranjohna chamada da função é modificado (seu tamanho e conteúdo são duplicados,e seu elemento 0 recebe o valor 2).

29

Page 31: PMR 2300 - Computação para Automação

3. Escreva um pequeno método em Java que receba dois arranjosa e b de ta-manho igual, contendo valores do tipo double, e retorne o produto escalar dea e b.

4. Elabore um programa recursivo que calcule o Mínimo Divisor Comum dedois inteiros usando o seguinte algoritmo, conhecido como algoritmo de Eu-clides: Divida o número maior pelo menor e pegue o resto; então dividao divisor pelo resto e assim sucessivamente até que o resto seja zero — oquociente da última divisão é o divisor comum. Por exemplo, tome 928 e100: dividimos 928 por 100, obtemos resto 28; dividimos 100 por 28, obte-mos resto 16; dividimos 28 por 16, obtemos resto 12; dividimos 16 por 12,obtemos resto 4; dividimos 12 por 4 e obtemos resto zero — o resultado é 4.

5. Escreva um algoritmo recursivo que transforme um número inteiro decimalem um número binário.

6. Considere a funçãof(n) definida recursivamente como segue:f(0) = 0;f(n) = f(n/2) sen é par;f(n) = 1 + f(n − 1) sen é ímpar. Codifiqueessa função em Java e obtenha o valor def(100).

7. Considere o seguinte algoritmo:

i n t e x e r c i c i o 1 (i n t x ) {i f ( x < 5)

re tu rn (3∗ x ) ;e l s e

re tu rn (2 ∗ e x e r c i c i o 1 ( x−5) + 7 ) ;}

Qual é o resultado deexercicio1(4) eexercicio1(20)? Desenhea árvore de chamadas recursivas para cada caso.

8. Considere o seguinte algoritmo:

i n t e x e r c i c i o 2 (i n t x , i n t y ) {i f ( x > y )

re tu rn (−1);e l s e {

i f ( x == y )re tu rn ( 1 ) ;

e l s ere tu rn ( x ∗ e x e r c i c i o 2 ( x +1 , y )

+ e x e r c i c i o 2 (2∗x , y ) )}

}

30

Page 32: PMR 2300 - Computação para Automação

Qual é o resultado de chamadasexercicio2(10,4),exercicio2(4,3),exercicio2(4,7)? Desenhe a árvore de chamadas recursivas para cadacaso.

9. Dado o fragmento de código abaixo, desenhe a árvore de recursão paraf(1, 10) e obtenha o valor de retorno.

double f ( double x , double y ) {i f ( x >= y )

re tu rn ( ( x+y ) / 2 ) ;e l s e

re tu rn ( f ( f ( x +2 ,y−1) , f ( x +1 ,y−2 ) ) ) ;}

10. Coloque em ordem crescente de complexidade:O (2n), O (n!), O(n5),

O (n log n). Qual é a complexidade em notação BigOh de um programaque utiliza3n4 + n log n operações?

11. Considere um polinômiop(x) =∑N

i=0 aixi, e suponha que o valor desse

polinômio para um particular valorx é calculado usando o método de Hor-ner:

p(x) = a0 + x(a1 + x(a2 + x(a3 + · · ·+ x(an−1 + xan) . . . ).

Caracterize em notação BigOh o número de operações aritméticas (adiçõese multiplicações) executadas nesse método.

12. Escreva uma rotina recursiva que resolve com custoO(2N)

o seguinte pro-blema: Dado um conjunto deN inteirosA1 aAN , e um inteiroK maior quetodos osAi, descubra se existe um subconjunto dos inteirosA1 aAN cujasoma é exatamenteK. (Nota: Esse problema é chamado Problema da Somade Subconjuntos; não existe nenhuma solução conhecida paraesse problemaque seja polinomial emN . A descoberta de uma solução polinomial paraesse problema é um dos problemas abertos mais importantes emmatemá-tica, e o problema mais importante em computação teórica.)

13. Considere a sequência: [26,34,9,0,4,89,6,15,27,44].Desenhe esquematica-mente os passos realizados por ordenação por inserção e por união (merge-sort) para ordenar essa sequência de forma crescente.

14. Qual é a ordem de complexidade em notação BigOh para ordenamento porinserção, seleção, união (mergesort) nos seguintes casos:

• O arranjo a ser ordenado está ordenado em ordem crescente.

• O arranjo a ser ordenado está ordenado em ordem decrescente.

Considere que o resultado final deve ser o arranjo ordenado emordem cres-cente.

31

Page 33: PMR 2300 - Computação para Automação

15. Escreva uma função que faça ordenamento de quatro inteiros distintos comno máximo cinco comparações.

16. Prove que o seguinte algoritmo ordena corretamente um arranjoa entre ín-dicesi ej (inclusive), e obtenha a complexidade do algoritmo em notaçãoBigOh.

void ordena (i n t a [ ] , i n t i , i n t j ) {i f ( a [ i ] > a [ j ] )

t r o q u e a [ i ] e a [ j ]i f ( ( i +1) >= j )

re tu rn ;i n t k = ( i− j + 1 ) / 3 ;ordena ( a , i , j−k ) ;ordena ( a , i +k , j ) ;o rdena ( a , i , j−k ) ;

}

17. Considere o método:

1 void prova ( i n t a [ ] , i n t b [ ] , i n t c ) {2 B ina rySearch s =new B inarySearch ( a ) ;3 i n t i = s . s e a r c h ( c ) ;4 f o r ( i n t j = 0 ; j <a . l e n g t h ; j ++)5 f o r ( i n t k =0; k<b . l e n g t h ; k++)6 System . ou t . p r i n t l n ( j + s . s e a r c h ( b [ k ] ) ) ;7 }

onde BinarySearch é uma classe pública que executa busca binária em ar-ranjos; o construtor deBinarySearch recebe um arranjo de inteiros eo método públicosearch(int c) procura o inteiroc no arranjo, retor-nando o índice dec no arranjo. Suponha quec e que todos os elementos deb sempre estão ema. Considere quea eb podem ter tamanhoN e no piorcaso os dois tem tamanhoN.

(a) Qual a complexidade do programa em notação BigOh no pior caso?Justifique.

(b) Suponha que a terceira linha seja removida; qual a complexidade doprograma resultante em notação BigOh, no pior caso? Justifique.

(c) Suponha que a sexta linha seja substituída porSystem.out.println( j + k ). Qual a complexidade do pro-grama resultante em notação BigOh no pior caso? Justifique.

(d) Suponha que a quarta e quinta linhas sejam substituídas por

f o r ( j = i ; j <a . l e n g t h ; j ++)f o r ( k = j ; k<b . l e n g t h ; k++)

32

Page 34: PMR 2300 - Computação para Automação

Qual a complexidade do programa resultante em notação BigOhnopior caso? Justifique.

18. Considere o código abaixo, assumindo quen é maior que zero:

1 i n t e x e r c i c i o 1 (i n t n , i n t x ) {2 i n t sum = 0 ;3 i f ( x < 0) re tu rn (−1);4 i f ( x >= n ) x = n ;5 f o r ( i n t i = 0 ; i < n ; i ++) {6 sum ++;7 f o r ( i n t j = 0 ; j < n ; j ++) {8 a u x i l i a r ( sum , n ) ;9 f o r ( i n t k = j ; k < n ∗ x ; k++)10 sum = sum + 2 ;11 }12 }13 re tu rn ( sum ) ;14 }15 void a u x i l i a r ( i n t sum , i n t n ) {16 sum = n ∗ sum ;17 }

(a) Obtenha o valor de retorno da funçãoexercicio1 em termos den ex. Justifique. [1.0]

(b) Obtenha a complexidade em notação BigOh em funçãoapenasden nopior caso. Justifique. [1.0]

(c) Apresente esquematicamente (através de um desenho) o conteúdo doStack e do Heap do programa ao fim da primeira execução da linha6,assumindo que tanto Stack quanto Heap estão vazios na chamada deexercicio1(10,1). [0.5]

(d) Suponha que a linha 5 seja substituída pela linha

5 f o r ( i n t i = x ; i < n ; i ++) {

Obtenha o valor de retorno em função den ex; assumindo quen é par,obtenha a complexidade em notação BigOh em função apenas den nopior caso. Justifique. [1.5]

19. Considere o código abaixo:

1 i n t e x e r c i c i o 2 (i n t a ) {2 re tu rn ( e x e r c i c i o 2 ( a , 0 , a . l e n g t h ) ) ;3 }4 i n t e x e r c i c i o 2 (i n t a , i n t x , i n t y ) {

33

Page 35: PMR 2300 - Computação para Automação

5 i n t n = y−x ;6 i f ( n < 2) re tu rn ( 0 ) ;7 i n t z = 0 ;8 f o r ( i n t i =0; i <7; i ++) {9 Ordena . o r d e n a I n s e r c a o ( a , i∗ n / 7 ,10 ( i +1) ∗ ( n / 7 ) − 1 ) ;11 z = z + e x e r c i c i o 2 ( a , i∗ n / 7 ,12 ( i +1) ∗ ( n / 7 ) − 1 ) ;13 }14 re tu rn ( z ) ;15 }

A funçãoOrdena.ordenaInsercao(a, x, y) ordena o sub-arranjode a entre indicesx e y (inclusive) por inserção. Para simplificar, assumaquen é uma potência de um número que for apropriado.

(a) Apresente uma relação de recorrência que rege o custoT (n) desta fun-ção em termos do comprimenton do arranjo de entrada. Justifique.[1.0]

(b) Resolva a relação de recorrência obtida no item anterior, justificandocada passo. [1.5]

(c) Suponha que a linha 9 seja substuída por ordenação por união. Qual éa relação de recorrência resultante? Justifique. [0.5]

20. Considere uma busca sequencial de um elementoX em um arranjo deN ele-mentos. Normalmente assumimos que cada comparação utilizada na buscatem um custo fixo. Suponha porém que cada comparação exija umabuscabinária no arranjo deN elementos. Qual é a complexidade da busca deX emnotação BigOh no pior caso?

21. Para o código a seguir, indique o trecho crítico do programa (isto é, as linhasque se repetem mais vezes). Determine o valor da variávelsum ao final.Indique a complexidade no pior caso em notação BigOh. Justifique.

i n t sum = 0 ;f o r ( i n t i =0; i <n ; i ++)

f o r ( i n t j = 0 ; j <( n∗ i ) ; j ++)f o r ( i n t k =0; k< j ; k++)

sum++;

DICA: O resultado éO(N5), pois o valor desum atingeN5/6 −N4/4 −

N3/6 +N2/4.

22. Para o código a seguir, indique o trecho crítico do programa. Determine ovalor da variávelsum ao final. Indique a complexidade no pior caso emnotação BigOh. Justifique.

34

Page 36: PMR 2300 - Computação para Automação

i n t sum = 0 ;f o r ( i n t i =0; i <n ; i ++)

sum ++;f o r ( i n t i =0; i <n ; i ++)

f o r ( i n t j =0; j <( i ∗ i ) ; j ++)i f ( ( j%i ) == 0)

f o r ( i n t k =0; k< j ; k++)sum ++;

DICA: O resultado éO(N4), pois o valor desum atingeN4/8−5N3/12+

3N2/8− 11N/12. Este valor é obtido pela expressão

N−1∑

i=0

1 +

N−1∑

i=1

i−1∑

j=0

ij−1∑

k=0

1.

Note o efeito da operação % na complexidade do programa.

23. Demonstre que o seguinte programa leva a um loop infinito paran maior que2.

pub l i c boolean v e r i f y ( i n t x , i n t y , i n t z , i n t n ) {boolean f l a g = f a l s e ;i n t auxX , auxY , auxZ ;whi le ( f l a g == f a l s e ) {

auxX = 1 ; auxY = 1 ; auxZ = 1 ;f o r ( i n t i =0; i <n ; i ++) {

auxX ∗= x ;auxY ∗= y ;auxZ ∗= z ;

}i f ( auxX + auxY == auxZ )

f l a g = t rue ;n ++;

}}

DICA: Esse problema é extremamente simples! Verifique a expressão mate-mática produzida para cada valor den, e argumente que a expressão não temsolução usando um resultado conhecido em matemática.

24. Considere os seguintes métodos:

pub l i c cube (i n t n ) {aux = 0 ;f o r ( i n t i =1; i <=n ; i ++)

aux += i∗ i ∗ i ;

35

Page 37: PMR 2300 - Computação para Automação

re tu rn ( aux ) ;}pub l i c s qua r e (i n t n ) {

aux =0;f o r ( i n t i =1; i <=n ; i ++)

aux += i ;re tu rn ( aux ∗ aux ) ;

}

(a) Indique a complexidade dos dois métodos em notação BigOh.

(b) Demonstre que os dois métodos retornam o mesmo valor.

(c) Escreva um método que retorna o mesmo valor em tempoO (1).

25. Considere o seguinte teorema (conhecido como Teorema doLimite Supe-rior): um politopo comN vértices emD dimensões temKND/2 faces parauma constanteK > 0 e para qualquerN maior que um certoM . A partirdesse teorema, prove que a ordenação e impressão das faces deum politopocomN vértices em 4 dimensões pode ser feita emO

(N2 logN

). Justifique

a partir da definição da notação BigOh.

DICA: Lembre-se que um politopo é um objeto geométrico definido porhiperplanos em um espaço comD dimensões (paraD = 2, temos poliedros).

26. Considere um programa com dois métodos. O primeiro método recebe umnúmeroN e produz um arranjoa de tamanhoN !, onde cada elemento doarranjo é uma permutação do arranjob igual a[1, 2, ..., N ] (existemN ! per-mutações de uma lista comN elementos). Suponha quea seja ordenado dealguma forma, e o segundo método realiza uma busca binária ema. Proveque a complexidade do segundo método éO (N logN), usando a aproxima-ção de Stirling:

N ! =√2Nπ(N/e)N (1 +O (1/N)).

27. Considere os dois programas abaixo:

i n t do I t 1 ( i n t a [ ] ) {i n t n = a . l e n g t h ;i n t sum = 0 ;f o r ( i n t i =0; i <=n ; i ++)

f o r ( i n t j =0; j <= i ; j ++)sum += a [ i ] ∗ a [ j ] ;

re tu rn ( sum ) ;}i n t do I t 2 ( i n t a [ ] ) {

i n t n = a . l e n g t h ;

36

Page 38: PMR 2300 - Computação para Automação

i n t sum = 0 ;i n t sum2 = 0 ;f o r ( i n t i =0; i <=n ; i ++) {

sum += a [ i ] ;sum2 += a [ i ] ∗ a [ i ] ;

}re tu rn ( ( sum ∗ sum + sum2 ) / 2 ) ;

}

(a) Determine a complexidade de cada método no pior caso em notaçãoBigOh.

(b) Prove que os dois métodos retornam o mesmo resultado. (Dica: Useindução finita emn, o tamanho do vetora. Note que os dois métodosretornam o mesmo resultado paran = 1, assuma que os resultados sãoiguais paran genérico e prove que são iguais para(n+ 1).)

28. Considere o seguinte método:

pub l i c void d o I t ( i n t a [ ] , i n t b [ ] ) {Ordena . ordena ( a ) ;f o r ( i n t i =0; i <b . l e n g t h ; i ++) {

i n t aux = B inarySearch . s e a r c h ( a , b [ i ] ) ;f o r ( i n t j =aux ; j <a . l e n g t h ; j ++)

System . ou t . p r i n t l n ( a [ j ] ) ;}

}

onde:

• void ordena(int a[]) é um método de classe (da classeOrdena)que faz o ordenamento do arranjoa).

• int search(int a[], int x) é um método de classe (da classeBinarySearch) que faz busca binária do elementox no arranjoa eretorna o índice dex ema.

• a eb são arranjos de tamanho máximoN .

• todos os elementos deb estão ema (os elementos deb podem serrepetidos).

Qual a complexidade em notação BigOh no pior caso em função deN para(justifique!):

(a) métodoordena implementado com ordenação por inserção.

(b) métodoordena implementado com mergesort.

37

Page 39: PMR 2300 - Computação para Automação

29. Você foi chamado por uma empresa para analisar um bloco fundamental deprogramas de controle de fluxo de caixa. Você identificou que oseguintemétodo é chamado muito frequentemente:

pub l i c i n t d o I t ( i n t a [ ] ) {i n t i , j , k ;i n t sum = 0 ;i n t aux = 1 ;f o r ( i =0; i <a . l e n g t h ; i ++) {

sum++;aux ∗= a [ i ] ;

}f o r ( i =0; i <a . l e n g t h ; i ++) {

f o r ( j =0; j <a . l e n g t h ; j ++) {sum++;aux = aux + ( a [ i ] − a [ j ] ) ;

}}f o r ( i =0; i <a . l e n g t h ; i ++)

f o r ( j = i ; j <(2 ∗ i ) ; j ++)f o r ( k= j ; k <( j + 5 ) ; k++)

sum ++;re tu rn ( sum+aux ) ;

}

(a) Determine a complexidade do programa em função deN , o tamanhodo vetor de entradaa, em notação BigOh. Justifique.

(b) Codifique o programa de forma que o resultado seja o mesmo mas acomplexidade sejaO (N). Justifique.

30. Considere o seguinte fragmento de código. A funçãoproximoArranjo(M)retorna um arranjo de comprimentoM preenchido com inteiros lidos a partirde um arquivo pré-especificado (essa operação tem custoO(M)), e a fun-çãoordenaUniao(a) ordena o arranjoa usando ordenação por união. Afunçãoauxiliar(a,x) é recursiva: cada chamada onde o arranjoa temcomprimentoQ realiza operações de custoO(Q) seguidas de 3 chamadasrecursivas à mesma funçãoauxiliar, cada uma delas usando metade doarranjoa.

1 pub l i c s t a t i c REC1( i n t N, i n t M) {2 i n t i , j , a [ ] , sum = 0 ;34 f o r ( i =0; i <N; i ++) {5 a = prox imoAr ran jo (M) ;6 ordenaUniao ( a ) ;

38

Page 40: PMR 2300 - Computação para Automação

7 f o r ( j =0; j <M; j ++)8 i f ( a [ j ] == 0)9 sum = sum + 1 ;10 e l s e11 sum = a u x i l i a r ( a , a [ j ] ) ;12 }13 re tu rn ( sum ) ;14 }

Qual o custo deREC1 em função deN e M , em notação BigOh no piorcaso? Justifique cada passo do seu argumento.

31. Considere o seguinte fragmento de código:

1 pub l i c s t a t i c SUB1( Ob jec t a [ ] , i n t b [ ] [ ] ,2 boolean saveMemory ) {3 i n t i , j , k , sum = 0 ;45 f o r ( k =0; k<b . l e n g t h ; k++) {6 i f ( saveMemory == t rue ) o r de na S e l e c a o ( b [ k ] ) ;7 e l s e ordenaUniao ( b [ k ] ) ;8 }9 boolean f l a g = f a l s e ;10 f o r ( k =0; k<b . l e n g t h ; k++) {11 i f ( b [ k ] [ 0 ] == 0) f l a g = t rue ;12 }13 i f ( f l a g == t rue ) {14 f o r ( i =0; i <a . l e n g t h ; i ++) {15 f o r ( j = i +1; j <a . l e n g t h ; j ++) {16 i f ( a [ i ]== a [ j ] ) sum = sum +1;17 }18 }19 }20 re tu rn ( sum ) ;21 }

O arranjoa temN linhas eN colunas, e o arranjob temN elementos. AfunçãoordenaSelecao(c) ordena o arranjoc por seleção e a funçãoordenaUniao(c) ordena o arranjoc por união. AssumaN > 1.

(a) Qual o custo deSUB1 em função deN , em notação BigOh no piorcaso? Justifique.

(b) Recodifique a função de forma que o seu retorno seja igual,mas as fun-çõesordenaSelecao(c)eordenaUniao(c)nãosejam usadas,e o custo sejaO(N2) em notação BigOh no pior caso. Justifique.

39

Page 41: PMR 2300 - Computação para Automação

32. Uma função recursivaSUB2(a,k) recebe como entrada um arranjoa detamanhoN e um inteirok que indica o nível da recursão. A função é semprechamada comoSUB2(a,0). Uma análise da função indicou que seu custoT (N) éO(1) paraN = 1 e (α > 0 é uma constante)

T (N, k) =

{2T (N/2, k + 1) + αN, parak par,4T (N/2, k + 1) + αN, parak ímpar.

Obtenha o custo da chamadaSUB2(a,0) assumindo queN é uma potênciade2.

33. Considere uma recursão em que cada problema de tamanhoN é divididorecursivamente em 4 sub-problemas. Cada um desses sub-problemas temtamanhoN/2. Assuma queN é um número cujo logaritmo em uma baseconveniente é um número inteiro. Qual é a complexidade dessarecursãopara um problema de tamanhoN , se o “custo” de unir as soluções dos quatrosub-problemas de um único problema de tamanhoN é exatamenteN2, e o“custo” de resolver um problema comN = 1 é exatamente 1.

DICA: Considere o primeiro caso. A recursão leva à seguinte expressão:

T (N) = 4T (N/2) +N2.

Podemos escrever

T (N/2) = 4T (N/4) +N2/4

e portanto:T (N) = 16T (N/4) +N2 +N2.

Da mesma forma:

T (N/4) = 4T (N/8) +N2/16⇒ T (N) = 64T (N/8) +N2 +N2 +N2.

Seguindo nesse raciocínio, atingimos:

T (N) = 4kT (N/2k) + kN2.

Parak = log2N (pois a árvore de recursão terá tamanholog2 N ):

T (N) = N2T (1) +N2 log2N.

Portanto a complexidade éO(N2 logN

).

Tente resolver para o caso em que o “custo” de unir soluções éN3; a soluçãoéO

(N3). Lembre-se da expressão:

n∑

k=0

ak = (a(n+1) − 1)/(a − 1).

40

Page 42: PMR 2300 - Computação para Automação

34. Resolva a seguinte equação, resultado da análise de um algoritmo recursivo:

T (N) = aT (N/b) +N logN,

para:

(a) a igual a 3 eb igual a 2.

(b) a igual a 2 eb igual a 2.

(c) a igual a 2 eb igual a 3.

Assuma queN é uma potência na base mais conveniente e queT (1) = 1.

35. Considere o seguinte programa recursivo:

pub l i c i n t d o I t ( i n t a [ ] , i n t i , i n t j ) {i n t n = j − i − 1 ;i f ( n <= 1)

re tu rn ( 1 ) ;e l s ere tu rn ( d o I t ( a , i , i +n /2−1) +

d o I t ( a , i +n / 4 , i +3∗n /4−1) +d o I t ( a , i +n / 2 , j ) ) ;

}

Considere agora o seguinte método:

pub l i c i n t do ( i n t a [ ] ) {re tu rn ( d o I t ( a , 0 , a . l e n g t h− 1) ) ;

}

Qual é a ordem de complexidade da chamadado(a) para um vetora detamanhoN , em notação BigOh? Assuma queN é uma potência de 2.

36. Considere o seguinte fragmento de código, ondea eb são arranjos de mesmotamanhoN (ondeN > 2) e a funçãoSort.insertionsort(int a[], int o, int f)ordena o arranjoa entreo ef, usando ordenação por inserção.

pub l i c void d o I t ( i n t a [ ] , i n t b [ ] , i n t o , i n t f ) {i f ( ( f−o ) < 2 )

re tu rn ( a [ f ] ) ;e l s e

S or t . i n s e r t i o n s o r t ( a , o , f ) ;i f ( a [ 0 ] < b [ 0 ] )

d o I t ( a , b , o , ( f +o ) / 2 ) ;e l s e

d o I t ( a , b , ( f +o ) / 2 , f ) ;

41

Page 43: PMR 2300 - Computação para Automação

i f ( a [ 1 ] < b [ 1 ] )d o I t ( a , b , o + ( f−o ) / 4 , o + 3∗ ( f−o ) / 4 ) ;

d o I t ( a , b , o , o + ( f−o ) / 3 ) ;}

Escreva a equação recursiva que deve ser resolvida para obter a comple-xidade deste fragmento de código em notação BigOh, considerando o piorcaso. Indique também as condições de contorno que devem ser atendidaspela solução (isto é, qual a complexidade da parada da recursão). Justifiquea resposta. [Note: não há necessidade de resolver a equação!]

37. Resolva as seguintes equações recursivas, expressandoo resultado em nota-ção BigOh e assumindo queN é uma potência na base mais conveniente:

• T (1) = 1, T (N) = 3T (N/2) +N .

• T (1) = 1, T (N) = 7T (N/3) +N2.

• T (1) = 1, T (N) = 2T (N − 1) +N .

42

Page 44: PMR 2300 - Computação para Automação

Capítulo 3

Orientação a Objetos eEstruturas de Dados

Conceber um programa complexo requer considerável organização. A programa-ção orientada a objetos procura facilitar a organização de programas, promovendoa modularidade do código e o isolamento entre partes distintas de um programa,facilitando assim a reutilização dessas partes. Linguagens orientadas a objeto ga-nharam muita ênfase na década de 90; várias outras ferramentas e metodologiasde programação têm aparecido desde então mas as linguagens orientadas a objetocontinuam tendo lugar de destaque na prática de programação.

Considere um exemplo. Suponha que você precisa fazer um programa paracontrolar uma empresa aérea. Quais são as entidades de interesse (ou seja, os“objetos”)? Podemos considerar os seguintes objetos: aeroportos, vôos, reservas,passageiros. Podemos também imaginar que todo passageiro seja uma pessoa,portanto objetos que representam passageiros também representam pessoas. Final-mente podemos discutir como os diversos objetos interagem,talvez requisitandooperações de outros objetos (por exemplo, uma reserva pode “fornecer” o nomedo passageiro envolvido). Programação orientada a objetosvisa dar ferramentasao programador para representar esses objetos de forma simples e concisa. Paratanto, o programador pode agrupar conjuntos de variáveis emobjetos computaci-onais que representam objetos (concretos ou abstratos) do mundo real. Assim, opropósito maior de programação orientada a objetos é:

• reutilizar código, quando possível;

• encapsular dados;

• organizar identificadores;

• abstrair e isolar estruturas;

Programação orientada a objetos é muito útil quando temos que codificar es-truturas de dados.

43

Page 45: PMR 2300 - Computação para Automação

Estruturas de dados são objetos que armazenam dados de formaeficiente, ofe-recendo certos “serviços” para o usuário (ordenação eficiente dos dados, busca pormeio de palavras chave, etc). Uma estrutura de dados abstraias características prin-cipais de uma atividade que envolve armazenamento de informações; por exemplo,a estrutura defila armazena dados de forma que o dado há mais tempo na estruturaé o primeiro a ser retirado.

As estruturas básicas abordadas nessa apostila são:

• Pilhas, filas, listas ligadas.

• Árvores e árvores de busca.

• Hashtables (tabelas de dispersão).

3.1 Pilhas (Stacks)

Umapilha é uma estrutura de dados em que o acesso é restrito ao elementomaisrecente na pilha. As operações básicas realizadas com uma pilha são:

• push: inserir no topo;

• pop: retirar do topo;

• top: observar o topo.

Em uma pilha “tradicional”, essas operações devem ocorrer emO(1), independen-temente do tamanhoN da pilha (ou seja, em tempo constante).

push(a) a push(b)

b

a pop() a a

a

top()

Figura 3.1: Operações em uma pilha.

3.1.1 Verificação de Consistência de Parênteses

Considere o problema de verificar se existe um fechamento de parênteses para cadaabertura em uma expressão algébrica com letras e símbolos+,−, ∗, /.

Pode-se utilizar uma pilha como no exemplo a seguir:

44

Page 46: PMR 2300 - Computação para Automação

( ()

"fecha""abre"

A+B*(C/D+E)

Figura 3.2: Verificação de fechamento de parênteses

/∗ V e r i f i c a ç ã o de p a r e n t ê s e s∗ /pub l i c c l a s s V e r i f i c a {

s t a t i c pub l i c void main ( S t r i n g a r gs [ ] ) {i f ( a r gs . l e n g t h < 1) {

System . ou t . p r i n t l n ( " I n s i r a e n t r a d a ! " ) ;System . e x i t (−1);

}S t r i n g e n t r a d a = a r gs [ 0 ] ;P i l haAr p i l h a = new P i lhaAr ( ) ;f o r ( i n t i =0; i < e n t r a d a . l e n g t h ( ) ; i ++) {

char c = e n t r a d a . charA t ( i ) ;i f ( c== ’ ( ’ )

p i l h a . push ( c ) ;i f ( c== ’ ) ’ ) {

char o = p i l h a . pop ( ) ;i f ( o== ’ 0 ’ ) {

System . ou t . p r i n t l n ( " F a l t a a b e r t u r a ! " ) ;System . e x i t (−2);

}}

}i f ( p i l h a . tamanho ( ) >0) {

System . ou t . p r i n t l n ( " F a l t afechamento ! " ) ;System . e x i t (−3);

}e l s e System . ou t . p r i n t l n ( " En t radac o n s i s t e n t e ! " ) ;

}}

Exercícios adicionais:

1. Considere a verificação de consistência com colchetes [ ] echaves { } (noteque problemas como “([)]” devem ser detectados);

45

Page 47: PMR 2300 - Computação para Automação

2. Codifique um programa que verifica consistência de “{}” em arquivos con-tendo programas em Java, indicando as linhas com problemas.

3.1.2 Implementação de Pilha

Temos a seguir uma implementação de Pilha que usa um arranjo para armazenardados. Note que esta implementação de Pilha usaamortização: quando o arranjoé inteiramente preenchido, seu tamanho é duplicado.

pub l i c c l a s s P i lhaAr {p r i va t e char a r r a n j o [ ] ;p r i va t e i n t topo ;

s t a t i c p r i va t e f i n a l i n t DEFAULT = 10 ;

pub l i c P i lhaAr ( ) {a r r a n j o = new char [DEFAULT] ;topo = −1;

}

pub l i c i n t tamanho ( ) {re tu rn ( topo + 1 ) ;

}

pub l i c char [ ] conteudo ( ) {char c [ ] = new char [ topo + 1 ] ;f o r ( i n t i =0; i <= topo ; i ++)

c [ i ] = a r r a n j o [ i ] ;re tu rn ( c ) ;

}

pub l i c void push (char x ) {topo ++;i f ( topo == a r r a n j o . l e n g t h )

d u p l i q u e A r r a n j o ( ) ;a r r a n j o [ topo ] = x ;

}

pub l i c char pop ( ) {i f ( topo >= 0)

re tu rn ( a r r a n j o [ topo−−]);e l s e re tu rn ( ’ 0 ’ ) ;

}

pub l i c char t op ( ) {

46

Page 48: PMR 2300 - Computação para Automação

i f ( topo >= 0)re tu rn ( a r r a n j o [ topo ] ) ;

e l s e re tu rn ( ’ 0 ’ ) ;}

pub l i c void e s v a z i e ( ) {topo = −1;

}

p r i va t e void d u p l i q u e A r r a n j o ( ) {char novoArran jo [ ] = new char [2 ∗ a r r a n j o . l e n g t h ] ;f o r ( i n t i =0; i < a r r a n j o . l e n g t h ; i ++)

novoArran jo [ i ] = a r r a n j o [ i ] ;a r r a n j o = novoArran jo ;

}}

3.1.3 Avaliação de Expressões

Pilhas são muito usadas no processamento de linguagens, porexemplo em compi-ladores. Uma aplicação importante é a conversão e avaliaçãode expressões numé-ricas.

Existem três tipos de notação para expressões numéricas:

1. infixa, onde operador entre operandos:(A+B);

2. pós-fixa, onde operador segue operandos:(AB+) (notação polonesa re-versa);

3. pré-fixa, onde operador precede operandos:(+AB) (notação polonesa).

A vantagem da notação pós-fixa é que ela dispensa parênteses.Considere osexemplos:

Infixa Pós-fixa

A−B ∗ C ABC∗A ∗ (B −C) ABC − ∗A ∗B −C AB ∗ C−(A−B) ∗ C AB − C∗

A+D/(C ∗DE) ADCDE∗/+

(A+B)/(C −D) AB + CD − /Suponha que tenhamos uma expressão pós-fixa e desejemos obter o valor da

expressão (“avaliar a expressão”). Fazemos isso passando pelos elementos da ex-pressão,

1. empilhando cada operando;

47

Page 49: PMR 2300 - Computação para Automação

2. processando cada operador:

(a) retiramos dois operandos da pilha;

(b) executamos a operação;

(c) empilhamos o resultado.

No final o resultado está no topo da pilha.Considere o exemplo: tome a expressão em notação pós-fixa:

1; 2; 3; ;−; 4; 5; 6; ∗; +; 7; ∗;−.

Essa expressão é igual a1−23−(4+5∗6)∗7 em notação infixa. O processamentopara avaliação é:

Pilha:

Operação Parcial Conteúdo da Pilha

Insere 1 1Insere 2 1; 2Insere 3 1; 2; 3

Operador:23 1; 8Operador: 1-8 -7

Insere 4 -7; 4Insere 5 -7; 4; 5Insere 6 -7; 4; 5; 6

Operador: 5*6 -7; 4; 30Operador: 4+30 -7; 34

Insere 7 -7; 34; 7Operador: 34*7 -7; 238

Operador: -7-238 -245 (Resultado final)

Veja a seguir um exemplo de implementação de algoritmo de avaliação de expres-são pós-fixa.

/∗∗ Ava l iação de e x p r e s s ão pos− f i x a .∗ Operandos apenas i n t e i r o s p o s i t i v o s .∗ Operandos e operadores e p a r ê n t e s e s devem∗ s e r separados por espaços .∗ Autor : Fabio Cozman∗ /

import j a va . u t i l . S t r i n g T o k e n i z e r ;

pub l i c c l a s s Ava l ia {s t a t i c pub l i c void main ( S t r i n g a r gs [ ] ) {

i f ( a r gs . l e ng t h <1) {System . ou t . p r i n t l n ( " I n s i r a e n t r a d a ! " ) ;

48

Page 50: PMR 2300 - Computação para Automação

System . e x i t (−1);}

S t r i n g e n t r a d a = a r gs [ 0 ] ;P i l haAr p i l h a = new P i lhaAr ( ) ;

S t r i n g T o k e n i z e r s t =new S t r i n g T o k e n i z e r ( e n t r a d a ) ;

whi le ( s t . hasMoreElements ( ) ) {S t r i n g nextToken = s t . nextToken ( ) ;i f ( nextToken . compareTo ( "+" ) == 0) {

opera ( p i l ha , 1 ) ;} e l s e i f ( nextToken . compareTo ( "−" )==0) {

opera ( p i l ha , 2 ) ;} e l s e i f ( nextToken . compareTo ( "∗ " )==0) {

opera ( p i l ha , 3 ) ;} e l s e i f ( nextToken . compareTo ( " / " )==0) {

opera ( p i l ha , 4 ) ;} e l s e i f ( nextToken . compareTo ( " ^ " )==0) {

opera ( p i l ha , 5 ) ;} e l s e

p i l h a . push ( new I n t e g e r ( nextToken ) ) ;}System . ou t . p r i n t l n ( " R e s u l t a do= " + p i l h a . pop ( ) ) ;

}

s t a t i c void opera ( P i l haAr p i l ha , i n t t i p o ) {Ob jec t op1 = p i l h a . pop ( ) ;Ob jec t op2 = p i l h a . pop ( ) ;i f ( ( op1==n u l l ) | | ( op2==n u l l ) ) {

System . ou t . p r i n t l n ( " En t radai n c o n s i s t e n t e ! " ) ;System . e x i t (−2);

}I n t e g e r i n t e g e r 1 = ( I n t e g e r ) op1 ;I n t e g e r i n t e g e r 2 = ( I n t e g e r ) op2 ;i n t i n t 1 = i n t e g e r 1 . i n t V a l u e ( ) ;i n t i n t 2 = i n t e g e r 2 . i n t V a l u e ( ) ;

i n t r e s u l t a d o = 0 ;i f ( t i p o == 1)

r e s u l t a d o = i n t 2 + i n t 1 ;e l s e i f ( t i p o == 2)

r e s u l t a d o = i n t 2− i n t 1 ;e l s e i f ( t i p o == 3)

49

Page 51: PMR 2300 - Computação para Automação

r e s u l t a d o = i n t 2 ∗ i n t 1 ;e l s e i f ( t i p o == 4)

r e s u l t a d o = i n t 2 / i n t 1 ;e l s e i f ( t i p o == 5) {

r e s u l t a d o = 1 ;f o r ( i n t i =0; i < i n t 1 ; i ++)

r e s u l t a d o = r e s u l t a d o∗ i n t 2 ;}p i l h a . push (new I n t e g e r ( r e s u l t a d o ) ) ;

}}

Considere agora a conversão de uma expressão infixa para pós-fixa:

1. Varremos a expressão infixa:

(a) ao encontrarmos um operando, o copiamos na saída;

(b) ao encontrarmos um operador, o colocamos em uma pilha; porém an-tes desempilhamos e colocamos na saída os operadores da pilha atéencontrarmos um operador com precedência menor ou uma aberturade parênteses;

(c) ao encontrarmos uma abertura de parênteses, a colocamosna pilha;

(d) ao encontrarmos um fechamento de parênteses, desempilhamos e co-piamos na saída os operadores da pilha até a abertura de parêntesescorrespondente, que é desempilhada e descartada;

2. ao final, desempilhamos e copiamos na saída os operadores que restam napilha.

Note a precedência das operações, da menor para maior:+ ou−, seguida de∗ou\, seguida de.

Exemplo 3.1.1.ExpressãoA/(B + C) ∗D:Entrada Conteúdo da Pilha Saída

A A/ / A( / ( AB / ( AB+ / ( + ABC / ( + ABC) / ABC+* * ABC+/D ABC+/D*

50

Page 52: PMR 2300 - Computação para Automação

Exemplo 3.1.2.Expressão((A − (B ∗ C)) +D):Entrada Conteúdo da Pilha Saída

( (( ( (A ( ( A- ( ( - A( ( ( - ( AB ( ( - ( AB* ( ( - ( * ABC ( ( - ( * ABC) ( ( - ABC*) ( ABC*-+ ( + ABC*-D ( + ABC*-D) ABC+*-D+

Exemplo 3.1.3.ExpressãoA−B ∗ C +D:Entrada Conteúdo da Pilha Saída

A A- - AB - AB* - * ABC - * ABC+ + ABC*-D ABC*-D+

Exemplo 3.1.4.ExpressãoA ∗B − C +D:Entrada Conteúdo da Pilha Saída

A A* * AB * AB- - AB*C - AB*C+ + AB*C-D AB*C-D+

Podemos combinar os algoritmos anteriores e fazer a avaliação de expressõesinfixas usando duas pilhas (uma para operadores e outra para operandos).

Exemplo 3.1.5.Expressão1− 2 3− (4 + 5 ∗ 6) ∗ 7:

51

Page 53: PMR 2300 - Computação para Automação

Entrada Conteúdo da Pilha Saída

1 1- - 12 - 1; 2ˆ - ˆ 1; 23 - ˆ 1; 2; 3- - 1− 2 3 = −7( - ( -74 - ( -7; 4+ - ( + -7; 45 - ( + -7; 4; 5* - ( + * -7; 4; 56 - ( + * -7; 4; 5; 6) - -7; 4 + 5 ∗ 6 = 34

* - * -7; 347 - * -7; 34; 7

−7− 34 ∗ 7 = −245

3.2 Filas (Queues)

Uma fila é uma estrutura em que o acesso é restrito ao elemento mais antigo. Ope-rações:

• enqueue: inserir na fila;

• dequeue: retirar da fila.

A implementação mais comum é por “arranjo circular”:

Vai sair Entrou

dados

Figura 3.3: Arranjo circular de fila

A implementação a seguir usa um arranjo e amortização:

/∗ F i l a baseada em ar r an j o ∗ /

pub l i c c l a s s F i l a A r {p r i va t e Objec t a r r a n j o [ ] ;p r i va t e i n t tamanho ;p r i va t e i n t i n d i c e V a i S a i r ;

52

Page 54: PMR 2300 - Computação para Automação

p r i va t e i n t i n d i c e E n t r o u ;s t a t i c p r i va t e f i n a l i n t DEFAULT = 10 ;

pub l i c F i l a A r ( ) {a r r a n j o = new Objec t [DEFAULT] ;e s v a z i e ( ) ;

}

pub l i c i n t tamanho ( ) {re tu rn ( tamanho ) ;

}

pub l i c void e s v a z i e ( ) {tamanho = 0 ;i n d i c e V a i S a i r = 0 ;i n d i c e E n t r o u = a r r a n j o . l e ng t h−1;

}

pub l i c void enqueue ( Ob jec t x ) {i f ( tamanho == a r r a n j o . l e n g t h )

d u p l i q u e A r r a n j o ( ) ;i n d i c e E n t r o u = i nc r e m e n t e ( i n d i c e E n t r o u ) ;a r r a n j o [ i n d i c e E n t r o u ] = x ;tamanho ++;

}

p r i va t e i n t i n c r e m e n t e (i n t i n d i c e ) {i n d i c e ++;i f ( i n d i c e == a r r a n j o . l e n g t h )

i n d i c e = 0 ;re tu rn ( i n d i c e ) ;

}

p r i va t e void d u p l i q u e A r r a n j o ( ) {Ob jec t novoArran jo [ ] = new Objec t [2 ∗ a r r a n j o . l e n g t h ] ;f o r ( i n t i =0; i < tamanho ; i ++) {

novoArran jo [ i ] = a r r a n j o [ i n d i c e V a i S a i r ] ;i n d i c e V a i S a i r = i nc r e m e n t e ( i n d i c e V a i S a i r ) ;

}a r r a n j o = novoArran jo ;i n d i c e V a i S a i r = 0 ;i n d i c e E n t r o u = tamanho – 1 ;

}

53

Page 55: PMR 2300 - Computação para Automação

pub l i c Objec t dequeue ( ) {i f ( tamanho == 0)

re tu rn ( n u l l ) ;tamanho−−;Ob jec t x = a r r a n j o [ i n d i c e V a i S a i r ] ;i n d i c e V a i S a i r = i nc r e m e n t e ( i n d i c e V a i S a i r ) ;re tu rn ( x ) ;

}

pub l i c Objec t [ ] conteudo ( ) {Ob jec t novoArran jo [ ] = new Objec t [ tamanho ] ;i n t i n d i c e = i n d i c e V a i S a i r ;f o r ( i n t i =0; i < tamanho ; i ++) {

novoArran jo [ i ] = a r r a n j o [ i n d i c e ] ;i n d i c e = i nc r e m e n t e ( i n d i c e ) ;

}re tu rn ( novoArran jo ) ;

}}

3.3 Listas Ligadas (Encadeadas)

Uma alternativa a arranjos é a estrutura de lista ligada, na qual armazenamos dadosem células interligadas.

NósInício da lista

Figura 3.4: Lista ligada.

Os nós são armazenados no Heap. A vantagem desse tipo de estrutura é aflexibilidade permitida no uso da memória. A desvantagem é que alocar memóriaé uma tarefa demorada (mais lenta que acesso a arranjos).

Esse tipo de estrutura é muito flexível e pode acomodar inserção e retirada dedados de locais arbitrários.

Para definir uma lista ligada, precisamos primeiro definir o elemento armaze-nador (nó):

/∗ L i s t a L igada∗ Classe s i m p l e s que implementa um nó de l i s t a l i g a d a∗ /

54

Page 56: PMR 2300 - Computação para Automação

pub l i c c l a s s Nó {Ob jec t dado ;Nó proximo ;

pub l i c Nó( Ob jec t x ) {dado = x ;proximo = n u l l ;

}}

A partir daí podemos implementar várias funcionalidades:

1. Pilhas;

2. Filas;

3. Vector: estrutura genérica de inserção/remoção em localarbitrário.

Note: as bibliotecas padrão da linguagem Java oferecem uma classe Vector,mas com implementação por arranjo (com amortização)!

Uma técnica interessante é permitir um construtor de Nó que tenha o próximonó:

Nó( Ob jec t x , Nó p ) {dado = x ;proximo = p ;

}

Considere então a inserção de um dado em uma posição posterior a um nóreferenciado porcorrente (atual). Temos:

corrente

dado 1 dado2

este nó écorrente.próximo

Figura 3.5: Inserção de dado em lista ligada - parte 1.

Nó temp = new Nó( x , c o r r e n t e . proximo ) ;c o r r e n t e . proximo = temp ;

ou, simplificando:

c o r r e n t e . proximo =new Nó( x , c o r r e n t e . proximo ) ;

55

Page 57: PMR 2300 - Computação para Automação

corrente

dado 1

x

dado2

Figura 3.6: Inserção de dado em lista ligada - parte 2.

O resultado final é:Para remover um nó posterior a um nó indicado porcorrente, temos:

i f ( c o r r e n t e . proximo != n u l l )c o r r e n t e . proximo = c o r r e n t e . proximo . proximo ;

corrente

dado 1 dado2 dado 3

Figura 3.7: Remoção de um dado de lista ligada.

Para visitar todos os elementos de uma lista, de forma similar a um laço quepercorre um arranjo, temos:

f o r (Nó p = l i s t a . p r i m e i r o ; p != n u l l ; p = p . proximo ) {. . .}

3.3.1 Listas Duplamente Encadeadas

Uma estrutura interessante é o deque, composto por nós que apontam em duasdireções:

dado 1 dado2 dado 3

Figura 3.8: Lista duplamente encadeada.

Com essa estrutura é possível percorrer os dados em ambos os sentidos.

56

Page 58: PMR 2300 - Computação para Automação

3.3.2 Implementação de Pilha com Lista Ligada

/∗ Implementação de p i l h a∗ usando l i s t a l i g a d a∗ /

pub l i c c l a s s P i l h a Li {p r i va t e Nó topo ;

pub l i c p i l h a L i ( ) {topo = n u l l ;

}

pub l i c void push ( Ob jec t x ) {Nó n = new Nó( x ) ;n . proximo = topo ;topo = n ;

}

pub l i c Objec t pop ( ) {i f ( topo == n u l l ) re tu rn ( n u l l ) ;Ob jec t t = topo . dado ;topo = topo . proximo ;re tu rn ( t ) ;

}}

3.3.3 Implementação de Fila com Lista Ligada

/∗ Implementação de f i l a∗ usando l i s t a l i g a d a∗ /

pub l i c c l a s s F i l a L i {p r i va t e Nó v a i S a i r ;p r i va t e Nó e n t r o u ;

pub l i c f i l a L i ( ) {v a i S a i r = n u l l ;e n t r o u = n u l l ;

}

pub l i c void enqueue ( Ob jec t x ) {i f ( v a i S a i r == n u l l ) {

e n t r o u = new Nó( x ) ;v a i S a i r = e n t r o u ;

57

Page 59: PMR 2300 - Computação para Automação

} e l s e {e n t r o u . proximo = new Nó( x ) ;e n t r o u = e n t r o u . proximo ;

}}

pub l i c Objec t dequeue ( ) {i f ( v a i S a i r == n u l l ) re tu rn ( n u l l ) ;Ob jec t t = v a i S a i r . dado ;v a i S a i r = v a i S a i r . proximo ;re tu rn ( t ) ;

}}

3.4 Árvores

Uma árvore é uma estrutura composta por nós e arestas entre nós; as arestas sãodirecionadas (“seta”) e:

• um nó (e apenas um) é a raiz;

• todo nó (exceto a raiz) tem uma seta apontando para ele a partir de um outronó (o “pai”);

• um único caminho vai da raiz a qualquer nó.

A

B C D E

F G H I J

K 3

2

1

0

Profundidade

Figura 3.9: Profundidade em árvores.

A altura de um nó é sua profundidade + 1.Árvores em que todo nó tem no máximo dois “filhos” são árvores binárias

(vistas adiante!).Para armazenar os dados em uma árvore, temos que dispor de nóscom referên-

cias aos filhos.Podemos criar um nó que mantenha uma lista ligada na qual estão as referên-

cias aos filhos.No caso da árvore anterior:

58

Page 60: PMR 2300 - Computação para Automação

B DC E

A

IJ

K

H

null

F G

null null

null

null

null

null

null

null null null

Figura 3.10: Árvore implementada com lista ligada.

Uma aplicação de árvores é a estrutura de diretórios de sistemas operacionaiscomo Unix, Linux ou Windows.

Suponha que queiramos imprimir o nome de arquivos a partir deum diretório.Podemos fazer isso com o seguinte algoritmo:

Impr im i r ( ) {Imprima nome do a r qu i vo d i r e t ó r i o c o r r e n t e ;Se f o r um d i r e t ó r i o , e n t ã o para cada e lemento x

c o n t i d o no d i r e t ó r i o e xe c u t e x . Impr im i r ( ) ;}

Note que essa é uma função recursiva. A ordem de “visita” aos nós é chamadadeordem anterior. No exemplo:

A

B

C

D

E

F G

H

I

JK

Figura 3.11: Visita em ordem anterior

Suponha que a ordem seja diferente: primeiro os filhos, depois o pai. Então,no exemplo, teremos:

F, G, B, C, H, D, I, K, J, E, AA ordem de visita é então chamada deordem posterior.De forma geral, árvores podem ser definidas recursivamente:cada nó é a raiz

de uma subárvore. É possível usar essa propriedade para várias tarefas como, porexemplo, calcular altura:

altura do nó = 1 + máx(altura dos filhos).

59

Page 61: PMR 2300 - Computação para Automação

Da mesma forma, o número de nós em uma árvore pode ser calculado recursi-vamente:

número de nós a partir de um nó (incluindo o nó) = 1 + soma(número de nóspara cada filho).

3.4.1 Árvores Binárias

Um tipo particularmente importante de árvore é a árvore binária, aquela em quecada nó tem no máximo dois filhos.

Considere um exemplo de aplicação: armazenamento de expressões. Nessetipo de árvore, as “folhas” contêm variáveis; os demais nós contêm operações.

+

a *

cb

d

Figura 3.12: Aplicação de árvores binárias - armazenamentode expressões.

Para imprimir a expressão codificada através de uma árvore desse tipo:

• a partir da raiz,

– imprima nó esquerdo recursivamente;

– imprima o conteúdo do prórpio nó;

– imprima nó direito recursivamente.

Neste exemplo, obtemos(a+ ((b− c) ∗ d))Esta ordem de visita, particular a árvores binárias, é denominadaordem inte-

rior .Consideremos as várias ordens, para a árvore a seguir:

A

B C

D E

F G

Figura 3.13: Ordens anterior, interior e posterior

• Anterior: A,B,C,D,F,E,G.

60

Page 62: PMR 2300 - Computação para Automação

• Interior: B,A,D,F,C,G,E.

• Posterior:B,F,D,G,E,C,A.

Cada uma dessas ordens pode ser gerada de forma recursiva:Ordem Anterior:

e xe c u t e ( nó ) :v i s i t e Nó ;se ( f i l h o esquerdo e x i s t e )

e xe c u t e ( f i l h o esquerdo ) ;se ( f i l h o d i r e i t o e x i s t e )

e xe c u t e ( f i l h o d i r e i t o ) ;

Ordem Interior:

e xe c u t e ( nó ) :se ( f i l h o esquerdo e x i s t e )

e xe c u t e ( f i l h o esquerdo ) ;v i s i t e Nó ;se ( f i l h o d i r e i t o e x i s t e )

e xe c u t e ( f i l h o d i r e i t o ) ;

Ordem Posterior:

e xe c u t e ( nó ) :se ( f i l h o esquerdo e x i s t e )

e xe c u t e ( f i l h o esquerdo ) ;se ( f i l h o d i r e i t o e x i s t e )

e xe c u t e ( f i l h o d i r e i t o ) ;v i s i t e Nó ;

Note: implementações recursivas são muito comuns em algoritmos para árvo-res!

/∗∗ Árvore B i ná r i a .∗ Classe s i m p l e s que implementa∗ um nó de árvore b i n á r i a .∗ /pub l i c c l a s s NóBinar io {

Ob jec t dado ;NóBinar io esquerdo , d i r e i t o ;

pub l i c nóB i na r i o ( Ob jec t x ) {dado = x ;esquerdo = n u l l ;d i r e i t o = n u l l ;

61

Page 63: PMR 2300 - Computação para Automação

}

pub l i c nóB i na r i o ( Ob jec t x , NóB inar io e , NóBinar io d ) {dado = x ;esquerdo = e ;d i r e i t o = d ;

}

/∗∗ Método r e c u r s i v o para ob t e r∗ número de nós em árvore .∗ /pub l i c i n t tamanho ( ) {

i n t tamanhoEsquerdo = 0 ;i n t t a m a nhoD i r e i t o = 0 ;i f ( esquerdo != n u l l )

tamanhoEsquerdo = esquerdo . tamanho ( ) ;i f ( d i r e i t o != n u l l )

t a m a nhoD i r e i t o = d i r e i t o . tamanho ( ) ;re tu rn (1 + tamanhoEsquerdo + t a m a nhoD i r e i t o ) ;

}

Exercício: Codifique uma função que calcula altura!

3.4.2 Aplicação de árvores binárias: Compressão de textos

Um problema clássico em computação é o de como representar uma sequência debits com informação, ou seja, uma sequência em que os bits representam símbolos.

Uma maneira simples é usar um código com mesmo número de bits para cadasímbolo. Por exemplo:A = 001; B = 010; C = 100.

Em geral é possível comprimir um “texto” codificado em tamanho fixo, usandocódigos de tamanho variável. Ideia básica: quanto mais frequente o símbolo, me-nor seu código.

Exemplo 3.4.1. Suponha que A ocorre 80%, B ocorre 10 % e C ocorre 10% .Considere o código:A = 0; B = 10; C = 11. O comprimento médio é1 ∗ 0.8 +2 ∗ 0.1 + 2 ∗ 0.1 = 1.2.

Um método para geração de códigos que atendem a esse princípio é conhecidocomo método de Huffman.

A técnica usada é a de “codificação de prefixos”: nenhum códigoé prefixo deoutro código.

O algoritmo para geração de códigos de Huffman é baseado em árvores biná-rias.Entrada: tabela em que cada símboloSi tem uma frequênciafi (fi >= 0,

∑fi =

1);

62

Page 64: PMR 2300 - Computação para Automação

Saída: Códigoci para cada símbolosi.Procedimento:

1. Crie uma árvore binária para cada símbolo, contendo apenas o par(si, fi)como raiz;

2. Ordene as árvores em ordem decrescente de frequências, colocando-as emuma lista ordenada L. Em caso de árvores de mesma frequência utilize comoapoio a tabela de entrada, ou seja, a ordem de inserção das árvores de mesmafrequência deve seguir a ordem dos elementos da tabela;

3. Enquanto houver mais de uma árvore disponível:

(a) Retire a árvoreT1 cuja raiz tem menor frequência, indicada porf1(retire último elemento de L);

(b) Retire a árvoreT2 cuja raiz tem menor frequência (entre as árvoresrestantes), indicada porf2 (retire o último elemento de L);

(c) Crie uma nova árvoreT12 em que:

i. a raiz tem 2 filhos:

• o filho esquerdo é a raiz deT2;

• o filho direito é a raiz deT1;

ii. a raiz armazena (S1 ∪S2, f1 + f2) - S1 são símbolos na raiz deT1

eS2 são os símbolos na raiz deT2;

(d) InsiraT12 em L, mantendo L ordenada por frequências (das raízes).Note que se existeTi tal que sua frequência é igual af1 + f2, coloqueT12 "depois"deTi;

4. Os códigos são gerados a partir da única árvore T restante ao final do pro-cesso: atribua 0 para cada arco esquerdo e 1 para cada arco direito; o códigode cada folha é lido no caminho entre a raiz e a folha.

Se o códigoci do símbolosi tem comprimento|ci| em bits, o comprimento médiode uma mensagem será:∑

i |ci| ∗ fi

Exemplo 3.4.2.Considere:si a b c dfi (em %) 79 10 10 1

Obtemos:

Temos:a = 0; b = 11; c = 100; d = 101. O comprimento médio é0.79 ∗ 1 +0.1 ∗ 2 + 0.1 ∗ 3 + 0.01 ∗ 3 = 1.3.

Note: se o código fosse de tamanho fixo igual a 2 bits, o comprimento médioseria0.79 ∗ 2 + 0.1 ∗ 2 + 0.1 ∗ 2 + 0.01 ∗ 2 = 2.

Exemplo 3.4.3.Exemplo:espaço (esp) a b d e f h i k n o r s t u v

9 5 1 3 7 3 1 1 1 4 1 5 1 2 1 1

63

Page 65: PMR 2300 - Computação para Automação

a b c d100

a79

b c d21

cd11

b10

c10

d1

0 1

0 1

0 1

Figura 3.14: Compressão de textos

Veja nas duas figuras a seguir a resolução deste problema. Primeiro é feito odesmembramento para depois serem atribuídos os códigos (comprimidos) de cadacaractere.

3.4.3 Busca por nível e por profundidade

Árvores são muito usadas para representar problemas de busca. Os arcos a partir deum nó são encarados como caminhos alternativos para encontrar algo de interesse.

Suponha que um domínio seja representado como segue:Nesse caso, a busca por F exige a visita em A e C.Existem duas maneiras básicas de fazer busca por um nó em uma árvore:

• busca pornível: visitamos todos os nós em uma determinada profundidade epassamos para a profundidade seguinte;

• busca porprofundidade: visitamos nós em profundidades consecutivas (ob-tido por ordem anterior).

A busca por nível não corresponde a nenhuma ordem vista anteriormente.No exemplo, a busca por nível visita A, B, C, D, E, F, G, H, I.Esse tipo de busca é também chamado de busca emlargura e é muito comum

em algoritmos para jogos.

3.5 Árvores Binárias de Busca

Considere uma árvore onde cada nó contenha um “dado” e um “identificador” parao dado. Suponha que os identificadores possam ser ordenados (por exemplo, sãonúmeros).

Árvores binárias de busca são árvores binárias em que:

• todos os nós descendentes de um nó X, à esquerda de X, têm identificadores“menores” do que o identificador de X;

64

Page 66: PMR 2300 - Computação para Automação

esp9

esp9

e7 a5 5r n4 d3 f 3 t 2

e7 a5 5r n4

esp9

esp9

esp9

esp9

n i k b h e u v o s d a r f t esp46

b1 h1 i1 k1 o1 s u v1 1 1

i k 2 u v22o sb h2

2 2 2 2o su v i k b h

u v o s4 i k b h 4

d3 f 3 t 2

4 4 d3 f 3 t 2i k b h u v o s

f t5

u v o s d7

e7 a5 5r n4

e7 u v o s d7 r 5 f t 5n4 i k b h 4

r f t 10

r f t 10 n i k b h8

n i k b h8

7 u v o s d7 a5

a5

u v o s d a12

u v o s d a12 r f t10 n i k b h8

e

e7

r f t esp19

n i k b h e15

r f t esp19

n i k b h e15 u v o s d a12

n i k b h e u v o s d a27

n i k b h e u v o s d a27 r f t esp19

Figura 3.15: Compressão de textos - desmembramento.

65

Page 67: PMR 2300 - Computação para Automação

n i k b h e u v o s d a r f t esp46

27n i k b h e u v o s d a r f t esp19

n i k b h e15 u v o s d a12

n i k b h8

r f t10esp

9

n4 i k b h 4

e7u v o s d7 5ra5 f t 5

4u v o s d3f 3 t 2

2i k 2b h 2u v 2o s

s1o1v1u1h1b11ki1

0

0

0

0 0

0

0 0

0

0

0

1

1

1

1

1

11

1 1

1 1

1 1 1 10 0

0

0

Figura 3.16: Compressão de textos - reunindo.

B

D

A

C

E

G

F

H

I

Figura 3.17: Busca por F.

• todos os nós descendentes de um nó X, à direita de X, têm identificadores“maiores” do que o identificador de X.

Em uma árvore binária, uma ordem interior passa pelos nós em ordem crescentede identificadores.

Ordem Interior: 1, 2, 3, 5, 7, 9.

3.5.1 Implementação

Busca: inicie na raiz e mova para a direita ou para a esquerda recursivamente.Mínimo: mova sempre à esquerda.Máximo: mova sempre à direita.Inserção: inicie na raiz, mova para direita ou esquerda recursivamente até en-

contrar o ponto de inserção.

/∗

66

Page 68: PMR 2300 - Computação para Automação

Exemplo 3.5.1.

7

2 9

5

3

1

Figura 3.18: Ordem interior

∗ Árvore B i ná r i a de Busca .∗ /

pub l i c c l a s s NóBinar ioBusca {i n t dado ; / / I n t e i r o , para s i m p l i f i c a r !NóBinar ioBusca esquerdo , d i r e i t o ;

pub l i c NóBinar ioBusca (i n t d ) {dado = d ;esquerdo = n u l l ;d i r e i t o = n u l l ;

}

pub l i c NóBinar ioBusca minimo ( ) {NóB inar ioBusca n = t h i s ;whi le ( n . esquerdo != n u l l )

n = n . esquerdo ;re tu rn ( n ) ;

}

pub l i c NóBinar ioBusca maximo ( ) {NóB inar ioBusca n = t h i s ;whi le ( n . d i r e i t o != n u l l )

n = n . d i r e i t o ;re tu rn ( n ) ;

}}

/∗∗ Busca r e c u r s i v a na árvo re∗ /pub l i c NóBinar ioBusca busca (i n t x ) {

67

Page 69: PMR 2300 - Computação para Automação

i f ( x < dado ) {i f ( esquerdo != n u l l )

re tu rn ( esquerdo . busca ( x ) ) ;e l s e re tu rn ( n u l l ) ;

} e l s e i f ( x > dado ) {i f ( d i r e i t o != n u l l )

re tu rn ( d i r e i t o . busca ( x ) ) ;e l s e re tu rn ( n u l l ) ;

} e l s e re tu rn ( t h i s ) ;}

/∗∗ I n s e r ç ão r e c u r s i v a na árvo re∗ /pub l i c void i n s e r i r ( i n t x ){

i f ( x < dado ){

i f ( esquerdo != n u l l )esquerdo . i n s e r i r ( x ) ;

e l s eesquerdo =new NóBinar ioBusca ( x ) ;

} e l s e i f ( x > dado ){

i f ( d i r e i t o != n u l l )d i r e i t o . i n s e r i r ( x ) ;

e l s e d i r e i t o = new NóBinar ioBusca ( x ) ;} e l s e re tu rn ;

}

A remoção de um dado é mais complexa. Vejamos, em ordem, casosde difi-culdade crescente:

1. É feita uma busca e o dado a ser removido não existe: nada a fazer;

2. É feita uma busca e o dado a ser removido está em um nó com nenhum filho:simplesmente remova este nó;

3. É feita uma busca e o dado a ser removido está em um nó com um únicofilho: remova o nó e coloque seu filho no lugar;

4. É feita uma busca e o dado a ser removido está em um nó com doisfilhos:este é o caso mais complicado - veja sua solução no exemplo a seguir:

Suponha que queiramos remover o nó R. Se X já tem dois filhos (ouseja,se X tem outro filho além de R), não temos como colocar A e B como filhos de

68

Page 70: PMR 2300 - Computação para Automação

X

R

A B

Figura 3.19: Remoção do nó R causa problemas.

X. Mesmo se R é o único filho de X, há uma dificuldade: tanto A quanto B são“menores” que X, portanto B não pode figurar como nó direito deX. Solução:encontrar o menor dado na subárvore à direita da raiz R e colocar esse dado em R;depois eliminar o nó que originalmente continha o menor dadoà direita de R.

Exemplo prático:

9

4

o nó 2

Remova

1 5

7

3

4

7

2

1 5

3

9

Figura 3.20: Remoção do nó ’2’.

Isso funciona, pois o nó contendo o menor dado em uma subárvore só podeconter 0 ou 1 filho. Portanto, remover esse nó sempre é trivial.

/∗∗ Remoção r e c u r s i v a na árvo re ;∗ r e t o r n a nó r a i z da árvo re .∗ /pub l i c NóBinar ioBusca remover (i n t x ) {

i f ( x < dado ) {i f ( esquerdo != n u l l )

esquerdo = esquerdo . remover ( x ) ;} e l s e i f ( x > dado )

{i f ( d i r e i t o != n u l l )

d i r e i t o = d i r e i t o . remover ( x ) ;} e l s e re tu rn ( remove ( ) ) ;

69

Page 71: PMR 2300 - Computação para Automação

re tu rn ( t h i s ) ;}

p r i va t e NóBinar ioBusca remove ( ) {/ / Sem f i l h o s ou um f i l h o d i r e i t o :i f ( esquerdo == n u l l ) re tu rn ( d i r e i t o ) ;

e l s e { / /Um f i l h o esquerdo :i f ( d i r e i t o == n u l l ) re tu rn ( esquerdo ) ;

e l s e { / / Dois f i l h o s :i f ( d i r e i t o . esquerdo ==n u l l ) {

dado = d i r e i t o . dado ;d i r e i t o = d i r e i t o . d i r e i t o ;

} e l s e {NóB inar ioBusca pa i = d i r e i t o ;NóB inar ioBusca f i l h o = pa i . esquerdo ;whi le ( f i l h o . esquerdo != n u l l ) {

pa i = f i l h o ;f i l h o = pa i . esquerdo ;

}dado = f i l h o . dado ;pa i . esquerdo = f i l h o . d i r e i t o ;

}}re tu rn ( t h i s ) ;

}}

Note: essa função retorna o nó raiz da árvore com dado removido.Note: da forma como definido, uma árvore de busca binária não tem elemen-

tos repetidos. Se for necessário armazenar elementos com mesmo identificador, éconveniente usar uma estrutura auxiliar (por exemplo, uma lista ligada) em cadanó.

Uma possibilidade interessante é obter o k-ésimo maior elemento em uma ár-vore de busca binária. Para isso, adicione em cada nó um contador que indicaquantos nós existem sob o nó.

Para encontrar o k-ésimo elemento:

• Sek = (#E + 1) + 1→ X é o nó.

• Sek < (#E + 1) + 1→ k-ésimo elemento está à esquerda; reinicie em Y.

• Sek > (#E + 1) + 1→ k-ésimo elemento está à direita; reinicie em Z.

70

Page 72: PMR 2300 - Computação para Automação

11

6 3

5

4

2

0

20

1

0

0

Figura 3.21: Árvore de busca binária.

#E #D

E D

X

Y Z

Figura 3.22: k-ésimo elemento.

3.5.2 Complexidade de busca em árvore binária

O custo de busca é proporcional ao número de nós visitados atéatingir o nó pro-curado. O esforço médio de busca é igual à altura da árvore; nopior caso, essenúmero é igual ao número de nós:

Uma árvorebalanceadaé uma árvore que tem altura de ordemO(logN), ondeN é o número de nós na árvore. Intuitivamente, uma árvore balanceada é uma ár-vore “cheia”, em que os nós não-folhas têm dois filhos. Se supusermos que osdados são inseridos em uma árvore com identificadores uniformemente distribuí-dos, temos:

Teorema: O esforço médio de busca em uma árvore binária éO(logN).Temos o seguinte resultado:Teorema: A altura média de uma árvore binária de busca com inserções uni-

formemente distribuídas é1.38 logN .Note: “Uniformemente distribuídas” significa que todas as permutações de

sequências de entrada têm mesma probabilidade.

71

Page 73: PMR 2300 - Computação para Automação

linear

Figura 3.23: Custo nas árvores de busca binária.

3.6 Hashing e Hash Tables (Tabelas de Dispersão)

A ideia básica de hashing é espalhar os dados em um arranjo. Cada entrada doarranjo corresponde a um aglomerado “pequeno” de dados:

g1

g2

g3

Figura 3.24: Hashing.

Quando um dado é inserido, o aglomerado (“bucket”) que o receberá é aces-sado e o dado é ali inserido. O bucket pode ser armazenado em uma lista ligada,por exemplo.

Quando um dado é procurado, acessamos seu bucket e o procuramos ali. Comoos buckets são “pequenos”, a procura é rápida. Para que isso funcione, temos quegarantir que:

1. os aglomerados sejam exaustivos, ou seja, um dado sempre éassociado a umaglomerado;

2. os aglomerados sejam mutuamente exclusivos, ou seja, só um aglomeradopor dado;

3. os dados sejam “bem espalhados” entre os aglomerados disponíveis.

Precisamos assim de um esquema deendereçamentoque produza o endereçode um bucket a partir de um dado.

Note que os dados não são necessariamente numéricos, portanto precisamos deuma função de endereçamento bastante genérica (“função de hashing”). Em geral,o dado é primeiramente transformado em um inteiroK. Existem várias funções dehashing.

72

Page 74: PMR 2300 - Computação para Automação

3.6.1 Funções de Hashing

1. Divisão inteira:h = (K%n)︸ ︷︷ ︸

resto

+1.

Exemplo 3.6.1.Suponha que temos 5 buckets, ou seja,n = 5:

• 54→ 54%5 + 1 = 4 + 1 = 5;

• 41→ 41%5 + 1 = 1 + 1 = 2;

• 4→ 4%5 + 1 = 4 + 1 = 5.

2. Extração de dígitos.

Exemplo 3.6.2. • 547790→ 577 (1◦, 3◦ e 4◦ dígitos);

• 856430→ 85 (1◦ e 2◦ dígitos).

3. “Fold digits”: adição de dígitos.

Exemplo 3.6.3.123456789 ⇒ 123 + 456 + 789 = 1368 → 368 (pegamosos 3 últimos dígitos).

4. Polinomial: compute um polinômiop(k) e extraia dígitos.

O objetivo é sempre “espalhar” os dados entre osn buckets. A função dehashing de divisão inteira é muito usada.

3.6.2 Encadeamento separado ou encadeamento aberto

Até agora consideramos Hash Tables onde os dados estão armazenados em umaestrutura auxiliar para cada bucket. Isso é denominadoencadeamento separado(ou textitencadeamento externo).

No encadeamento aberto, os dados estão armazenados diretamente em um ar-ranjo único. Considere a seguinteestratégia linear: se vamos inserir um dado comfunção de hashing por divisão inteira e o códigoh = (K%n) + 1 leva a uma po-sição no arranjo que que já está ocupada, tentamosh + 1, h + 2, h + 3, · · · , atéencontrarmos uma posição vaga. É aqui que o dado será inserido.

Note: em encadeamento aberto, não podemos remover diretamente um item;para “remover” um item, o retiramos e marcamos sua posição como “vazia”.

Algumas operações:

1. Busca. Para encontrarmos um dado, simplesmente fazemos os mesmospas-sos até que encontramos o dado ou "esgotamos"o "bucket"(note que esseprocesso requer informação sobre quantos dados há em cada bucket - parasabermos quando parar);

2. Remoção.Para remover um dado, temos que, primeiro, encontrá-lo, e de-pois:

73

Page 75: PMR 2300 - Computação para Automação

• mover todos os demais dados do bucket;

• marcar aquela posição como vazia.

Uma estratégia que tem melhor desempenho na prática é oespalhamento qua-drático, no qual se usa a sequência de endereços

(i+ j2)modN

paraj = 0; 1; 2; · · · , até encontrar um elemento vago (nesse caso, utiliza-seNprimo para obter garantias teóricas de desempenho).

Finalmente, usa-se também o “hashing duplo”, em que uma função de hashsecundária é usada.

3.6.3 Alguns conceitos importantes em hash tables

1. Fator de Carga (load factor). Fração da tabela que está cheia (portanto éum número entre 0 e 1) para encadeamento aberto. Normalmentedeseja-seque uma hash table não opere com fator de carga próximo de 1 (emencade-amento aberto).

2. Rehashing. Quando o fator de carga fica muito alto, o arranjo base de ar-mazenamento precisa ter seu tamanho aumentado (um novo arranjo maior écriado, e os dados são copiados nele). Durante rehashing sãotambém retira-das as posições marcadas como “vazias” (criadas por remoçãode dados).

Uma análise matemática detalhada revela que o número de acessos realizadosem média para inserir um dado em uma hashtable com encadeamento aberto linearé

n ≈1 + 1

(1−λ)2

2em queλ é o fator de carga.

Note: paraλ = 12 , temosn = 2.5; paraλ = 9

10 , temosn = 50.Para procurar um dado, temos:

• Se o dado não está na hashtable,

n ≈1 + 1

(1−λ)2

2.

• Se o dado está na hashtable,

n ≈1 + 1

(1−λ)

2.

Para encadeamento aberto quadrático com número primo de aglomerados eλ < 1

2 , nenhuma inserção faz mais que dois acessos a um mesmo aglomerado.A análise e os resultados sobre custo médio são muito mais complicados nesse

caso.

74

Page 76: PMR 2300 - Computação para Automação

3.7 Grafos

Um grafo é uma estrutura que generaliza árvores, sendo formado por nós e arestas.Cada nó em um grafo pode ser conectado a vários outros nós. Se as arestas têmdireção (neste caso são chamadasarcos), o grafo édirecionado. Se as arestas nãotêm direção, o grafo énão-direcionado.

Grafo direcionado(ou dirigido)

Grafo não−direcionado(ou não−dirigido)

Figura 3.25: Grafos.

Um grafo direcionado éacíclico quando não existe um caminho direcionadoque parte de um nó e retorna ao mesmo nó.

Grafos são usados para representar redes rodoviárias, eletrônicas ou de forneci-mento de energia; modelos mecânicos ou estatísticos, etc. Quando um arco conectadois nós A e B, partindo de A para B, o Nó A épai (ou origem do arco) e nó o B éfilho (ou destino do arco). Dois nós são adjacentes se são conectados por arestas.

Existem várias maneiras de implementar computacionalmente uma estruturade grafos:

1. Lista de arestas:

• armazenamos cada nón como um objeto;

• armazenamos cada arestae como um objeto contendo

– nós origem e destino;

– indicação sobre direcionalidade.

(outros dados, como nome, custo, etc, podem ser armazenadosnesses obje-tos).

A B

C

D

Figura 3.26: Lista de arestas.

nós: A, B, C, D

75

Page 77: PMR 2300 - Computação para Automação

arestas: (A,C), (B,C), (C,D), (A,D)

Nessa configuração é fácil acessar arestas mas nem sempre é fácil encontraruma aresta a partir de um nó.

2. Lista de adjacências: Adicionamos, a cada nó, uma lista na qual estãocontidos os nós adjacentes (ou as arestas ligadas ao nó). Assim, podemosencontrar adjacências facilmente, bem como partir de arestas e encontrarnós.Frequentemente a lista de arestas não é implementada quando temos alista de adjacências.

A B

C

D

Figura 3.27: Lista de adjacências.

3. Matriz de adjacências: Cada nó recebe um índice inteiro; a matriz arma-zena no elementoij uma referência à aresta entre o nói e o nój (se a arestaexiste).

A B

C

D

Figura 3.28: Matriz de adjacências.

∅ ∅ eAB eAD

∅ ∅ eBC ∅∅ ∅ ∅ eCD

∅ ∅ ∅ ∅

.

3.7.1 Busca em profundidade e em largura

É muito comum termos dados organizados em um grafo e desejarmos encontrar onó que contém um dado particular. Supondo que a busca pelo dado d começa emum nón, existem duas maneiras básicas de realizar esse tipo de busca:

1. Busca em profundidade: A partir de um nó, escolhemos um vizinho não-visitado e continuamos a busca nesse vizinho, marcando antes o nó como

76

Page 78: PMR 2300 - Computação para Automação

visitado. Se chegarmos a um ponto sem vizinhos não-visitados, retornamosa um nó que não tenha todos os vizinhos visitados. O algoritmoé:

DFS( g r a f o G, nó n , dado d ) :se dado d e s t á em n , r e t o r n e ;pa ra t odos os v i z i n h o s de n ,

se o v i z i n h o m não f o i v i s i t a d o ,DFS(G, m, d ) ;

A B C D

E F G H

I J

M N O P

K L

1

2

3

4

5

6

7 8

9

10

11

1213

14 15

16

Figura 3.29: Busca em profundidade.

2. Busca em largura: Nesse caso, o grafo é dividido em níveis a partir de umnó de onde a busca está sendo iniciada. O nó inicial está no nível 0; seusvizinhos estão no nível 1; os vizinhos destes nós que não foram visitadosestão no nível 2. Em geral, o nívelLi é formado pelos vizinhos de nós emLi que não estejam nos níveisL0, L1, · · · , Li−1.

O código básico que realiza busca em largura, usa listas auxiliares para arma-zenar os níveis do grafo:

BFS ( g r a f o G, nó n ) :c r i e l i s t a L com nó n ;enquanto a l i s t a L c o n t i v e r algum nó , r e p i t a :

r e t i r e o p r i m e i r o nó de L ;se dado r e t i r a d o e s t á ne s s e nó , r e t o r n e ;caso c o n t r á r i o , co loque os v i z i n h o sdo nóno f i n a l de L ( apenas a q u e l e s v i z i n h o s quenão e s t ã o em L ) ;

Selecione vizinhos em sentido horário.

77

Page 79: PMR 2300 - Computação para Automação

B D

E G H

I J

M N O P

K L

F

CAL0

L1

L2

L3

L4

L5

L2L1

L3

Figura 3.30: Busca em largura.

A B C

E F G

I

n

Figura 3.31: Exemplo de busca em largura.

Temos: L0 = {A}; L0 = {B,F,E}; L0 = {F,E,C}; L0 = {E,C, I};L0 = {C, I}; L0 = {I,G}; L0 = {G}; L0 = ∅.

Note que podemos usar o mesmo esquema para fazer busca em profundidadesem recursão:

DFS( g r a f o G, nó n , dado d ) :c r i a uma l i s t a L com nó n ;enquanto l i s t a L c o n t i v e r algum nó , r e p i t a :

se dado d procurado e s t á n e s t e nó , r e t o r n e ;caso c o n t r á r i o , co loque os v i z i n h o sdo nóno i n í c i o de L ( apenas a q u e l e s v i z i n h o s quea i nda não e s t ã o em L ) ;

78

Page 80: PMR 2300 - Computação para Automação

3.7.2 Grafos com pesos e caminhos mínimos

Um grafo ponderado é um grafo que tem um peso numéricow(e) associado a cadaarestae. O comprimentode um caminhoc é a soma dos pesos nas arestas em c:

w(c) =k−1∑

i=0

w((nc, nc+1))

comc = ((n0, n1), · · · , (nk−1, nk)). A distância entre dois nós é o comprimentomínimo entre eles.

Vamos considerar apenas o caso em que todos os pesos são não-negativos(w(i) ≥ 0). Nesse caso existe um algoritmo importante:Algoritmo de DykstraCaminho mínimo entre nón e qualquer outro nó.O algoritmo é basicamente uma busca em largura “ponderada”,começando a partirda origemn do caminho procurado. A busca se expande em torno den examinandonós em ordem de distância.Vamos supor que todas as arestas são não-direcionadas e que não há um nó comaresta para ele mesmo nem pares de nós com arestas “paralelas” entre eles.Definimos uma funçãoD(v) que retorna a distância entren e v encontrada até omomento. Inicialmente,D(n) = 0 eD(v)→∞ parav 6= n.Também definimos um conjuntoC contendo os nós já explorados em largura.No início, colocamosn emC.A cada iteração, colocamos emC um vérticev (ainda não emc) que tenha menorD(v). Neste ponto atualizamosD(z) para todo nóz que é vizinho dev e não estáem L: seD(v) + w((v, z)) < D(z), entãoD(z)← D(v) + w((v, z)).

Dyks t ra ( g r a f o G, nó n )/ / g r a f o não−d i r e c i ona d o sem a r e s t a s p a r a l e l a s .D( n ) = 0 , D( v ) = i n f i n i t o para v != n ;c r i e l i s t a L ordenada com nós ordenados por D ( . ) ;enquanto L não f o r vaz ia , r e p i t a :

pa ra cada v i z i n h o z de v em L :se D( v ) + w( ( v , z ) ) < D( z )

D( z ) = D( v ) + w( ( v , z ) ) ;co loque o peso de z como D( z ) ;r e o r de ne L ;

ao fim , r e t o r n a D( v ) pa ra cada nó v .

Exemplo 3.7.1.Nó BWI.

Note que quando um nóv é removido deL (colocado emC), seu rótuloD(v)contém a distância correta entren e v. Ao fim, todos os caminhos mínimos aténestão determinados.

79

Page 81: PMR 2300 - Computação para Automação

BOS

PVD

JFK

BWI

SFO

MIA

LAX

ORD

DFW

2704

1846

867 187

849

144

12581090

946

1121

2342

1235

337 13111464

184

740

621802

371

621

328

184

0

2467

1423

9462658

BOS

PVD

JFK

BWI

SFO

MIA

LAX

ORD

DFW

Figura 3.32: Melhor caminho entre aeroportos nos EUA.

Exemplo 3.7.2.

n

1 2

3 4

5

2 6

2

2

4

24

3

1

n

1 2

3 4

5

2

2

2

3

2

5

6

3

4

0

1

Figura 3.33: Exemplo - algoritmo de Dykstra.

Demonstração(quando nó entra emC, D(v) está correto):Em primeiro lugar, o valor deD(z)(z 6∈ C) representa um caminho mínimo

den az usando vértices emC.Usamos indução finita.A sentença está correta para o primeiro nó, que én comD(n) = 0.Assuma que os primeirosN nós colocados emC tenhamD(.) correto. Consi-

dere agora o nóv que tem menorD(.) dentre os nós fora deC.Suponha (para obter uma contradição) que haja um caminho entre n e v de

comprimento menor queD(v). Este caminho deve passar por um nóu não-visitado(fora deC). O caminho atéu tem todos os nós comD(.) correto (por hipótese).

Além disso,D(u) < D(v), poisu está no caminho mais curto atév. Obtemosuma contradição, pois teríamos escolhidou em vez dev para colocar emC.

Em relação a estruturas de dados, o seguinte resumo é válido.

80

Page 82: PMR 2300 - Computação para Automação

v

u

n z

3

6

v

u

n

3

6

C C 2

3D(v)=3

D(u)=2

D(Z)=2+6=8

D(z)=6z

Figura 3.34: Qual o caminho mais curto entre z e n?

C

d>0

D(v)

D(u)

nu

v

Figura 3.35: Contradição.

3.8 Resumo

1. Arranjos

(a) rápidos no acesso;

(b) fáceis de ordenar→ quando ordenado, fácil de buscar;

(c) necessidade de amortização para gerenciar aumentos;

(d) dificuldade de inserção/remoção mantendo demais dados.

2. Listas ligadas

(a) lentas, mas flexíveis;

(b) facilidade de inserção/remoção arbitrárias.

3. Árvores

(a) estruturas com hierarquia;

81

Page 83: PMR 2300 - Computação para Automação

(b) possibilidade de ordenação rápida;

(c) custo de manutenção alto.

4. Hashtables

(a) rapidez em busca e acesso;

(b) alguma perda em memória;

(c) difícil implementação.

82

Page 84: PMR 2300 - Computação para Automação

3.9 Exercícios

Alguns exercícios a seguir lista tem implementações em software, com testes,nos sequintes arquivos:http://www.poli.usp.br/p/fabio.cozman/Didatico/Deque.javahttp://www.poli.usp.br/p/fabio.cozman/Didatico/ListaLigada.javahttp://www.poli.usp.br/p/fabio.cozman/Didatico/Verifique.javahttp://www.poli.usp.br/p/fabio.cozman/Didatico/ArvoreBinariaBusca.java

1. Escreva uma classe chamadaComplexo que opera sobre números comple-xos. O construtor básico deve ser:Complexo( double a, double b ).Um segundo construtor deve ser providenciado para criar o número reala:Complexo( double a ).Codifique os métodosadd(Complexo c),subtract(Complexo c),multiply(Complexo c) edivide(Complexo c).

2. Considere que você comprou uma biblioteca contendo a classeComplexo,cujo manual indica:

pub l i c c l a s s Complexo :pub l i c Complexo (double a , double b ) ;pub l i c Complexo add ( Complexo c ) ;pub l i c Complexo s u b t r a c t ( Complexo c ) ;pub l i c Complexo m u l t i p l y ( Complexo c ) ;pub l i c Complexo d i v i d e ( Complexo c ) ;

Você deseja criar uma classe comoComplexo, porém com métodos adi-cionais que permitem somar, subtrair, dividir e multiplicar por um númeroreal:

pub l i c Complexo add (double d ) ;pub l i c Complexo s u b t r a c t (double d ) ;pub l i c Complexo m u l t i p l y (double d ) ;pub l i c Complexo d i v i d e (double d ) ;

Codifique uma classeSuperComplexo que contém toda a funcionalidadeindicada anteriormente usando o esquema de hierarquias de Java.

3. Considere um programa que contenha umpackage aeroporto. Temosa classePessoa, com atributoint RG, e a classePassageiro, que ésubclasse dePessoa e tem atributoint ID e métodopublic voidaccess(). Temos também a classeRota, com atributosprivate intID eAeroporto aeroporto. A classeAeroporto tem atributoStringnome. Finalmente, a classeReserva tem atributosdouble valor ePassageiro 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).

83

Page 85: PMR 2300 - Computação para Automação

DICA: O código para a classe Passageiro é

package a e r o p o r t o ;pub l i c c l a s s P a s s a g e i r o extends Pessoa {

i n t ID ;pub l i c void a c c e s s ( ) {}

}

4. Considere umpackage denominadoescola. Temos as seguintes classes.ClassePessoa tem atributospublic String nome eprivate intID. ClasseAluno é subclasse dePessoa e tem atributosprivate intnumero. ClasseArea tem atributoprotected int codigo. ClasseHabilitacao é subclasse deArea e tem atributoAluno aluno.

(a) Codifique uma implementação simples para cada classe. Sehouvermembros com acesso não indicado no diagrama de classes, assumaacesso público para esses membros.

(b) É possível acessar:

• codigo emArea a partir dePessoa? DeAluno? DeHabilitacao?De classes em outro pacote?

• nome emPessoa a partir dePessoa? DeAluno? DeHabilitacao?De classes em outro pacote?

5. Considere as seguintes classes:

• Tree (contém uma variávelage que éprotected)

• Deciduous extends Tree

• Evergreen extends Tree

• Pine extends Evergreen

• Forest

Suponha que todas as classes estão no mesmopackage. Desenhe um di-agrama de classes simplificado, sem indicar métodos nem variáveis. Quaisclasses podem acessar a variávelage da classeTree? Suponha agora quetodas as classes estejam empackages diferentes; quais classes podemacessar a variávelage da classeTree?

6. Suponha que você estã codificando um programa para controle fiscal de umaempresa. As seguintes classes estão sendo planejadas:

• Classe Pessoa, contendo membros nome (String, public), rg (int, pri-vate) e id (int, protected).

• Classe Cliente, sub-classe de Pessoa, contendo membro categoria (int).

84

Page 86: PMR 2300 - Computação para Automação

• 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, pro-tected).

As três primeiras classes compõe o pacote pessoas; as demaiscompõe opacote produtos.

(a) Apresente o código que define cada uma dessas classes com seus mem-bros. [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 sobreuma 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 sobreuma fila: en-queue(5), enqueue(3), dequeue(), enqueue(2), enqueue(8), dequeue(), de-queue(), enqueue(9), enqueue(1), dequeue(), enqueue(7),enqueue(6), de-queue(), dequeue().

9. Qual é o custo em notação BigOh para inserção de um elementoem umapilha 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 donó com dado 10? Qual é a expressão representada pela árvore, em notaçãoinfixa (justifique)?

85

Page 87: PMR 2300 - Computação para Automação

-

* +

+ 3 * +

3 3 41 1110

11. Considere a inserção dos seguintes números em uma árvorebiná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 in-serções em uma árvore binária de busca não importa; qualquerque seja aordem de inserção dos elementos em uma árvore binária de busca, a árvoreé a mesma.

13. Uma listaduplamente ligadaé uma lista na qual cada nó tem uma ligaçãopara o próximo nó e também para o nó anterior. Uma lista duplamente ligadaé frequentemente referida comodeque. 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 ;. . . / / cod igo contendo os metodos da c l a s s e ( a comp le ta r ) .

}c l a s s Node {

Ob jec t e lement ;Node next , prev ;. . . / / cod igo contendo os metodos da c l a s s e ( a comp le ta r ) .

}

Discussão e solução:

A idéia em um deque é que cada nó aponta para o próximo nó e para onó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 . nex t ) {. . .

}

Apenas para ilustrar o funcionamento de um deque, suponha que temos umobjetoe e queremos achar o nó que contém esse objeto em um deque. Su-ponha que o deque é o objetolista. 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 . nex t ) {i f ( p . e lement == e )

86

Page 88: PMR 2300 - Computação para Automação

break ;}

Ao fim desse processo,p é o nó que contéme.

Uma maneira bastante simple de implementar um deque é fazer odeque com“sentinelas”; ou seja, montar uma lista aonde o primeiro e o último nós nãocontém nenhum dado e servem apenas para garantir quefirst e lastnunca sejamnull. Percorremos um deque com “sentinelas” fazendo:

f o r ( Node p = l i s t a . f i r s t . nex t ; p != l i s t a . l a s t ; p = p . nex t ) {. . .

}

Retornando ao exercício, considere a solução a seguir, que primeiro varreo deque contando o número de nós, e depois vai até a metade (note queestamos usando sentinelas):

/ / Encont ra e lemento do meio com con tador .pub l i c Objec t midd leE lement ( ) {

i n t i = 0 ;Node p , q ;f o r ( p = f i r s t . nex t ; p != l a s t ; p = p . nex t ) {

i ++;}i n t meio = i / 2 ;i = 0 ;f o r ( q = f i r s t . nex t ; i < meio ; q = q . nex t ) {

i ++;}re tu rn ( q . e lement ) ;

}

É fácil resolver o exercício sem usar contadores para dequescom númeroímpar do nós. A solução é começar a varrer o deque do início e dofinal,a cada passo incrementando um lado e decrementando outro, até atingir omesmo nó (que é o nó do meio).

/ / Encont ra e lemento do meio sem con tador ./ / Para deque com numero impar de e l e m e n t os !pub l i c Objec t middleElementOdd ( ) {

Node p = f i r s t . nex t ;Node q = l a s t . prev ;whi le ( p . e lement != q . e lement ) {

p = p . nex t ;q = q . prev ;

}

87

Page 89: PMR 2300 - Computação para Automação

re tu rn ( p . e lement ) ;}

14. Crie um método para concatenar duas lista ligadas e formar uma nova listaligada.

Discussão:

Vamos resolver esse problema assumindo duas listas (listasnormais 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 {

Ob jec t e lement ;Node nex t ;

}

Então:

/ / Concatenas t a t i c L i s t a L i g a d a c onc a t e na ( 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 pa 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 . nex t ) {

q = p ;}/ / Agora l i gamos o u l t i m o no ’ de l i s t a 1 com l i s t a 2 :q . nex 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 ;re tu rn ( l ) ;

}

O custo desse procedimento éO(n), onden é o tamanho delista1.

15. Apresente um fragmento de código para concatenar dois deques com as es-truturas esquematizadas no Exercício 1.

Discussão e solução:

Supondo deques sem sentinelas, basta fazer:

88

Page 90: PMR 2300 - Computação para Automação

l i s t a 2 . f i r s t . p rev = l i s t a 1 . l a s t ;l i s t a 1 . l a s t . nex 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 coisasem destruir os deques iniciais, é preciso efetivamente criar novos nós paracada um dos nós emlista1 elista2. Ou seja, é preciso criar um dequenova e varrer os outros dois deques (primeirolista1 e depoislista2),criando um nó para cada elemento nesses deques. Faça isso como um exer-cício.

Considere agora a concatenação de deques com “sentinelas”.Isso complicaum pouco o código; como um exercício adicional, imagine o quedeve serfeito.

16. Codifique um método que troca a posição de dois nósx e y em uma listaligada. O método deve receber referências aos dois nós, com aseguintechamada:

void t r o q u e ( Node x , Node y ) { . . . }

Discussão e solução:

Se tivéssemos que trocar apenas os conteúdos dex ey, seria fácil:

Ob jec t temp = x . e lement ;x . e lement = y . e lement ;y . e lement = temp ;

No entanto temos que trocar efetivamente os nós. Para isso, temos que en-contrar o pai e o filho dex e y. Vamos assumir quex e y não sãonull.Fazemos então:

/ / Troca do 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 . nex t ) {

i f ( p . nex t == x )paiX = p ;

i f ( p . nex t == y )paiY = p ;

}Node f i l hoX = x . nex t ;Node f i l hoY = y . nex t ;

89

Page 91: PMR 2300 - Computação para Automação

/ / Agora fazemos a t r oc a :paiX . nex t = y ;y . nex t = f i l hoX ;paiY . nex t = x ;x . nex t = f i l hoY ;

}

17. Codifique um algoritmo para garantir que sequências de caracteres estejambalanceadas em relação a parênteses, colchetes e chaves. O método devereceber uma String contendo uma sequência de caracteres, e verificar o ba-lanceamento dos parênteses, colchetes e chaves.

Discussão:

O problema aqui é garantir que cada parênteses (ou colchete ou chave) queseja aberto seja também fechado, e que não haja problema na ordem de aber-tura e fechamento. A solução mais simples é através de uma pilha. Suponhaque a entrada do algoritmo seja um arranjo contendo caracteres. Assumaque uma classePilha como vista em aula esteja disponível, porém assumaque esta classe manipule diretamente caracteres (ou seja, dêpush epop emcaracteres). Assuma quepop retorna um espaço quando a pilha está vazia.

Então, colocamos cada “abertura” na pilha, e retiramos uma “abertura” quandoencontramos um “fechamento”. Os erros possíveis são: uma “abertura”nunca é fechada (pilha não está vazia no final), uma “abertura” não casacom um “fechamento”, ou um “fechamento” não tem abertura.

/ / Re to rne f a l s e se ha ’ erro , t r u e se nao ha ’ e r ro :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 az 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 != ’ ( ’ ) ) {

re tu rn ( f a l s e ) ; / / De tec tou er ro !}

}i f ( a r r a n j o [ i ] == ’ ] ’ ) {

t e s t e = p i l h a . pop ( ) ;

90

Page 92: PMR 2300 - Computação para Automação

i f ( ( t e s t e == ’ ’ ) | | ( t e s t e != ’ [ ’ ) )re tu rn ( f a l s e ) ; / / De tec tou er ro !

}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 != ’ { ’ ) )

re tu rn ( f a l s e ) ; / / De tec tou er ro !}

}/ / P i l ha tem que e s t a r v az i a !i f ( p i l h a . pop ( ) != ’ ’ )

re tu rn ( f a l s e ) ;/ / Se chegou a t e ’ aqui , nao ha ’ e r ro :re tu rn ( t rue ) ;

}}

18. Codifique um método que inverte uma fila. O método recebe umobjeto dotipo FilaAr e deve retornar uma fila invertida.

Discussão:

Uma solução simples: crie uma pilha; coloque todos os elementos da fila napilha, 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 re-versa):

ABC ∗+C ∗D+

SeA = 2, B = 3, C = 4, D = 5, qual o valor da expressão? Suponha quea expressão é avaliada através de uma pilha; desenhe o conteúdo da pilha aoencontrar cada operando.

Solução:

A sequência abaixo mostra a pilha em vários momentos do algoritmo, indi-cando as operações que levam a mudanças na pilha:

CBA∗ B ∗ C

A+

CA+B ∗ C ∗

DC ∗ (A+B ∗ C)

+ D + C ∗ (A+B ∗ C)

Para os valores indicados, temos5 + 4(2 + 3 ∗ 4) = 61.

91

Page 93: PMR 2300 - Computação para Automação

20. Escreva um método que recebe uma lista ligadalista, um objetoe e umnóx da lista, e insere um novo nó contendoe antesdex.

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 , Ob jec t e ) {/ / P r ime i ro e nc on t r a pa i de x .f o r ( Node p = f i r s t ; p != n u l l ; p = p . nex t )

i f ( p . nex t == x )break ;

i f ( p == n u l l )re tu rn ;

/ / Cr ia novo no ’ .Node novo = new Node ( ) ;novo . e lement = e ;/ / I n s e r e novo no ’ .p . nex t = novo ;novo . nex t = x ;

}

21. Modifique a implementação de fila com arranjo para que o métododequeuereduza o comprimento do arranjo (pela metade) sempre que apenas um quartodo arranjo esteja ocupado.

22. Escreva uma classe que implementa uma fila com arranjo circular, com osmétodosenqueue, dequeue (como visto em aula) e com o novo métodoenqueueFirst, que coloca um objeto como primeiro da fila. Pede-se queo métodoenqueueFirst tenha custoO(1), exceto nos casos em que oarranjo está cheio (resolva essa situação por amortização).

23. Esquematize um procedimentonão recursivo para imprimir uma árvore bi-nária em ordem anterior.

Discussão e solução:

Use uma pilha:

(a) Inicialize uma pilha epush 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, compop, e imprima essenó.

92

Page 94: PMR 2300 - Computação para Automação

ii. Tome os filhos do nó que foi retirado e coloque-os na pilha;colo-que primeiro o nó direito e depois o nó esquerdo.

Esse procedimento garante que todo nó será impresso antes deseus filhos, etodo 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ó A será colocado na pilha. A partir daí:

(a) A será retirado e impresso; C e B serão colocados.

(b) B será retirado e impresso; E e D serão colocados.

(c) D será retirado e impresso; nenhum será colocado.

(d) E será retirado e impresso; H será colocado.

(e) H será retirado e impresso; nenhum será colocado.

(f) C será retirado e impresso; G e F serão colocados.

(g) F será retirado e impresso; nenhum será colocado.

(h) G será retirado e impresso; nenhum será colocado e 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 dealturah é2h − 1.

Solução:

A raiz está na profundidade 0, seus filhos na profundidade 1, eassim pordiante. A altura da árvore é igual à maior profundidade de um nó na árvoremais 1.

O número máximo de nós ocorre quando todos os nós tem 2 filhos; nessecaso, o número de nós é:

h−1∑

i=0

2i =2h − 1

2− 1= 2h − 1.

93

Page 95: PMR 2300 - Computação para Automação

25. Em uma árvore binária, um nó com 2 filhos é ditocompleto. Demonstre queo número de nós completos mais um é igual ao número de folhas.

Solução:

Denote porC o número de nós completos e porF o número de folhas. Amaneira mais simples de demonstrar isso é por indução finita.Considereuma árvore com um único nó; nesse casoC = 0 e F = 1 (portanto aafirmaçãoC + 1 = F é verdadeira). Considere agora uma árvore qualquercomn nós e suponha queC + 1 = F vale para essa árvore. Suponha agoraque um nó seja adicionado a essa árvore. O pai desse nó tem que ter zero ouum 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 nemC nemF e portantoC + 1 = F porhipótese. Se o pai tem um filho, agora o pai ficou completo (portantoC foiincrementado) e o novo nó é uma folha nova (portantoF foi incrementado)e o resultado é queC + 1 = F .

26. Considere uma árvore binária de busca (ou seja, todo nó tem uma chavemaior 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 denós com chaves em ordem crescente. Suponha que uma árvore binária debusca seja implementada de forma que todo nó mantenha um valor inteirosizeOfSubtree, que armazena o número de nós na sub-árvore com raizno próprio nó. Por exemplo, se um nó tem dois filhos e esses filhos não temfilhos, entãosizeOfSubtree é igual a 3. A estrutura básica seria:

pub l i c c l a s s Spec ia lNode {i n t key ;Spec ia lNode 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étodokth na classeSpecialNode que encontra ok-ésimo elemento na sub-árvore com raiz no nó de chamada – ok-ésimo ele-mento alcançado em ordem interior. Ou seja, sen é umSpecialNode echamarmosn.kth(3), então o método deve retornar o conteúdo dekeyno terceiro nó (em ordem crescente) na sub-árvore cuja raiz én. Assumaque o usuário sempre chaman.kth(j) com um valor dej que é maior ouigual a 1 e menor ou igual ao número de nós na sub-árvore com raiz emn.

Discussão e solução:

Para encontrar a solução, imagine um nó A com dois filhos B e C. Suponhaque B tenhasizeOfSubtree igual an e C tenhasize OfSubtreeigual am. Ou seja, existemn nósantesde A na árvore que começa em A, em nósdepoisde A na árvore que começa em A. Ou seja, A é o(n+1)-ésimonó. Portanto se tivermosA.kth(j), temos três opções:

94

Page 96: PMR 2300 - Computação para Automação

(a) Sej = n+ 1, então A é o nó procurado.

(b) Sej < n+ 1, então oj-ésimo nó está na sub-árvore com raiz em B.

(c) Sej > n+ 1, então oj-ésimo nó está na sub-árvore com raiz em C.

Temos:

pub l i c c l a s s Spec ia lNode {i n t key ;Spec ia lNode 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 ;. . .

/ / Encont re k−esimo e lemento na ordem i n t e r i o r :i n t k th ( 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) )

re tu rn ( key ) ;i f ( j < ( n +1) )

re tu rn ( l e f t . k th ( j ) ) ;i f ( j > ( n +1) )

re tu rn ( r i g h t . k th ( j − ( n +1) ) ) ;re tu rn (−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 comp i la r ) .}

. . .}

Note que o problema assume quekth nunca é chamado com um valor menorque um ou maior que o número total de nós, portanto não é preciso verificaressas condições. Tente imaginar o que mudaria se essas condições tivessemque ser verificadas; seria preciso verificar o número de nós nofilho direitopara evitar “estouro”.

27. Dada a árvore abaixo, imprima os nós em ordem interior, ordem anterior, eordem posterior.

95

Page 97: PMR 2300 - Computação para Automação

1

2 3

4 5 6 7

15

8 9 10

12 13

11

16

18

14

17

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 classePilhaAr(ou seja, uma pilha implementada com arranjo). Temos um arranjo básicode armazenamento chamadoarranjo e um inteirotopo que indica o topoda pilha; setopo é igual a -1, a pilha está vazia. Codifique um métodoinsira(Object e, int i) que insere o objetoe na pilha na posiçãoi. O objetoe deve ser inserido apenas sei for maior ou igual a zero oumenor ou igual à posição do topo da pilha.

Solução:

Um possível método a ser inserido na classePilhaAr é:

pub l i c void i n s i r a ( Ob jec t e , i n t i ) {i f ( ( i <0) | | ( i > top ) ) / / Cond icoes em que nada ac on t e c e .

re tu rn ;/ / I n s e r e :topo ++;i f ( topo == a r r a n j o . l e n g t h )

doub leA r ray ( ) ; / / Metodo que d u p l i c a ar ran jo ,/ / v i s t o em aula .

f o r ( i n t j = topo ; 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 ;}

96

Page 98: PMR 2300 - Computação para Automação

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

RDOEM[]A(100)

EM[]A(58) RDO(42)

EM[](35) A(23) O(20)

E(18) M[](17)

RD(22)

M(9) [](8)

R(12) D(10)

Uma árvore obtida seguindo o algoritmo de Huffman é vista acima. Para essalinguagem, monte o código de Huffman. Codifique a palavra DEMORA nocódigo obtido. Usando o código obtido, qual seria o tamanho médio de umtexto com 100 caracteres?

A palavra DEMORA é codificada como 10100000101110001.

Se tivermos 100 caracteres, o valor esperado para o tamanho será: 43 carac-teres ocupando 2 bits, 40 caracteres ocupando 3 bits, e 17 caracteres ocu-pando 4 bits, perfazendo um total de43 × 2 + 40 × 3 + 17 × 4 = 274bits.

30. Suponha que uma árvore binária contém um caracter em cadanó. A ordeminterior de visita aos nós produz a sequência ABCEDFJGIH. A ordem an-terior de visita aos nós produz a sequência JCBADEFIGH. Desenhe umaárvore binária que produza essas ordens.

Discussão e solução:

Para resolver, note que a ordem anterior de uma árvore semprecomeça pelaraiz, enquanto que a ordem interior tem a sub-árvore “esquerda” antes daraiz, e a sub-árvore “direita” depois da raiz. Assim:

97

Page 99: PMR 2300 - Computação para Automação

J

C I

B D G H

A E F

Tente esquematizar um algoritmo (e codificar um método) que receba umaordem anterior e uma ordem interior, e gere uma árvore que produza essasordens.

31. Uma classe que implementa árvores binárias tem a seguinte definição:

pub l i c c l a s s NoArvoreB inar ia {p r i va t e i n t dado ;p r i va t e NoArvoreB inar ia esquerdo , d i r e i t o ;

pub l i c NoArvoreB ina r ia (i n t d ) {dado = d ;esquerdo = 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:

pub l i c i n t buscaPorN ive l (i n t d ) {/ / Retorna 1 se encon t rou 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 afunçãobuscaPorNivel.Qual é a complexidade da busca implementada no pior caso, para árvore con-tendoN nós, em notação BigOh?

Discussão:use uma estrutura de dados auxiliar; recursão direta na árvorenão resolve essa questão.

98

Page 100: PMR 2300 - Computação para Automação

32. Considere a árvore binária de busca abaixo, onde estão indicadas as chavesem 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 à suaesquerda (no caso, 9) e removemos esse elemento, ou substituímos 10 pelomenor elemento à sua direita (no caso, 30) e removemos esse elemento.

33. 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ço27 10 18 3 4 5 2 7 1 23

Obtenha o código de Huffman para esse texto. Codifique a mensagem “adi-ado o dia do xaxa” no código gerado. Se o texto original continha 10.000caracteres, qual o tamanho do texto em bits após a compressãousando ocódigo gerado?

34. Considere uma hashtable de encadeamento separado, na qual são inseridasárvores binárias de busca. Cada árvore contémN nós, e cada nó contémum dado. Suponha queN árvores foram inseridas na hashtable, e que todosos dados em uma determinada árvore sejam mapeados no mesmo elemento(bucket) da hashtable.

• Suponha primeiro que houve espalhamento perfeito, ou seja,cada po-siçã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, nopior caso, em notação BigOh?

99

Page 101: PMR 2300 - Computação para Automação

– Agora abandone a suposição que as árvores estão balanceadas.Qual é a complexidade de encontrar um dado nessa estrutura, nopior caso, em notação BigOh?

• Agora suponha que não houve espalhamento perfeito.

– Assuma que toda árvore inserida na hashtable está balanceada.Qual é a complexidade de encontrar um dado nessa estrutura, nopior 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, nopior caso, em notação BigOh?

35. Uma interface gráfica deve abrir uma janela com um botão. Oseguinte có-digo foi feito:

import j a va . awt .∗ ;import j a va . awt . e ve n t .∗ ;

pub l i c c l a s s I n t e r f a c e G r a f i c a {pub l i c s t a t i c void main ( S t r i n g a r gs [ ] ) {

Frame f = new Frame ( ) ;f . s e t S i z e ( 1 0 0 , 1 0 0 ) ;But ton b = new But ton ( " Aper te " ) ;f . add ( b ) ;f . show ( ) ;

}

pub l i c I n t e r f a c e G r a f i c a ( ) {}

}

É necessário processar oActionEvent gerado peloButton através dométodoactionPerformed. A ação a ser feita é simplesmente escrever“Aperte” na tela. Lembre-se que esse método deve estar presente na interfaceActionListener (a qual deve ser comunicada aoButton pelo métodoaddActionListener). Com essa informações, modifique o código paraprocessar o botão.

Considere que uma subclasse deButton deva ser criada, chamadaNewButton.Essa subclasse deve ser codificada de forma que, se oButton no códigoacima for substituído por umNewButton, toda a funcionalidade do pará-grafo anterior seja obtida sem nenhuma outra modificação. Explique comoa classeNewButton deve funcionar e codifique a classeNewButton.

100