Estrutura de dados
Upcoming SlideShare
Loading in...5
×
 

Estrutura de dados

on

  • 5,271 views

Acesse centenas de materiais e mais de 04 mil horas de cursos online gratuitos de TI no Portal GSTI: www.portalgsti.com.br.

Acesse centenas de materiais e mais de 04 mil horas de cursos online gratuitos de TI no Portal GSTI: www.portalgsti.com.br.

Statistics

Views

Total Views
5,271
Views on SlideShare
1,888
Embed Views
3,383

Actions

Likes
0
Downloads
55
Comments
0

7 Embeds 3,383

http://www.portalgsti.com.br 3322
http://feeds.feedburner.com 52
http://191612280685791701_19317d95a3f85ba36cff0bbfd1b451ec53699a91.blogspot.com 3
http://127.0.0.1 2
http://portalgstinovolayout.blogspot.com.br 2
http://direto.daer.rs.gov.br 1
http://3.bp.blogspot.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Estrutura de dados Estrutura de dados Document Transcript

    • Algoritmos e Estruturas de Dados IMarcos Castilho Fabiano Silva Daniel Weingaertner Vers˜o 0.7 a Maio de 2011
    • 2 Algoritmos e Estruturas de Dados I - Notas de Aula est´ licen- a ciado segundo a licen¸a da Creative Commons Atribui¸ao-Uso c c˜ N˜o-Comercial-Vedada a Cria¸˜o de Obras Derivadas 2.5 Bra- a ca sil License.http://creativecommons.org/licenses/by-nc-nd/ 2.5/br/ Algoritmos e Estruturas de Dados I - Notas de Aula is licen- sed under a Creative Commons Atribui¸ao-Uso N˜o-Comercial- c˜ a Vedada a Cria¸ao de Obras Derivadas 2.5 Brasil License.http: c˜ //creativecommons.org/licenses/by-nc-nd/2.5/br/ AVISO: Este texto ainda est´ em constru¸˜o. a ca
    • Sum´rio a1 Introdu¸˜o ca 72 Sobre problemas e solu¸˜es co 9 2.1 Contando o n´mero de presentes em um evento . . . . . . . . . . . . . 9 u 2.2 Trocando os quatro pneus . . . . . . . . . . . . . . . . . . . . . . . . . 12 2.3 Conclus˜o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 a3 Sobre algoritmos e programas 15 3.1 O que ´ um algoritmo? . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 e 3.2 O que ´ um programa? . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 e 3.3 Exerc´ ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 O modelo do computador 21 4.1 Hist´rico . . . . . . . . . . . . . . . . . . . . . . . . . . o . . . . . . . . . 21 4.2 Princ´ ıpios do modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 4.2.1 Endere¸os versus conte´dos . . . . . . . . . . . c u . . . . . . . . . 22 4.2.2 O repert´rio de instru¸oes . . . . . . . . . . . . o c˜ . . . . . . . . . 23 4.2.3 O ciclo de execu¸˜o de instru¸oes . . . . . . . . ca c˜ . . . . . . . . . 25 4.2.4 Exemplo de execu¸ao de um programa . . . . . c˜ . . . . . . . . . 25 4.3 Humanos versus computadores . . . . . . . . . . . . . . . . . . . . . . . 26 4.3.1 Abstra¸˜o dos endere¸os . . . . . . . . . . . . . ca c . . . . . . . . . 27 4.3.2 Abstra¸˜o dos c´digos das instru¸oes . . . . . . ca o c˜ . . . . . . . . . 28 4.3.3 Abstra¸˜o do repert´rio de instru¸˜es . . . . . . ca o co . . . . . . . . . 29 4.3.4 Abstra¸˜o dos endere¸os de mem´ria (vari´veis) ca c o a . . . . . . . . . 30 4.4 Abstra¸ao das instru¸˜es (linguagem) . . . . . . . . . . c˜ co . . . . . . . . . 31 4.5 Conclus˜o . . . . . . . . . . . . . . . . . . . . . . . . . a . . . . . . . . . 33 4.6 Exerc´ ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 Conceitos elementares 37 5.1 Algoritmos e linguagens de programa¸ao . . . . . . c˜ . . . . . . . . . . . 37 5.2 C´lculo de ra´ de uma equa¸ao do segundo grau a ızes c˜ . . . . . . . . . . . 38 5.3 Imprimir a soma de dois n´meros dados . . . . . . u . . . . . . . . . . . 39 5.4 Imprimindo sequˆncias de n´meros na tela . . . . . e u . . . . . . . . . . . 40 5.5 Imprimir os quadrados de uma faixa de n´meros . . u . . . . . . . . . . . 44 5.6 Imprimindo a soma de v´rios pares de n´meros . . a u . . . . . . . . . . . 44 3
    • 4 ´ SUMARIO 5.7 Testar se um n´mero lido ´ positivo u e . . . . . . . . . . . . . . . . . . . . 45 5.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 5.9 Apˆndice . . . . . . . . . . . . . . . e . . . . . . . . . . . . . . . . . . . . 47 5.10 Exerc´ ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 496 T´cnicas elementares e 55 6.1 Atribui¸˜es dentro de repeti¸˜es . . . . . . co co . . . . . . . . . . . . . . . . 55 6.1.1 Somando n´meros . . . . . . . . . u . . . . . . . . . . . . . . . . 55 6.2 Desvios condicionais aninhados . . . . . . . . . . . . . . . . . . . . . . 57 6.2.1 O menor de trˆs . . . . . . . . . . . e . . . . . . . . . . . . . . . . 58 6.3 Desvios condicionais dentro de repeti¸oes . c˜ . . . . . . . . . . . . . . . . 58 6.3.1 Imprimir apenas n´meros positivos u . . . . . . . . . . . . . . . . 58 6.3.2 Somando pares e ´ ımpares . . . . . . . . . . . . . . . . . . . . . . 61 6.3.3 Convertendo para bin´rio . . . . . a . . . . . . . . . . . . . . . . 62 6.3.4 Menor de 3, segunda vers˜o . . . . a . . . . . . . . . . . . . . . . 64 6.4 Repeti¸oes dentro de condi¸oes . . . . . . c˜ c˜ . . . . . . . . . . . . . . . . 65 6.4.1 Calculo do MDC . . . . . . . . . . . . . . . . . . . . . . . . . . 65 6.5 Repeti¸oes aninhadas . . . . . . . . . . . . c˜ . . . . . . . . . . . . . . . . 66 6.5.1 Tabuada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 6.5.2 Fatorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 6.6 Exerc´ ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 707 Aplica¸˜es das t´cnicas elementares co e 75 7.1 N´meros de Fibonacci . . . . . . . u . . . . . . . . . . . . . . . . . . . . 75 7.2 Maior segmento crescente . . . . . . . . . . . . . . . . . . . . . . . . . 77 7.3 S´ries . . . . . . . . . . . . . . . . . e . . . . . . . . . . . . . . . . . . . . 79 7.3.1 N´mero neperiano . . . . . u . . . . . . . . . . . . . . . . . . . . 79 7.3.2 C´lculo do seno . . . . . . . a . . . . . . . . . . . . . . . . . . . . 80 7.4 N´meros primos . . . . . . . . . . . u . . . . . . . . . . . . . . . . . . . . 83 7.5 Exerc´ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 868 Refinamentos sucessivos 91 8.1 Primos entre si . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 8.2 Amigos quadr´ticos . . . . . . . . . a . . . . . . . . . . . . . . . . . . . . 93 8.3 Pal´ındromos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 8.4 Inverter um n´mero de trˆs d´ u e ıgitos . . . . . . . . . . . . . . . . . . . . 99 8.5 C´lculo do MDC pela defini¸˜o . . a ca . . . . . . . . . . . . . . . . . . . . 101 8.6 Exerc´ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1049 Fun¸˜es e procedimentos co 107 9.1 Motiva¸˜o . . . . . . . . . . . . . . ca . . . . . . . . . . . . . . . . . . . . 107 9.1.1 Modularidade . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 9.1.2 Reaproveitamento de c´digo o . . . . . . . . . . . . . . . . . . . . 108 9.1.3 Legibilidade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 9.1.4 Coment´rio adicional . . . . a . . . . . . . . . . . . . . . . . . . . 109 9.2 No¸oes fundamentais . . . . . . . . c˜ . . . . . . . . . . . . . . . . . . . . 109
    • ´SUMARIO 5 9.2.1 Exemplo b´sico . . . . . . . . . . . . . . . . . . a . . . . . . . . . 109 9.2.2 O programa principal . . . . . . . . . . . . . . . . . . . . . . . . 109 9.2.3 Vari´veis globais . . . . . . . . . . . . . . . . . a . . . . . . . . . 110 9.2.4 Fun¸oes . . . . . . . . . . . . . . . . . . . . . . c˜ . . . . . . . . . 110 9.2.5 Parˆmetros por valor . . . . . . . . . . . . . . . a . . . . . . . . . 112 9.2.6 Parˆmetros por referˆncia . . . . . . . . . . . . a e . . . . . . . . . 113 9.2.7 Procedimentos . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 9.2.8 Vari´veis locais . . . . . . . . . . . . . . . . . . a . . . . . . . . . 115 9.3 Alguns exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 9.3.1 Calculando d´ ıgito verificador . . . . . . . . . . . . . . . . . . . . 116 9.4 C´lculo do MDC pela defini¸˜o . . . . . . . . . . . . . a ca . . . . . . . . . 119 9.4.1 Calculando ra´ de equa¸˜es do segundo grau ızes co . . . . . . . . . 121 9.5 Exerc´ ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12410 Estruturas de dados 125 10.1 Vetores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 10.1.1 Primeiros problemas com vetores . . . . . . . . . . . . . . . . . 128 10.1.2 Soma e produto escalar de vetores . . . . . . . . . . . . . . . . . 136 10.1.3 Busca em vetores . . . . . . . . . . . . . . . . . . . . . . . . . . 138 10.1.4 Ordena¸ao em vetores . . . . . . . . c˜ . . . . . . . . . . . . . . . 148 10.1.5 Outros algoritmos com vetores . . . . . . . . . . . . . . . . . . . 152 10.1.6 Exerc´ ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 10.2 Matrizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 10.2.1 Matrizes em Pascal . . . . . . . . . . . . . . . . . . . . . . . . . 179 10.2.2 Exemplos elementares . . . . . . . . . . . . . . . . . . . . . . . 180 10.2.3 Procurando elementos em matrizes . . . . . . . . . . . . . . . . 186 10.2.4 Inserindo uma coluna em uma matriz . . . . . . . . . . . . . . . 188 10.2.5 Aplica¸oes de matrizes em imagens . c˜ . . . . . . . . . . . . . . . 190 10.2.6 Exerc´ ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 10.3 Registros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 10.3.1 Introdu¸ao aos registros . . . . . . . c˜ . . . . . . . . . . . . . . . 209 10.3.2 Vetores de registros . . . . . . . . . . . . . . . . . . . . . . . . . 210 10.3.3 Registros com vetores . . . . . . . . . . . . . . . . . . . . . . . . 212 10.3.4 Observa¸˜es importantes . . . . . . . co . . . . . . . . . . . . . . . 213 10.3.5 Exerc´ ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21611 Desenvolvendo programas de maior porte 225 11.0.1 Campo minado . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 11.1 Exerc´ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23412 Tipos abstratos de dados 241 12.1 Tipo Conjunto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 12.2 Tipo Lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 12.2.1 Exerc´ıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
    • 6 ´ SUMARIO
    • Cap´ ıtulo 1Introdu¸˜o caEste material cont´m notas de aulas da disciplina CI055 – Algoritmos e Estruturas de eDados I, ministrada para os curso de Bacharelado em Ciˆncia da Computa¸ao (BCC), e c˜Matem´tica Industrial (MatInd) e para o Bacharelado em Inform´tica Biom´dica a a e(BIB) da Universidade Federal do Paran´. a Esta disciplina ´ ministrada no primeiro semestre (para os calouros) e ´ a primeira e edas quatro que cobrem o conte´do b´sico de algoritmos sem o qual um curso de u acomputa¸ao n˜o faz sentido. As disciplinas subsequentes s˜o: c˜ a a • Algoritmos e Estruturas de Dados II; • Algoritmos e Estruturas de Dados III; e • Algoritmos e Teoria dos Grafos. A orienta¸˜o da Coordena¸ao dos cursos ´ que este deve ter um conte´do forte ca c˜ e uem conceitos de algoritmos no qual a implementa¸ao final em uma linguagem de pro- c˜grama¸ao ´ vista apenas como um mecanismo facilitador ao aprendizado dos conceitos c˜ ete´ricos. o O texto est´ dividido em duas partes bem definidas, a primeira entre os cap´ a ıtulos 2e 9, cont´m os princ´ e ıpios b´sicos da constru¸˜o de algoritmos elementares, incluindo a caa parte de subprogramas, com especial aten¸˜o a quest˜es tais como passagem de ca oparˆmetros e vari´veis locais e globais. A no¸˜o de modularidade ´ bastante explorada. a a ca e A segunda parte, a partir do cap´ ıtulo 10, cont´m princ´ e ıpios de estruturas de dadosb´sicas, onde se introduz a no¸ao de vetores unidimensionais, a primeira das estruturas a c˜de dados. Nesta estrutura, praticamos a elabora¸˜o de algoritmos modulares e j´ n˜o ca a aescrevemos um c´digo inteiro, mas sim um conjunto de fun¸oes e procedimentos que, o c˜em uma abordagem por refinamentos sucessivos (top down), s˜o constru´ a ıdos passo apasso. Alguns algoritmos importantes s˜o estudados em suas vers˜es b´sicas: busca e a o aordena¸ao de vetores. No¸˜es de complexidade de algoritmos s˜o mencionadas, ainda c˜ co aque de modo informal, pois isto ´ conte´do de per´ e u ıodos mais avan¸ados. Contudo, ´ c eimportante ao aprendiz ter no¸ao clara da diferen¸a de custo entre diferentes algorit- c˜ cmos. 7
    • 8 CAP´ ¸˜ ITULO 1. INTRODUCAO As ultimas estruturas de dados relevantes para o primeiro per´ ´ ıodo s˜o as matrizes ae o conceito de registro. Havendo tempo, tamb´m se discute estruturas um pouco emais sofisticadas, misturando-se vetores, registros e matrizes. Finalmente se oferece um desafio aos alunos. O objetivo ´ o de mostrar uma eaplica¸ao interessante dos conceitos que eles j´ dominam. Normalmente trabalha-se c˜ aem sala de aula o desenvolvimento de um programa que tem sido a constru¸ao de um c˜jogo simples que pode ser implementado em uma estrutura de matriz, eventualmentecom registros. A ideia ´ que eles possam fazer um programa mais extenso para etreinarem a constru¸ao de programas modulares. Este material constitui o ultimo c˜ ´cap´ıtulo deste material. O estudante n˜o deve iniciar uma parte sem antes ter compreendido o conte´do a udas anteriores. Tamb´m n˜o deve iniciar um novo cap´ e a ıtulo sem ter compreendido osanteriores. Sobre a linguagem, o estudante ´ encorajado a buscar apoio na literatura e nos eguias de referˆncia dispon´ e ıveis para o compilador escolhido (Free Pascal ), incluindoum guia de referˆncia b´sico que foi escrito pelos monitores da disciplina no ano de e a2009. A leitura destas notas de aula n˜o isenta o estudante de buscar literatura comple- amentar, sempre bem-vinda. Em particular, uma ´tima hist´ria da computa¸ao pode o o c˜ser encontrada em [Tre83]. Alguns excelentes textos introdut´rios em algoritmos est˜o o aem [Car82], [Sal98], [Med05] e [Wir78]. Para mais detalhes de programa¸˜o em Pascal cao leitor pode consultar [Far99] e tamb´m os guias de referˆncia da linguagem [Gui]. e eFinalmente, embora talvez de dif´ compreens˜o para um iniciante, recomendamos ıcil apelo menos folhear o material em [Knu68].
    • Cap´ ıtulo 2Sobre problemas e solu¸oes c˜Vamos iniciar nosso estudo com uma breve discuss˜o sobre problemas e solu¸˜es. O a coobjetivo ´ deixar claro desde o in´ que: e ıcio • n˜o existe, em geral, uma unica solu¸˜o para o mesmo problema; a ´ ca • algumas solu¸oes s˜o melhores do que outras, sob algum crit´rio; c˜ a e • alguns problemas s˜o casos particulares de outros similares; a • as vezes, ´ melhor resolver o problema mais gen´rico, assim, resolve-se uma e e classe de problemas, e n˜o apenas um. a Ser˜o apresentados dois problemas reais e para cada um deles segue uma discuss˜o a asobre a existˆncia de diversas solu¸oes para um dado problema. A ˆnfase ser´ dada e c˜ e anas diferen¸as entre as solu¸˜es e tamb´m na discuss˜o sobre at´ que ponto deve-se c co e a eficar satisfeito com a primeira solu¸ao obtida ou se ela pode ser generalizada para c˜problemas similares.2.1 Contando o n´ mero de presentes em um evento uNo primeiro dia letivo do primeiro semestre de 2009, um dos autores deste materialcolocou o seguinte problema aos novos alunos: quer´ ıamos saber quantos estudantesestavam presentes na sala de aula naquele momento. A sala tinha capacidade aproxi-mada de 100 lugares e a naquele momento estava razoavelmente cheia. Os estudantes discutiram v´rias possibilidades. Apresentamos todas elas a seguir. aPrimeira solu¸˜o caA primeira solu¸ao parecia t˜o obvia que levou algum tempo at´ algum aluno verbali- c˜ a ´ ezar: o professor conta os alunos um por um, tomando o cuidado de n˜o contar algu´m a eduas vezes e tamb´m de n˜o esquecer de contar algu´m. e a e Quais s˜o as vantagens deste m´todo? Trata-se de uma solu¸ao simples, f´cil de a e c˜ a ´ uma solu¸ao perfeita para salas de aula comexecutar e produz o resultado correto. E c˜ 9
    • 10 CAP´ ¸˜ ITULO 2. SOBRE PROBLEMAS E SOLUCOESpoucos alunos, digamos, 20 ou 30. Outro aspecto considerado foi o fato de que estem´todo n˜o exige nenhum conhecimento pr´vio de quem vai executar a opera¸˜o, a e a e can˜o ser saber contar. Tamb´m n˜o exige nenhum equipamento adicional. a e a Quais as desvantagens? Se o n´mero de alunos na sala for grande, o tempo ne- ucess´rio para o t´rmino da opera¸ao pode ser insatisfat´rio. Para piorar, quanto a e c˜ omaior o n´mero, maior a chance de aparecerem erros na contagem. Foi discutida a uadequa¸ao desta solu¸˜o para se contar os presentes em um com´ ou manifesta¸ao c˜ ca ıcio c˜popular numa pra¸a p´blica. Concluiu-se pela inviabilidade do m´todo nestes casos. c u e Executamos a contagem em aproximadamente 1 minuto. Dois alunos tamb´m efizeram a contagem e, ap´s conferˆncia, obtivemos o resultado correto, que serviu o epara an´lise das outras solu¸˜es. a coSegunda solu¸˜o caPensando no problema de se contar na ordem de 100 alunos, um estudante sugeriuque se fizesse apenas a contagem das carteiras vazias e em seguida uma subtra¸ao com c˜rela¸ao ao n´mero total de carteiras na sala. c˜ u A solu¸˜o tamb´m ´ muito simples e funciona perfeitamente bem, mas exige um ca e econhecimento pr´vio: deve-se saber antecipadamente o total de carteiras na sala. e Esta maneira de contar ´ cada vez melhor quanto maior for o n´mero de presentes, e upois o n´mero de carteiras vazias ´ menor do que o das ocupadas. Por outro lado, se u ea sala estiver com pouca gente, o m´todo anterior ´ mais eficiente. e e Os alunos observaram tamb´m que a solu¸ao n˜o se aplica para os casos de con- e c˜ atagem de presentes a um com´ numa pra¸a p´blica, pois n˜o h´ carteiras na rua. ıcio c u a aTerceira solu¸˜o caPara resolver o problema do com´ ıcio, outro estudante sugeriu que se fizesse umaestimativa baseada na metragem total da pra¸a, multiplicada pelo n´mero estimado c ude pessoas por metro quadrado. Solu¸ao elegante, na pr´tica ´ o que a organiza¸˜o do com´ e a pol´ usam. c˜ a e ca ıcio ıciaMas deve-se saber de antem˜o a metragem da pra¸a e estimar a taxa de pessoas por a cmetro quadrado. O m´todo ´ t˜o bom quanto melhor for a estimativa. Tamb´m ´ e e a e emelhor se a popula¸ao estiver uniformemente distribu´ c˜ ıda. Concluiu-se que ´ um bom m´todo, mas que n˜o ´ preciso. Isto ´, a chance e e a e edo n´mero estimado ser exatamente o n´mero de presentes ´ baixa. Os m´todos u u e eanteriores s˜o exatos, isto ´, nos d˜o o n´mero correto de presentes. Este m´todo a e a u etamb´m serve razoavelmente bem para o n´mero de alunos na sala de aula. De fato, e unesta aula, o professor conseguiu o n´mero com aproxima¸ao 80% correta. A quest˜o u c˜ aque restou ´ se o erro de 20% ´ aceit´vel ou n˜o. Isto depende do motivo pelo qual e e a ase quer contar os alunos na sala.Quarta solu¸˜o caPara resolver o problema da precis˜o, outro estudante sugeriu o uso de roletas. a
    • ´2.1. CONTANDO O NUMERO DE PRESENTES EM UM EVENTO 11 Efetivamente ´ esta a solu¸ao para contar torcedores no est´dio ou presentes em e c˜ aum show de rock. Mas tamb´m foi considerado que a solu¸˜o exige uma ou mais e cacatracas, uma barreira para ningu´m entrar sem passar pela roleta e etc, para se egarantir a exatid˜o do resultado. No caso do com´ n˜o seria vi´vel. No caso da a ıcio a asala de aula foi constatado que n˜o havia roletas e portanto o m´todo n˜o se aplicava. a e aQuinta solu¸˜o caMais uma vez outro estudante apresentou uma boa alternativa: contar o n´mero de ufilas de carteiras e, dado que todas tenham o mesmo n´mero de estudantes, ent˜o u abastaria uma simples multiplica¸˜o para a determina¸˜o do n´mero correto. ca ca u De fato esta solu¸˜o funciona perfeitamente bem em lugares como por exemplo o caex´rcito. As filas s˜o rapidamente arrumadas com, digamos, 10 soldados em cada fila, e asabendo-se o n´mero de filas basta multiplicar por 10, eventualmente tendo-se que ucontar o n´mero de pessoas em uma fila que n˜o tenha completado 10. u a Infelizmente as carteiras estavam bagun¸adas na nossa sala e este c´lculo n˜o pode c a aser feito. Tamb´m ficaria estranho o professor colocar todos os alunos em filas. Foi etamb´m observado que o m´todo fornece a solu¸ao exata para o problema. e e c˜Sexta solu¸˜o caNova sugest˜o de outro aluno: cada estudante no in´ de cada fila conta o n´mero de a ıcio ualunos da sua fila, tomando o cuidado de contar a si pr´prio tamb´m. Depois soma-se o etodas as contagens de todos os primeiros de fila. Solu¸ao muito boa. Na verdade ´ a vers˜o em paralelo da primeira solu¸˜o. c˜ e a caDistribuindo-se a tarefa, cada primeiro de fila tem entre 10 e 15 alunos para con-tar em sua fila. Se a soma foi correta o n´mero obtido ao final do processo ´ exato. u eNo caso daquela aula os estudantes realizaram a opera¸˜o em poucos segundos, mais caalgum tempo para as somas (isto demorou mais. . . ). Mas o resultado foi exato. A solu¸ao n˜o exige conhecimento pr´vio, n˜o exige equipamento adicional e ´ c˜ a e a erazoavelmente escal´vel, isto ´, funciona para salas de tamanhos diferentes. a eS´tima solu¸˜o e caPara finalizar, o professor apresentou a solu¸ao seguinte: todos os estudantes se le- c˜vantam e se atribuem o n´mero 1. Em seguida os alunos se organizam em pares. Em ucada par, primeiro ´ somado o n´mero de cada um dos dois, um deles guarda este e un´mero e permanece de p´, o outro deve se sentar. Os que ficaram em p´ repetem u e eeste processo at´ que s´ exista um unico aluno em p´. Ele tem o n´mero exato de e o ´ e uestudantes na sala. Como se divide a sala em pares, ap´s a primeira rodada metade da sala deve ter oo n´mero 2 e a outra metade est´ sentada, considerando que a sala tem o n´mero de u a ualunos par. Se for ´ ımpar um deles ter´ ainda o n´mero 1. Ap´s a segunda rodada um a u oquarto dos alunos dever´ ter o n´mero 4 e trˆs quartos estar˜o sentados, eventualmente a u e aum deles ter´ um n´mero ´ a u ´ f´cil perceber que o resultado sai em tempo ımpar. E a
    • 12 CAP´ ¸˜ ITULO 2. SOBRE PROBLEMAS E SOLUCOESproporcional ao logaritmo do n´mero total de alunos, o que ´ bem r´pido. De fato, u e apara mil pessoas o processo termina em 10 passos e para um milh˜o de pessoas termina aem 20 passos. Parece um bom algoritmo, ele d´ resultado exato, n˜o exige conhecimento pr´vio, a a e´ escal´vel, isto ´, funciona muito bem para um grande n´mero de pessoas, mas exigee a e uorganiza¸ao dos presentes. c˜ Infelizmente aquela turma n˜o se organizou direito e o resultado veio com um erro ade 40%. . . Mas ap´s duas rodadas de treinamento, na terceira conseguimos obter o oresultado correto.2.2 Trocando os quatro pneusTodo mundo sabe trocar pneus, embora n˜o goste. O processo que um cidad˜o comum a aexecuta ´ muito simples: levanta o carro com o macaco, tira todos os quatro parafusos eda roda com o pneu furado, tira a roda do eixo, coloca a roda com o pneu novo noeixo, em seguida aperta os quatro parafusos. Finalmente, baixa o carro e est´ pronto. a Nos anos 1980, um famoso piloto de f´rmula 1 imaginou que poderia ser campe˜o o ado mundo se pudesse usar um composto de pneu mais mole e com isto ganhar preciosossegundos com rela¸ao aos seus concorrentes. O problema ´ que estes compostos mais c˜ emoles se deterioram rapidamente exigindo a troca dos quatro pneus no meio da corrida.O tal piloto, ap´s alguns c´lculos, concluiu que se levasse menos de 8 segundos para o atrocar os quatro pneus, valeria a pena aplicar este m´todo. e Obviamente a solu¸˜o caseira n˜o serve. O m´todo descrito acima custa em geral ca a e20 minutos por pneu, com um pouco de pr´tica 10 minutos. Com muita pr´tica 2 ou a a3 minutos. Para trocar os quatro pneus, 8 a 12 minutos. Da´ o problema: Como trocar os quatro pneus de um carro em menos de 8 segun- ıdos? Um dos grandes custos de tempo ´ ter que trocar o macaco para cada roda: usamos eum macaco hidr´ulico, destes de loja de pneus, e levantamos o carro todo de uma s´ a ovez. Mas, para cada roda, temos 4 parafusos, isto ´, 16 no total, ou melhor, 32, pois etem que tirar e depois recolocar: usa-se uma aparafusadeira el´trica para amenizar o eproblema, mas ainda n˜o ´ suficiente. a e Se a roda tiver um unico parafuso a economia de tempo ´ maior ainda. Mas ´ eainda estamos na casa dos minutos, e o tempo total deve ser menor que 8 segundos.Desistimos do campeonato? Com 4 pessoas, cada uma troca uma roda, divide-se o tempo por 4. Opa! J´ aestamos abaixo de 1 minuto. Se tiver ainda a possibilidade de 3 pessoas por roda: um tira o parafuso, outro tiraa roda velha, um terceiro coloca a roda nova e o primeiro aperta o parafuso. Mais 2mecˆnicos para levantar e baixar o carro todo de uma vez e est´ feito. a a Hoje em dia se trocam os quatro pneus de um carro de f´rmula 1, com direito a ocompletar o tanque de gasolina, em cerca de 6 segundos. Ah, o tal piloto foi campe˜o naquele ano, pois tamb´m usou o truque de aquecer a e
    • ˜2.3. CONCLUSAO 13os pneus antes da prova e andar com o carro contendo metade da gasolina, j´ que ele aia ter que parar nos boxes de qualquer maneira para trocar os pneus. . . O cara ´ um egˆnio. e2.3 Conclus˜o aMesmo para um problema simples existem diversas solu¸˜es. A escolha da melhor codepende de v´rios fatores. Por exemplo, se a resposta deve ser exata ou n˜o ou se os a aconhecimentos pr´vios necess´rios est˜o dispon´ e a a ıveis, e assim por diante. ´ E importante notar que somente ap´s uma s´rie de considera¸oes ´ poss´ escolher o e c˜ e ıvela melhor t´cnica e somente em seguida executar a tarefa. e Algumas solu¸˜es existem a no¸˜o de paralelismo. Hoje em dia os computadores co cavˆm com v´rios n´cleos de processamento e sempre existe a chance de se tentar quebrar e a uum problema em v´rios outros menores e deixar que v´rios processadores resolvam a aseus peda¸os de solu¸ao e depois tentar juntar os resultados com mais alguma opera¸˜o c c˜ casimples. No caso da f´rmula 1 isto funcionou, mas em geral n˜o ´ verdade. Infelizmente o a eexiste o problema da dependˆncia de dados. Por exemplo, o mecˆnico que vai colocar e aa roda nova s´ pode trabalhar depois que o outro tirou a roda velha. Em problemas ocom alto grau de dependˆncia, paralelizar ´ complicado.1 . e e 1 N˜o se estudar˜o algoritmos paralelos nesta disciplina. a a
    • 14 CAP´ ¸˜ ITULO 2. SOBRE PROBLEMAS E SOLUCOES
    • Cap´ ıtulo 3Sobre algoritmos e programasAp´s o estudo do problema, an´lise das diversas possibilidades de solu¸ao e a escolha o a c˜da melhor delas, cabe agora a tarefa de escrever um programa que implemente estasolu¸ao. Antes, contudo, ´ preciso saber a diferen¸a entre um algoritmo em um c˜ e cprograma. Isto ser´ discutido neste cap´ a ıtulo.3.1 O que ´ um algoritmo? eUm algoritmo ´ uma sequˆncia extremamente precisa de instru¸oes que, quando lida e e c˜e executada por uma outra pessoa, produz o resultado esperado, isto ´, a solu¸ao de e c˜um problema. Esta sequˆncia de instru¸oes ´ nada mais nada menos que um registro e c˜ eescrito da sequˆncia de passos necess´rios que devem ser executados para manipular e ainforma¸oes, ou dados, para se chegar na resposta do problema. c˜ Isto serve por dois motivos: o primeiro ´ que atrav´s do registro se garante que e en˜o haver´ necessidade de se redescobrir a solu¸ao quando muito tempo tiver passado a a c˜e todos tiverem esquecido do problema; o outro motivo ´ que, as vezes, queremos eque outra pessoa execute a solu¸ao, mas atrav´s de instru¸˜es precisas, de maneira c˜ e coque n˜o haja erros durante o processo. Queremos um algoritmo para a solu¸ao do a c˜problema. Uma receita de bolo de chocolate ´ um bom exemplo de um algoritmo (a lista de eingredientes e as quantidades foram omitidas, bem como a receita da cobertura):Bata em uma batedeira a manteiga e o a¸ucar. Junte as gemas uma a uma c´at´ obter um creme homog^neo. Adicione o leite aos poucos. Desligue a e ebatedeira e adicione a farinha de trigo, o chocolate em p´, o fermento oe reserve. Bata as claras em neve e junte-as a massa de chocolate `misturando delicadamente. Unte uma forma retangular pequenacom manteiga e farinha e leve para assar em forno m´dio pr´-aquecido e epor aproximadamente 30 minutos. Desenforme o bolo aindaquente e reserve. Este ´ um bom exemplo de algoritmo pois podemos extrair caracter´ e ısticas bastanteinteressantes do texto. Em primeiro lugar, a pessoa que escreveu a receita n˜o ´a e 15
    • 16 CAP´ ITULO 3. SOBRE ALGORITMOS E PROGRAMASnecessariamente a mesma pessoa que vai fazer o bolo. Logo, podemos estabelecer,sem preju´ que foi escrita por um mas ser´ executada por outro. ızo, a Outras caracter´ ısticas interessantes que est˜o impl´ a ıcitas s˜o as seguintes: a • as frases s˜o instru¸oes no modo imperativo: bata isso, unte aquilo. S˜o ordens, a c˜ a n˜o sugest˜es. Quem segue uma receita obedece quem a escreveu; a o • as instru¸oes est˜o na forma sequencial: apenas uma pessoa executa. N˜o exis- c˜ a a tem a¸oes simultˆneas. c˜ a • existe uma ordem para se executar as instru¸˜es: primeiro bata a manteiga e co o a¸ucar; depois junte as gemas, uma a uma, at´ acabar os ovos; em seguida c e adicione o leite. • algumas instru¸oes n˜o s˜o executadas imediatamente, ´ preciso entrar em um c˜ a a e modo de repeti¸ao de um conjunto de outras instru¸˜es: enquanto houver ovos c˜ co n˜o usados, junte mais uma gema. S´ pare quando tiver usado todos os ovos. a o • algumas outras instru¸oes n˜o foram mencionadas, mas s˜o obviamente ne- c˜ a a cess´rias que ocorram: ´ preciso separar as gemas das claras antes de come¸ar a e c a tarefa de se fazer o bolo, assim como ´ preciso ainda antes quebrar os ovos. e • algumas instru¸oes, ou conjunto de instru¸oes, podem ter a ordem invertida: c˜ c˜ pode-se fazer primeiro a massa e depois a cobertura, ou vice-e-versa. Mas nunca se pode colocar no forno a assadeira antes de se chegar ao t´rmino do preparo e da massa. Mesmo levando estas coisas em considera¸ao, qualquer ser humano bem treinado c˜em cozinha conseguiria fazer um bolo de chocolate razo´vel com as instru¸˜es acima, a copois todas as receitas seguem o mesmo padr˜o. As conven¸˜es que est˜o impl´ a co a ıcitasno algoritmo s˜o conhecidas de qualquer cozinheiro, pois seguem um formato padr˜o. a a O formato padr˜o para algoritmos que vamos considerar ´ o seguinte: a e • as instru¸˜es ser˜o escritas uma em cada linha; co a • as instru¸oes ser˜o executadas uma a uma, da primeira at´ a ultima linha, c˜ a e ´ nesta ordem, a menos que o pr´prio algoritmo tenha instru¸˜es que alterem este o co comportamento; • em cada linha, uma instru¸ao faz somente uma coisa; c˜ • tudo o que est´ impl´ a ıcito dever´ ser explicitado. a A figura 3.1 ilustra a receita de bolo de chocolate escrita dentro deste formatopadr˜o. a
    • ´3.1. O QUE E UM ALGORITMO? 17Algoritmo para fazer um bolo de chocolate.in´cio ı Providencie todos os ingredientes da receita. Providencie uma forma pequena. Ligue o forno em temperatura m´dia. e Coloque a menteiga na batedeira. Coloque o a¸ucar na batedeira. c Ligue a batedeira. Enquanto um creme homog^neo n~o for obtido, junte mais uma gema. e a Adicione aos poucos o leite. Desligue a batedeira. Adicione a farinha de trigo. Adicione o chocolate em p´. o Adicione o fermento. Reserve a massa obtida em um lugar tempor´rio. a Execute o algoritmo para obter as claras em neve. Junte as claras em neve a massa de chocolate que estava reservada. ` Misture esta massa delicadamente. Execute o algoritmo para untar a forma com manteiga e farinha. Coloque a forma no forno. Espere 30 minutos. Tire a forma do forno. Desenforme o bolo ainda quente. Separe o bolo em um lugar tempor´rio. a Fa¸a a cobertura segundo o algoritmo de fazer cobertura. c Coloque a cobertura no bolo.fim. Figura 3.1: Algoritmo para fazer bolo de chocolate. Infelizmente, nem todos conseguem fazer o bolo, pois existem instru¸˜es que so- comente os iniciados decifram: • “adicione aos poucos”; • “misturando delicadamente”; • “quando o creme fica homogˆneo?”. . . e No caso do computador a situa¸ao ´ pior ainda, pois trata-se de um circuito c˜ eeletrˆnico, de uma m´quina. Por este motivo, as instru¸oes devem ser precisas e o a c˜organizadas. Um algoritmo feito para um computador executar deve tornar expl´ ıcito todas asinforma¸oes impl´ c˜ ıcitas. Tamb´m deve evitar o uso de frases amb´ e ıguas ou imprecisase deve ser o mais detalhado poss´ıvel. Tamb´m n˜o pode ter frases de significado e adesconhecido. Na pr´xima se¸ao vamos desenvolver melhor este tema. o c˜
    • 18 CAP´ ITULO 3. SOBRE ALGORITMOS E PROGRAMAS3.2 O que ´ um programa? eUm programa ´ a codifica¸ao em alguma linguagem formal que garanta que os pas- e c˜sos do algoritmo sejam executados da maneira como se espera por quem executa asinstru¸oes. c˜ Vamos imaginar, a t´ıtulo de ilustra¸ao, que ´ a primeira vez que a pessoa entra na c˜ ecozinha em toda a sua vida e resolve fazer um bolo de chocolate seguindo o algorimo 3.1 O algoritmo 3.1 foi escrito por um cozinheiro para ser executado por um outrocozinheiro, o que n˜o ´ o caso, pois a pessoa ´ inexperiente em cozinha e n˜o sabe o a e e aque significa “bater as claras em neve”. Significa que o novato vai ficar sem o bolo. O novato precisaria de algo mais detalhado, isto ´, de instru¸˜es meticulosas de e cocomo se obt´m claras em neve. Poderia ser algo como ilustrado na figura 3.2. eAlgoritmo para fazer claras em nevein´cio ı Repita os tr^s seguintes passos: e Pegue um ovo. Quebre o ovo. Separe a clara da gema. Coloque somente a clara em um prato fundo. At´ que todos os ovos tenham sido utilizados. e Pegue um garfo. Mergulhe a ponta do garfo no prato. Repita os seguinteis passos: Bata a clara com o garfo por um tempo. Levante o garfo. Observe se a espuma produzida fica presa no garfo Quando a espuma ficar presa no garfo, pare. Neste ponto suas claras em neve est~o prontas. afim. Figura 3.2: Algoritmo para fazer claras em neve. J´ temos algo mais detalhado, mas nosso inexperiente cozinheiro pode ainda ter aproblemas: como se separa a clara da gema? Este tipo de situa¸ao parece n˜o ter fim. c˜ aQual ´ o limite do processo de detalhamento da solu¸ao? e c˜ O problema ´ que o cozinheiro que escreveu a receita original n˜o sabia o n´ de e a ıvelinstru¸ao de quem ia efetivamente fazer o bolo. Para isto, ´ preciso que se estabele¸a c˜ e co n´ m´ ıvel ınimo de conhecimento para quem vai executar, assim quem escreve sabe at´ eonde deve ir o n´ de detalhamento de sua receita. ıvel Um programa, neste sentido, ´ um algoritmo escrito de forma t˜o detalhada quanto e afor necess´rio para quem executa as instru¸oes. O algoritmo pode ser mais gen´rico, a c˜ eo programa n˜o. a Como estamos pensando em deixar que o computador execute um algoritmo, pre-cisamos escrever um programa em uma linguagem que o computador possa entender
    • ´3.2. O QUE E UM PROGRAMA? 19as instru¸oes para posteriormente poder execut´-las com sucesso. c˜ a Qual ´, afinal, o conjunto de instru¸oes que o computador conhece? Para responder e c˜a esta pergunta precisamos conhecer melhor como funciona um computador, para, emseguida, continuarmos no estudo de algoritmos.
    • 20 CAP´ ITULO 3. SOBRE ALGORITMOS E PROGRAMAS3.3 Exerc´ ıcios 1. Escreva algoritmos como os que foram escritos neste cap´ ıtulo para cada uma das solu¸˜es do problema discutido na se¸ao 2.1. co c˜ 2. Escreva um algoritmo para o problema da troca de um unico pneu de um carro. ´ 3. Escreva um algoritmo para o problema de trocar um pneu de uma bicicleta.
    • Cap´ ıtulo 4O modelo do computadorEsta se¸ao tem dois objetivos, o primeiro ´ mostrar como ´ o funcionamento dos c˜ e ecomputadores modernos, isto ´, no n´ e ıvel de m´quina. A segunda ´ que o aluno a eperceba, desde o in´ do seu aprendizado, as limita¸oes a que est´ sujeito quando ıcio c˜ aprograma, e quais s˜o todas as instru¸˜es que o computador conhece. a co Ao final da leitura, o estudante deve compreender que, por mais sofisticada queseja a linguagem de programa¸˜o utilizada, a computa¸˜o de verdade ocorre como ca ca 1ser´ mostrado aqui. a4.1 Hist´rico oUm computador (hardware) ´ um conjunto de circuitos eletrˆnicos que manipulam e osinais el´tricos e que s˜o capazes de transformar sinais de entrada em sinais de sa´ e a ıda.Os sinais el´tricos podem ser representados, basicamente, pelos n´meros zero e um. e uExistem v´rias maneiras de se fazer isto, mas n˜o entraremos em detalhes neste texto. a a O importante a destacar ´ que uma computa¸˜o ´ uma manipula¸˜o de dados e ca e caresidentes em mem´ria atrav´s de altera¸oes de sinais el´tricos realizadas por circuitos o e c˜ eintegrados implementados normalmente em placas de sil´ ıcio. Quando os computadores foram criados, na d´cada de 1930, a programa¸ao deles e c˜era feita de maneira muito prec´ria. Era necess´rio configurar uma situa¸ao dos a a c˜circuitos para manipular os sinais el´tricos da maneira desejada para cada programa eparticular. Para se executar outro programa era necess´rio alterar os circuitos, assim ase reprogramando o computador para manipular os dados de outra maneira. Um computador era algo raro naqueles tempos, e devia rodar v´rios programas adiferentes, o que resultava em imenso trabalho para os engenheiros (os programadoreseram engenheiros na ´poca). e A mem´ria do computador, naqueles tempos, era exclusividade dos dados que oseriam manipulados. O programa era feito nos circuitos eletrˆnicos. o 1 O texto que segue foi adaptado de outro escrito pelo prof. Renato Carmo para a disciplina CI-208- Programa¸˜o de Computadores ministrada para diversos cursos na UFPR. ca 21
    • 22 CAP´ ITULO 4. O MODELO DO COMPUTADOR John von Neumann propˆs um modelo bastante simples, no qual tanto o programa oquanto os dados poderiam ficar simultaneamente em mem´ria, desde que a parte que oficaria programada nos circuitos pudesse interpretar o que era dado e o que era oprograma e realizar os c´lculos, isto ´, manipular os dados. a e Isto foi poss´ ıvel pela implementa¸ao em hardware de um limitado conjunto de c˜instru¸oes que s˜o usados pelo programa que est´ em mem´ria. Isto revolucionou a c˜ a a oarte da programa¸˜o. Os computadores modernos ainda funcionam assim. ca Nesta se¸˜o pretende-se mostrar atrav´s de um exemplo os princ´ ca e ıpios deste modelo.4.2 Princ´ ıpios do modeloConforme explicado, Von Neumann propˆs que os dados e o programa poderiam ser ocarregados em mem´ria ao mesmo tempo. Um elemento adicional denominado ciclo ode execu¸˜o de instru¸˜es controla a execu¸ao do programa. ca co c˜ A ideia ´ implementar em hardware um pequeno conjunto de instru¸oes que n˜o e c˜ amudam e programar o computador para realizar opera¸oes complexas a partir da c˜execu¸ao de v´rias instru¸˜es b´sicas da m´quina. c˜ a co a a Cada fabricante define o seu conjunto de instru¸oes b´sicas, mas o importante a c˜ aobservar ´ que, uma vez implementadas, este conjunto define tudo o que o computador e ´sabe fazer. E isto que queremos saber. Neste cap´ ıtulo vamos usar como exemplo um computador fabricado pela Big Com-puter Company (BCC).4.2.1 Endere¸os versus conte´ dos c uO computador da BCC implementa o modelo Von Neumann, logo, sua mem´ria ocont´m os dados e o programa. e A mem´ria do computador em um dado instante do tempo ´ uma configura¸˜o de o e casinais el´tricos que podem ser vistos pelo ser humano como uma sequˆncia absurda e ede zeros e uns (chamados de bits).2 O ser humano costuma n˜o gostar muito desta forma de visualiza¸˜o, ent˜o con- a ca avencionou algumas maneiras de enxergar n´meros inteiros que representam os bits. uN˜o vamos apresentar neste texto as diversas maneiras de convers˜o de n´meros, o a a uleitor interessado pode estudar sobre representa¸˜o bin´ria na literatura. ca a Vamos imaginar que a mem´ria do computador ´ uma tabela contendo ´ o e ındices(endere¸os) com conte´dos (dados). A t´ c u ıtulo de exemplo, vamos considerar uma“fotografia” da mem´ria de um computador da BCC em um certo momento, fotografia oesta apresentada na figura 4.1 2 Quem assistiu ao filme Matrix pode imaginar a complica¸˜o. ca
    • 4.2. PRINC´ IPIOS DO MODELO 23 Endere¸o c Conte´ do u Endere¸o c Conte´ do u Endere¸o c Conte´ do u 0 1 21 49 42 54 1 54 22 6 43 8 2 2 23 52 44 57 3 1 24 51 45 9 4 50 25 3 46 33 5 4 26 53 47 2 6 7 27 46 48 76 7 46 28 52 49 67 8 4 29 5 50 76 9 47 30 55 51 124 10 46 31 53 52 14 11 46 32 54 53 47 12 7 33 8 54 235 13 48 34 55 55 35 14 4 35 2 56 23 15 49 36 56 57 78 16 50 37 46 58 243 17 48 38 52 59 27 18 3 39 5 60 88 19 51 40 57 61 12 20 47 41 56 62 12 Figura 4.1: Uma fotografia da mem´ria. o Para melhor entendimento, ´ importante que o leitor tenha em mente a diferen¸a e centre endere¸o e conte´do do endere¸o. Para facilitar a compreens˜o, vamos adotar c u c auma nota¸ao. Seja p um endere¸o. Denotamos por [p] o conte´do do endere¸o p. c˜ c u cVejamos alguns exemplos com base na figura 4.1: [0] = 1 [[0]] = [1] = 54 [[[0]]] = [[1]] = [54] = 235 [0] + 1 = 1 + 1 = 2 [0 + 1] = [1] = 54 [[0] + 1] = [1 + 1] = [2] = 2 [[0] + [1]] = [1 + 54] = [55] = 354.2.2 O repert´rio de instru¸oes o c˜Conforme mencionado, o modelo Von Neumann pressup˜e que o computador que est´ o aem uso possui um conjunto limitado de instru¸oes programado em hardware. c˜ Cada equipamento tem o seu repert´rio de instru¸˜es. O repert´rio do computador o co oda BCC foi definido ap´s longas discuss˜es da equipe t´cnica da empresa e tem um o o econjunto extremamente limitado de instru¸˜es, na verdade apenas nove. co
    • 24 CAP´ ITULO 4. O MODELO DO COMPUTADOR Esta defini¸˜o levou em conta a capacidade financeira da empresa que n˜o tinha ca amuita verba para gravar em circuitos integrados um conjunto mais rico de instru¸˜es. co 3 As nove instru¸oes do computador da BCC s˜o apresentadas na figura 4.2. . c˜ a C´digo o Mnemˆnico Descri¸˜o o ca Nota¸˜o ca 1 load escreva em [p + 1] o valor do [p + 1] ← [p + 2]. n´mero em [p + 2] e some 3 u em p 2 add escreva em [p + 1] o valor da [p + 1] ← [[p + 2]] + [[p + 3]]. soma dos n´meros em [[p + u 2]] e [[p + 3]] e some 4 em p 3 sub escreva em [p + 1] o valor [p + 1] ← [[p + 2]] − [[p + 3]]. da subtra¸ao do n´mero em c˜ u [[p+2]] pelo n´mero em [[p+ u 3]] e some 4 em p 4 mult escreva em [p + 1] o valor [p + 1] ← [[p + 2]] × [[p + 3]]. do produto dos n´meros em u [[p + 2]] e [[p + 3]] e some 4 em p [[p+2]] 5 div escreva em [p + 1] o valor da [p + 1] ← [[p+3]] . divis˜o do n´mero em [[p + a u 2]] pelo n´mero em [[p + 3]] u e some 4 em p 6 sqrt escreva em [p + 1] o valor da [p + 1] ← [[p + 2]]. raiz quadrada de [[p + 2]] e some 3 em p 7 read leia um n´mero do teclado, u [p + 1] ← ∨. escreva-o em [p + 1] e some 2 em p 8 write escreva [[p + 1]] na tala e ← [[p + 1]]. some 2 em p 9 stop pare • Figura 4.2: O repert´rio de instru¸oes do computador da BCC. o c˜ 3 Os concorrentes comerciais famosos da BCC implementam algumas centenas de instru¸˜es, e coainda nenhuma delas ´ a de bater claras em neve. e
    • 4.2. PRINC´ IPIOS DO MODELO 254.2.3 O ciclo de execu¸˜o de instru¸˜es ca coO ciclo de execu¸˜o de instru¸˜es define o comportamento do computador. Funciona ca coassim (no computador da BCC): 1. comece com p = 0; 2. interprete [p] de acordo com a tabela de instru¸˜es e pare somente quando a co instru¸ao for uma ordem de parar (instru¸ao 9, stop). c˜ c˜ Devemos lembrar que este comportamento tamb´m est´ implementado nos circui- e atos eletrˆnicos do computador da BCC. o4.2.4 Exemplo de execu¸˜o de um programa caA grande surpresa por tr´s do modelo de Von Neumann ´ que, mesmo que o leitor a eainda n˜o compreenda, o que existe na verdade “disfar¸ado” na fotografia da mem´ria a c oda figura 4.1 ´ um programa que pode ser executado pelo computador, desde que todo eo processo siga as instru¸˜es descritas na se¸˜o anterior. co ca Vamos tentar acompanhar passo a passo como ´ o funcionamento deste esquema. ePara isto, o leitor talvez queira ir marcando, a l´pis, as altera¸˜es que ser˜o feitas a co a o o ´a seguir em uma c´pia da “fotografia da mem´ria” acima. E recomendado nestemomento se ter uma vers˜o impressa daquela p´gina. a a Notem que, no momento, n˜o ´ necess´rio sabermos qual o programa implemen- a e atado, afinal de contas, o computador jamais saber´. . . Ele executa cegamente as ins- atru¸oes. N´s saberemos logo a frente, mas, agora, para entendermos como ´ o funci- c˜ o ` eonamento deste modelo, vamos nos imaginar fazendo o papel do computador. 1. O programa come¸a com p = 0 c 2. Em seguida, ´ preciso interpretar [p], isto ´ [0] = 1. A instru¸ao de c´digo “1” ´ e e c˜ o e “load”, cujo comportamento ´, segundo a tabela de instru¸˜es “escreva em [2] e co o valor do n´mero em [3] e some 3 em p”. Ora, [2] = 54 e [3] = 2. Logo, o valor u 2 ´ colocado como sendo o conte´do da posi¸˜o 54. Havia nesta posi¸˜o o valor e u ca ca 235. Ap´s a execu¸ao da instru¸ao, existe um 2 neste lugar. O valor 235 n˜o o c˜ c˜ a existe mais. Ao final foi somado 3 no valor de p, isto ´, agora p = 3. e 3. Como p = 3 devemos interpretar [3] = 1. Logo, a instru¸ao ´ novamente “load”. c˜ e Analogamente ao que foi feito no par´grafo anterior, o conte´do de [5] = 4 ´ a u e colocado como sendo o conte´do da posi¸ao [4] = 50. Na posi¸ao 50 havia o u c˜ c˜ valor 76. Ap´s a execu¸ao da instru¸˜o o 76 d´ lugar ao 4. Ao final o valor de o c˜ ca a p foi atualizado para 6. 4. Como p = 6 devemos interpretar [6] = 7. Logo, a instru¸˜o para ser executada ca agora ´ “read”, isto ´, esperar o usu´rio digitar algo no teclado e carregar este e e a valor em [p + 1] = [7] = 46. Supondo que o usu´rio digitou o valor 5, este agora a substitui o antigo valor, que era 33. Ao final, o valor de p foi atualizado de 6 para 8.
    • 26 CAP´ ITULO 4. O MODELO DO COMPUTADOR 5. Como p = 8 devemos interpretar [8] = 4. Logo, a instru¸˜o a ser executada ca ´ “mult”. Isto faz com que o computador fa¸a a multiplica¸ao do valor em e c c˜ [[10]] = [46] pelo mesmo valor em [[11]] = [46]. O valor em [46] ´ 5 (aquele e n´mero que o usu´rio tinha digitado no teclado). O resultado da multiplica¸˜o, u a ca 5 × 5 = 25, ´ carregado na posi¸˜o de mem´ria [9] = 47. O valor ali que era 2 e ca o agora passa a ser 25. Ao final, ao valor de p foi somado 4, logo neste momento p = 12. ´ E importante salientar que este ´ um processo repetitivo que s´ terminar´ quando e o aa instru¸˜o “stop” for a da vez. O leitor ´ encorajado a acompanhar a execu¸˜o ca e capasso a passo at´ o final para entender como ´ exatamente o comportamento dos e ecomputadores quando executam programas. Isto ´, fica como exerc´ e ıcio ao leitor!Destacamos que os circuitos implementados cuidam da altera¸˜o do estado el´trico ca edos circuitos da mem´ria. o4.3 Humanos versus computadoresN´s seres humanos n˜o nos sentimos muito a vontade com este tipo de trabalho o a `repetitivo. Temos a tendˆncia a identificar “meta-regras” e executar a opera¸ao com e c˜base em um comportamento de mais alto n´ ıvel. Em suma, n´s aprendemos algo neste oprocesso, coisa que o computador s´ faz em filmes de fic¸˜o cient´ o ca ıfica. A primeira coisa que nos perguntamos ´: por qual motivo ora se soma um valor eem p, ora outro? Isto ´, quando executamos a opera¸˜o “load”, o valor somado em p e cafoi 3. Depois, quando executada a opera¸ao “read” o valor somado foi 2. Em seguida, c˜para a instru¸˜o “mult” o valor somado foi 4. ca O estudante atento, notadamente aquele que foi at´ o final na execu¸ao do ciclo de e c˜opera¸oes deixado como exerc´ c˜ ıcio, talvez tenha percebido uma sutileza por tr´s deste amodelo. De fato, quando se executa a instru¸ao [p], o conte´do de [p+1] sempre ´ o endere¸o c˜ u e cde destino dos dados que s˜o resultado da opera¸ao em execu¸ao. Os endere¸os a c˜ c˜ csubsequentes apontam para os operandos da opera¸ao que est´ programada para c˜ aacontecer. Assim: • Se for uma multiplica¸˜o, subtra¸ao ou soma, precisamos de dois operandos e ca c˜ do endere¸o destino, por isto se soma 4 em p; c • Se for um “load” precisamos de um operando apenas, assim como para a raiz quadrada, por isto se soma 3 em p; • Se for uma leitura do teclado ou uma escrita na tela do computador, ent˜o um a unico argumento ´ necess´rio, por isto se soma apenas 2 em p. ´ e a Uma outra observa¸ao importante ´ que, por quest˜es de hardware, o computador c˜ e oprecisa entender a mem´ria como esta esp´cie de “tripa”. O ser humano, ao contr´rio, o e a
    • 4.3. HUMANOS VERSUS COMPUTADORES 27uma vez que j´ identificou pequenos blocos relacionados as instru¸oes, pode tentar a ` c˜entender esta mesma mem´ria em outro formato, isto ´, separando cada um destes o epequenos blocos em uma unica linha. ´ Observamos que apenas os n´meros de 1 a 9 podem ser interpretados como c´digos u ode alguma instru¸˜o, pois s˜o os unicos c´digos da tabela de instru¸oes da BCC. ca a ´ o c˜ A separa¸ao dos pequenos blocos resulta em uma visualiza¸˜o em que os dados c˜ cas˜o separados das instru¸˜es numa mesma linha, cada linha agora representa toda a a coinstru¸ao com os dados. Isto pode ser visto na figura 4.3. Importante notar que ´ a c˜ emesma informa¸ao da figura 4.1, s´ que em outro formato visual. c˜ o Endere¸o Instru¸ao Operando Operando Operando c c˜ 0 1 54 2 3 1 50 4 6 7 46 8 4 47 46 46 12 7 48 14 4 49 50 48 18 3 51 47 49 22 6 52 51 25 3 53 46 52 29 5 55 53 54 33 8 55 35 2 56 46 52 39 5 57 56 54 43 8 57 45 9 Figura 4.3: Separando as instru¸oes. c˜4.3.1 Abstra¸˜o dos endere¸os ca cContinuando nossa explora¸ao de aspectos percebidos pelo ser humano a partir da c˜maneira como o computador trabalha, agora ´ poss´ percebermos mais duas coisas e ıvelimportantes: 1. O computador n˜o mudou seu modo de operar, ele continua executando as a instru¸oes na mem´ria conforme foi apresentado na se¸ao 4.2.4; c˜ o c˜ 2. A visualiza¸˜o na forma apresentada na figura 4.3 ´ apenas uma maneira mais ca e simples para o ser humano perceber o que o computador est´ fazendo. a Esta segunda observa¸ao ´ muito importante. Ela nos permite aumentar o grau de c˜ e“facilidade visual” ou, dizendo de outra maneira, o grau de nota¸˜o sobre o modelo caVon Neumann, o que vai nos permitir a compreens˜o do processo de uma maneira acada vez mais “humana”.
    • 28 CAP´ ITULO 4. O MODELO DO COMPUTADOR De fato, a partir da figura 4.3, podemos perceber que o endere¸o em que ocorre ca instru¸ao ´ irrelevante para n´s, humanos. Podemos perfeitamente compreender o c˜ e oprocesso de computa¸˜o se eliminarmos a coluna do “Endere¸o” na figura 4.3. ca c A figura 4.4 ilustra como ficaria o programa em mem´ria visto de outra maneira, oagora n˜o apenas em formato de blocos mas tamb´m sem a coluna dos endere¸os. Va- a e cmos perceber que, apesar de muito parecido com a figura anterior, o grau de “polui¸ao c˜visual” ´ bem menor. e Instru¸ao Operando Operando Operando c˜ 1 54 2 1 50 4 7 46 4 47 46 46 7 48 4 49 50 48 3 51 47 49 6 52 51 3 53 46 52 5 55 53 54 8 55 2 56 46 52 5 57 56 54 8 57 9 Figura 4.4: Abstra¸ao dos endere¸os. c˜ c Vale a pena refor¸ar: o computador n˜o mudou, ele continua operando sobre os c acircuitos eletrˆnicos, o que estamos fazendo ´ uma tentativa, um pouco mais humana, o ede enxergar isto.4.3.2 Abstra¸˜o dos c´digos das instru¸oes ca o c˜Continuando neste processo de “fazer a coisa do modo mais confort´vel para o ser ahumano”, afirmamos que ´ poss´ aumentar ainda mais o grau de nota¸˜o. e ıvel ca Para a etapa seguinte, vamos observar que, embora os computadores manipulemn´meros (em particular, n´meros bin´rios) de maneira muito eficiente e r´pida, o u u a amesmo n˜o ocorre para os humanos, que tˆm a tendˆncia a preferirem nomes. a e e De fato, basta observar que n´s usamos no nosso dia-a-dia nomes tais como Marcos, oJos´ ou Maria e n˜o n´meros tais como o RG do Marcos, o CPF do Jos´ ou o PIS da e a u eMaria. Ora, j´ que ´ assim, qual o motivo de usarmos os n´meros 1 − 9 para as instru¸oes a e u c˜se podemos perfeitamente usar o mnemˆnico associado ao c´digo? o o Desta forma, vamos modificar ainda mais uma vez nossa visualiza¸ao da mem´ria, c˜ odesta vez escrevendo os nomes dos mnemˆnicos no lugar dos n´meros. Assim, na o u
    • 4.3. HUMANOS VERSUS COMPUTADORES 29coluna Instru¸˜o, substituiremos o n´mero 1 por load, 2 por add, 3 por sub e assim ca upor diante, conforme a figura 4.2. O programa da figura 4.4 pode ser visualizado novamente de outra forma, tal comoapresentado na figura 4.5. Notem que o grau de compreens˜o do c´digo, embora ainda a on˜o esteja em uma forma totalmente amig´vel, j´ ´ bastante melhor do que aquela a a aeprimeira apresenta¸ao da “fotografia da mem´ria”. c˜ o De fato, agora ´ poss´ compreender o significado das linhas, em que existe um e ıveldestaque para a opera¸˜o (o mnemˆnico), a segunda coluna ´ o endere¸o de destino ca o e cda opera¸˜o e as outras colunas s˜o os operandos. ca a Instru¸ao Operando Operando Operando c˜ load 54 2 load 50 4 read 46 mult 47 46 46 read 48 mult 49 50 48 sub 51 47 49 sqrt 52 51 sub 53 46 52 div 55 53 54 write 55 add 56 46 52 div 57 56 54 write 57 stop Figura 4.5: Programa reescrito com Mnemˆnicos. o O que falta ainda a ser melhorado? N´s humanos usamos desde a mais tenra idade ooutro tipo de nota¸ao para representarmos opera¸oes. Este ´ o pr´ximo passo. c˜ c˜ e o4.3.3 Abstra¸˜o do repert´rio de instru¸˜es ca o coNesta etapa, observaremos que as instru¸˜es executadas pelo computador nada mais cos˜o do que manipula¸ao dos dados em mem´ria. Os c´lculos s˜o feitos sobre os dados a c˜ o a ae o resultado ´ colocado em alguma posi¸ao de mem´ria. e c˜ o Podemos melhorar o grau de abstra¸ao considerando a nota¸˜o apresentada na c˜ cafigura 4.6. Isto ´, vamos usar as tradicionais letras finais do alfabeto para ajudar na emelhoria da facilidade visual. Assim poderemos reescrever o programa mais uma veze ele ficar´ como apresentado na figura 4.7. a
    • 30 CAP´ ITULO 4. O MODELO DO COMPUTADOR [p] Instru¸˜o ca Nota¸˜o ca 1 load x y x ← [y] 2 add x y z x ← [y] + [z] 3 sub x y z x ← [y] − [z] x = [p + 1] 4 mult x y z x ← [y] × [z] y = [p + 2] 5 div x y z x ← [y] [z] z = [p + 3] 6 sqrt x y x ← [y] 7 read x x←V 8 write x V ← [x] 9 stop • Figura 4.6: Nota¸ao para as instru¸˜es. c˜ co 54 ← 2 50 ← 4 46 ← ∨ 47 ← [46] × [46] 48 ← ∨ 49 ← [50] × [48] 51 ← [47] − [49] 52 ← [[51]] 53 ← [46] − [52] [53] 55 ← [54] ← [55] 56 ← [46] + [52] [56] 57 ← [54] ← [57] • Figura 4.7: Programa escrito sob nova nota¸ao. c˜4.3.4 Abstra¸˜o dos endere¸os de mem´ria (vari´veis) ca c o aNa verdade, assim como j´ observamos que o c´digo da instru¸ao n˜o nos interessa, a o c˜ avamos perceber que o mesmo ´ verdade com rela¸˜o aos endere¸os de mem´ria. Ent˜o, e ca c o aconvencionaremos que os n´meros podem ser trocados por nomes. Fazemos isto na uvers˜o seguinte do mesmo programa. a Conv´m notar que o ser humano gosta de dar nomes apropriados para as coi- esas4 . Assim, ´ importante que os nomes que usarmos tenham alguma rela¸˜o com o e ca 4 Quem quiser ter uma ideia do estrago quando n˜o damos bons nomes para as acoisas, pode acompanhar dois di´logos humor´ a ısticos, um deles, o original, da du-pla Abbot & Costello sobre um jogo de beisebol, a outra de um ex-presidentedos Estados Unidos falando sobre o novo presidente da China. Ambos os v´ıdeosest˜o dispon´ a ıveis no YouTube: (1) http://www.youtube.com/watch?v=sShMA85pv8M; (2)http://www.youtube.com/watch?v=Lr1DWkgUBTw.
    • ¸˜ ¸˜4.4. ABSTRACAO DAS INSTRUCOES (LINGUAGEM) 31significado que eles est˜o desempenhando no programa. a Ent˜o chega o momento de n´s sabermos que o programa que est´ em mem´ria a o a orecebe como entrada dois valores b e c e escreve como sa´ as ra´ ıda ızes da equa¸ao c˜x2 − bx + c = 0. Os c´lculos usam o m´todo de B´skara. A figura 4.8 mostra a a e aconven¸˜o para a substitui¸˜o dos endere¸os por nomes. ca ca c Endere¸o c Nome 54 dois 50 quatro 46 B 47 quadradoB 48 C 49 quadruploC 51 discriminante 52 raizDiscriminante 53 dobroMenorRaiz 55 menorRaiz 56 dobroMaiorRaiz 57 maiorRaiz Figura 4.8: Dando nomes para os endere¸os. c Agora, usaremos esta conven¸ao de troca de endere¸os por nomes para podermos c˜ creescrever o programa ainda mais uma vez, obtendo a vers˜o da figura 4.9. a Esta vers˜o define o ultimo grau de abstra¸˜o simples. A partir deste ponto a a ´ canota¸ao deixa de ser s´ uma abreviatura das instru¸oes e a tradu¸ao deixa de ser c˜ o c˜ c˜direta. Apesar do fato de ser o ultimo n´ de nota¸ao simples, ainda ´ poss´ melhorar- ´ ıvel c˜ e ıvelmos o grau de facilidade visual, mas desta vez passamos para a nota¸ao ou linguagem c˜de “alto n´ ıvel”, que vai exigir a introdu¸ao dos chamados compiladores. c˜4.4 Abstra¸˜o das instru¸˜es (linguagem) ca coApesar de todas as nota¸oes e conven¸oes que foram feitas no programa, at´ se chegar c˜ c˜ ena vers˜o mostrada na figura 4.9, de certa maneira, o programa ainda est´ em um a aformato muito parecido com o do programa original. Para que seja poss´ aumentar o n´ de nota¸ao ainda mais ´ preciso contar com ıvel ıvel c˜ ea ajuda de programas tradutores, ou como eles s˜o mais conhecidos, os compiladores. a Estes programas conseguem receber como entrada um texto escrito em um for-mato adequado e gerar como sa´ um programa no formato da m´quina. Isto ´ ıda a e
    • 32 CAP´ ITULO 4. O MODELO DO COMPUTADOR dois ← 2 quatro ← 4 B ← ∨ quadradoB ← B×B C ← ∨ quadruploC ← quatro × C discriminante ← quadradoB - quadruploC √ raizDiscriminante ← discriminante dobroMenorRaiz ← B - raizDiscriminante menorRaiz ← dobroM enorRaiz dois ← menorRaiz dobroMaiorRaiz ← B + raizDiscriminante maiorRaiz ← dobroM aiorRaiz dois ← maiorRaiz • Figura 4.9: Programa reescrito com nomes para vari´veis. aposs´ ıvel apenas se os programas forem escritos em um formato que respeite regrasextremamente r´ ıgidas, pois sen˜o a tarefa n˜o seria poss´ a a ıvel. As linguagens de alto n´ s˜o definidas a partir de uma gram´tica extremamente ıvel a amais r´ıgida que a do portuguˆs, por exemplo. Estas gram´ticas, conhecidas como e agram´ticas livre de contexto, tˆm como uma de suas principais caracter´ a e ısticas que elasn˜o permitem escrever programas amb´ a ıguos. O portuguˆs permite. e Sem entrarmos muito em detalhes desta gram´tica, a t´ a ıtulo de exemplo mostrare-mos vers˜es em mais alto n´ do programa da figura 4.9. Estas vers˜es s˜o apresen- o ıvel o atadas na figura 4.10. read B read C read B discriminante ← B2 -√ × C 4 read C raizDiscriminante ← discriminante √ raizDiscriminante ← B 2 − 4 × C menorRaiz ← B−raizDiscriminante 2 write B - raizDiscriminante 2 write menorRaiz maiorRaiz ← B+raizDiscriminante write C + raizDiscriminante 2 2 write maiorRaiz Figura 4.10: Duas outras vers˜es do programa. o Estas vers˜es s˜o compreens´ o a ıveis para o ser humano, mas ainda n˜o est˜o no a aformato ideal para servirem de entrada para o compilador, em particular por causados s´ımbolos de fra¸ao ou do expoente. Os compiladores exigem um grau maior de c˜rigidez, infelizmente. A disciplina Constru¸ao de Compiladores, no sexto per´ c˜ ıodo docurso, ´ exclusiva para o estudo profundo dos motivos desta dificuldade, tanto de se everificar se o programa est´ correto do ponto de vista gramatical, quanto do ponto de avista de se traduzir o programa para linguagem de m´quina. a
    • ˜4.5. CONCLUSAO 33 No momento, vamos nos limitar a apresentar na figura 4.11 uma vers˜o do mesmo aprograma escrito em Pascal. Ap´s compila¸ao, o resultado ´ um programa que pode o c˜ eser executado pelo computador. Em suma, o compilador Pascal ´ um programa que, entre outras coisas, consegue etransformar o c´digo de alto n´ mostrado na figura 4.11 e gerar um c´digo que o o ıvel ocomputador possa executar tal como mostrado na primeira figura.program bascara (input , output) ;var b, c , raiz discriminante : real ;begin read (b) ; read (c) ; raizdiscriminante:= sqrt (b∗b − 4∗c) ; write ((b − raizdiscriminante )/2) ; write ((b + raizdiscriminante )/2) ;end. Figura 4.11: Vers˜o do programa escrito em Pascal. a4.5 Conclus˜o aNesta parte do texto procuramos mostrar que qualquer linguagem de programa¸ao c˜de alto n´ (tal como Pascal, C ou JAVA) ´ meramente uma nota¸ao convencionada ıvel e c˜visando facilitar a vida do ser humano que programa o computador. Esta nota¸˜o catrata de como um texto se traduz em um programa execut´vel em um determinado asistema operacional (que usa um determinado conjunto reduzido de instru¸oes).c˜ Um programa que traduz um texto que emprega uma certa nota¸˜o convencionada caem um programa execut´vel ´ chamado de “compilador”. a e Assim, a arte de se programar um computador em alto n´ ıvel ´, basicamente, econhecer e dominar uma nota¸ao atrav´s da qual textos (ou programas fonte) s˜o c˜ e atraduzidos em programas execut´veis. a Programar, independentemente da linguagem utilizada, significa concatenar asinstru¸oes dispon´ c˜ ıveis dentro de um repert´rio a fim de transformar dados de entrada oem dados de sa´ para resolver um problema. ıda Nas linguagens de alto n´ ıvel, as instru¸oes complexas s˜o traduzidas em uma c˜ asequˆncia de opera¸oes elementares do repert´rio b´sico da m´quina. Por isto os pro- e c˜ o a agramas fonte, quando compilados, geram execut´veis que s˜o dependentes do sistema a aoperacional e do hardware da m´quina onde o programa executa. a A partir destas ideias, partindo do princ´ ıpio que se tem um algoritmo que resolveum problema, o que ´ preciso saber para se programar um computador? e • Ter a disposi¸˜o um editor de textos, para codificar o algoritmo na forma de ` ca programa fonte;
    • 34 CAP´ ITULO 4. O MODELO DO COMPUTADOR • Ter ` disposi¸ao um compilador para a linguagem escolhida (no nosso caso, o a c˜ Free Pascal ), para transformar automaticamente um programa fonte em um programa execut´vel. a No restante deste curso, vamos nos preocupar com a arte de se construir algoritmos,tendo em mente que o estudante dever´ ser capaz de saber transformar este algoritmo aem forma de programa fonte de maneira que este possa ser compilado e finalmenteexecutado em um computador.
    • 4.6. EXERC´ ICIOS 354.6 Exerc´ ıcios 1. Para perceber como o ambiente do computador ´ limitado em fun¸ao do redu- e c˜ zido n´mero de instru¸oes dispon´ u c˜ ıveis em baixo n´ıvel, vocˆ pode tentar jogar e este jogo (http://armorgames.com/play/2205/light-bot). Nele, existe um boneco que tem que cumprir um percurso com o objetivo de apagar todas as c´lulas azuis do terreno quadriculado usando apenas poucos comandos e com e pouca “mem´ria” dispon´ o ıvel. Vocˆ pode fazer o uso de duas fun¸oes que auxi- e c˜ liam nas tarefas repetitivas. Divirta-se! 2. Modifique a “fotografia da mem´ria” apresentada para que o computador resolva o a equa¸˜o ax2 + bx + c = 0 pelo m´todo de B´scara. A diferen¸a do que foi ca e a c 2 apresentado ´ o coeficiente a do termo x e o sinal de b. e 3. Leia os seguintes textos da wikipedia: (a) http://pt.wikipedia.org/wiki/Arquitetura_de_von_Neumann, sobre a arquitetura de von Neumann; (b) http://pt.wikipedia.org/wiki/Von_Neumann, sobre a vida de von Neu- mann, em especial a parte sobre computa¸ao. c˜
    • 36 CAP´ ITULO 4. O MODELO DO COMPUTADOR
    • Cap´ ıtulo 5Conceitos elementaresAgora que sabemos os princ´ ıpios de algoritmos e as limita¸oes da m´quina, ´ preciso c˜ a eintroduzir conceitos elementares de algoritmos, sem os quais n˜o ´ poss´ a e ıvel seguiradiante. Apresentaremos problemas simples o bastante para nos concentrarmos nas novi-dades, isto ´, nos aspectos relevantes das estruturas de controle de fluxo e demais econceitos presentes nas linguagens de programa¸˜o. Nos pr´ximos cap´ ca o ıtulos estas es-truturas elementares ser˜o utilizadas na constru¸˜o de solu¸oes para problemas cada a ca c˜vez mais sofisticados.5.1 Algoritmos e linguagens de programa¸˜o caConforme vimos, os algoritmos devem ser escritos em um n´ de detalhamento su- ıvelficiente para que o compilador consiga fazer a tradu¸˜o do c´digo para linguagem de ca om´quina. a O compilador precisa receber um texto formatado em uma linguagem simples, n˜o aamb´ ıgua, precisa. Para isto as linguagens de programa¸ao seguem uma gram´tica c˜ ar´ ıgida, se comparada com a da l´ ıngua portuguesa. Tamb´m segue um vocabul´rio e alimitado, constitu´ de alguns poucos elementos. ıdo O que vamos apresentar aqui ´ uma linguagem de mais alto n´ do que aquela e ıvelapresentada no cap´ ıtulo 4. Trata-se de uma maneira de escrever que ´ um ponto inter- emedi´rio entre a capacidade de reda¸ao do ser humano e a capacidade de compreens˜o a c˜ ado computador. A base das linguagens de programa¸˜o, em geral, ´ constitu´ por: ca e ıda • a no¸ao de fluxo de execu¸˜o de um programa; c˜ ca • os comandos da linguagem que modificam os fluxo de execu¸˜o; ca • os comandos, e demais conceitos da linguagem, que manipulam os dados em mem´ria e a intera¸ao com o usu´rio (entrada e sa´ de dados); o c˜ a ıda • as express˜es da linguagem que permitem a realiza¸˜o de c´lculos aritm´ticos e o ca a e l´gicos; o 37
    • 38 CAP´ ITULO 5. CONCEITOS ELEMENTARES Neste cap´ıtulo usaremos as regras do compilador Free Pascal e para isto o leitordeve ter em m˜os algum guia de referˆncia desta linguagem, por exemplo, o mini guia a ede referˆncia que est´ dispon´ no site oficial da disciplina CI0551 , onde as explica¸˜es e a ıvel cos˜o detalhadas. Em sala de aula haver´ explica¸ao satisfat´ria. Por outro lado, os a a c˜ ocomandos da linguagem s˜o suficientemente claros para que o programa fa¸a sentido, a cbasta traduzir literalmente os termos em inglˆs para suas vers˜es em portuguˆs. e o e Os c´digos ser˜o escritos em Pascal, pois acreditamos que editar c´digo, compilar, o a oexecutar e testar programas ajuda o aluno a compreender os conceitos te´ricos. Desta oforma os alunos poder˜o testar variantes em casa e melhorar o aprendizado. a5.2 C´lculo de ra´ a ızes de uma equa¸˜o do segundo ca grauProblema: Calcular as ra´ da equa¸˜o do segundo grau x2 − bx + c = 0. ızes ca No cap´ıtulo 4 n´s seguimos em detalhes o processo de obten¸ao da solu¸˜o em um o c˜ camodelo de baixo n´ ıvel e chegamos a um c´digo de alto n´ o ıvel escrito em Pascal. Afigura 5.1 ´ uma c´pia da solu¸˜o apresentada na figura 4.11. e o caprogram bascara (input , output) ;var b, c , raiz discriminante : real ;begin read (b) ; read (c) ; raizdiscriminante:= sqrt (b∗b − 4∗c) ; write ((b − raizdiscriminante )/2) ; write ((b + raizdiscriminante )/2) ;end. Figura 5.1: Programa que implementa o m´todo de B´scara. e a Este c´digo simples ´ rico em elementos das linguagens de programa¸˜o. Ele o e cacont´m quatro elementos importantes: os comandos de entrada e sa´ o comando e ıdade atribui¸ao e as express˜es aritm´ticas. Antes disso, relembramos que o fluxo de c˜ o eexecu¸ao do programa ´ assim: o programa inicia ap´s o begin e executa os comandos c˜ e ode cima para baixo, terminando no end. Os dois primeiros comandos, read, servem para o usu´rio do programa fazer a acarga dos valores dos coeficientes da equa¸ao para a mem´ria do computador. Duas c˜ ovari´veis (abstra¸oes para posi¸oes f´ a c˜ c˜ ısicas de mem´ria), a e b, recebem estes valores. o 1 http://www.inf.ufpr.br/cursos/ci055/pascal.pdf.
    • ´5.3. IMPRIMIR A SOMA DE DOIS NUMEROS DADOS 39 A linguagem Pascal exige a declara¸˜o dos tipos, no cabe¸alho do programa (o ca cque antecede o bloco entre o begin e o end. Isto ´ detalhado no material complementar esobre o compilador. As duas ultimas linhas contˆm o comando write, que serve para imprimir alguma ´ ecoisa na tela do usu´rio, neste caso, o resultado de um c´lculo. a a O c´lculo propriamente dito ´ apresentado ao computador na forma de uma ex- a epress˜o aritm´tica, isto ´, uma sequˆncia de contas que s˜o realizadas pelo compu- a e e e atador: subtraia de b o valor calculado e armazenado na vari´vel raizdiscriminante e aem seguida divida tudo por 2. A regra para constru¸ao de express˜es aritm´ticas ´ c˜ o e edetalhado no material complementar. A terceira linha de c´digo ilustra um exemplo de um comando de atribui¸˜o, deno- o catado pelo s´ ımbolo :=. O computador deve realizar o c´lculo da express˜o aritm´tica a a edo lado direito do s´ ımbolo := e somente ap´s armazenar o valor resultante na vari´vel o aque aparece do lado esquerdo. Os c´lculos s˜o realizados conforme as regras descritas no material complementar: a aprimeiro b ∗ b obt´m o quadrado de b. Em seguida o valor de c ´ multiplicado por 4. e eO c´lculo continua pela subtra¸˜o do primeiro valor obtido pelo segundo. Finalmente a caa raiz quadrada deste ultimo valor ´ calculada e apenas ap´s tudo isto ocorrer o ´ e oresultado ´ armazenado na vari´vel raizdiscriminante. e a Desta forma, express˜es aritm´ticas servem para fazer c´lculos. Comandos de o e aentrada servem para o usu´rio fornecer dados ao computador. Comandos de sa´ a ıdaservem para o usu´rio receber informa¸oes do computador. Comandos de atribui¸ao a c˜ c˜servem para o computador manipular dados em mem´ria. Estes s˜o os elementos o amais simples de qualquer programa.5.3 Imprimir a soma de dois n´ meros dados uVamos aqui considerar ainda um outro problema bem simples.Problema: Ler dois n´meros do teclado e imprimir a soma deles na tela. u O programa apresentado na figura 5.2 est´ correto e captura a excˆncia da solu¸ao! a e c˜Os comandos de leitura carregam os n´meros digitados no teclado na mem´ria, em u oposi¸oes acess´ c˜ ıveis a partir dos nomes a e b. Em seguida, uma express˜o aritm´tica a efaz o c´lculo da soma de ambos e o resultado ´ impresso na tela. a e Um pequeno problema ´ que, quando executado, o cursor fica piscando na tela e en˜o deixa nenhuma mensagem sobre o que o usu´rio deve digitar. a a O estudante pode querer modificar ligeiramente este c´digo para produzir uma ointerface um pouco mais amig´vel, mas deve neste caso observar que o resultado ser´ a ao mesmo. A vers˜o minimamente modificada para este problema ´ apresentada na a efigura 5.3. O programador iniciante deve ter em mente que n˜o deve perder muito tempo com a“firulas” na tela, pelo menos n˜o neste curso. Em outras disciplinas, quando a arte da aprograma¸ao estiver dominada, o estudante aprender´ a integrar elegantemente uma c˜ a
    • 40 CAP´ ITULO 5. CONCEITOS ELEMENTARESprogram soma2;var a ,b: integer ;begin read (a) ; read (b) ; write (a+b) ;end. Figura 5.2: Primeira solu¸˜o. caprogram soma2;var a ,b: integer ;begin write (’entre com o valor de a: ’) ; read (a) ; write (’entre com o valor de b: ’) ; read (b) ; writeln (a ,’+’ ,b,’= ’ ,a+b) ;end. Figura 5.3: Mesma solu¸˜o, agora com interface amig´vel. ca ainterface amig´vel com o usu´rio do programa ao mesmo tempo mantendo o c´digo a a oleg´ ıvel. Neste exemplo usamos a outra vers˜o do comando de impress˜o, o writeln, a aque al´m de imprimir na tela muda o cursor de linha. e5.4 Imprimindo sequˆncias de n´ meros na tela e uNesta se¸˜o usaremos como apoio um problema muito simples. Apesar disto, a dis- cacuss˜o ser´ bastante rica em conceitos de algoritmos. a aProblema: Imprimir todos os n´meros entre 1 e 5. u Provavelmente um humano escreveria algo assim: 1. imprima o n´mero 1; u 2. imprima o n´mero 2; u 3. imprima o n´mero 3; u 4. imprima o n´mero 4; u 5. imprima o n´mero 5; u Este algoritmo pode ser codificado em Pascal tal como ´ ilustrado na figura 5.4, eusando-se o comando de sa´ apresentado anteriormente. ıda
    • ˆ ´5.4. IMPRIMINDO SEQUENCIAS DE NUMEROS NA TELA 41program contar ;begin write (1) ; write (2) ; write (3) ; write (4) ; write (5) ;end. Figura 5.4: Primeira solu¸˜o para contar de 1 a 5. ca Ap´s compilado e executado, os n´meros 1, 2, 3, 4 e 5 aparecem na tela, atendendo o uao enunciado. Mas, a luz das discuss˜es do cap´ ` o ıtulo 2, ´ f´cil ver que ela n˜o ´ muito e a a eboa, pois n˜o permite uma reimplementa¸˜o simples de problemas similares. Por a caexemplo, se o enunciado fosse “Imprimir todos os n´meros entre 1 e 20” no lugar de u“todos entre 1 e 5”, ter´ ıamos que escrever um c´digo como o ilustrado na figura 5.5. oprogram contar ;begin write (1) ; write (2) ; write (3) ; write (4) ; write (5) ; write (6) ; write (7) ; write (8) ; write (9) ; write (10) ; write (11) ; write (12) ; write (13) ; write (14) ; write (15) ; write (16) ; write (17) ; write (18) ; write (19) ; write (20) ;end. Figura 5.5: Primeira solu¸˜o modificada para n´meros de 1 a 30. ca u Extrapolando o enunciado do problema, se fosse para imprimir n´meros entre 1 ue 30.000 ou entre 1 e 100.000.000, o programa ficaria com 30 mil ou 100 milh˜es de olinhas de c´digo extremamente repetitivo e de dif´ e custosa edi¸˜o. o ıcil ca A simplicidade do racioc´ ınio inicial resultou em uma tarefa t˜o exaustiva que o acomputador deixou de ajudar, ele passou a atrapalhar!
    • 42 CAP´ ITULO 5. CONCEITOS ELEMENTARES Felizmente, h´ algoritmos melhores! a O computador ´, conforme vimos, uma m´quina com pouqu´ e a ıssimos recursos, masque, se bem explorados, permite-nos escrever programas fant´sticos. O racioc´ a ıniodeve ser ent˜o desenvolvido de tal maneira que o trabalho fique com o computador e an˜o com o programador. a Primeira li¸ao: n˜o ´ perda de tempo pensar mais antes de escrever c´digo! c˜ a e o As opera¸˜es elementares da m´quina s˜o, basicamente, colocar e consultar dados co a ada mem´ria ou fazer contas com bastante rapidez. As opera¸˜es s˜o executadas uma o co apor uma, em ordem, visualmente de cima para baixo. Como explorar isto? Se pelo menos consegu´ ıssemos uma vers˜o em que o copi- aar/colar fosse vi´vel, j´ ajudaria. A figura 5.6 ilustra uma solu¸ao em que isto ´ a a c˜ eposs´ ıvel.program contar ;var i : integer ;begin i:= 1; write ( i ) ; i:= i + 1; write ( i ) ; i:= i + 1; write ( i ) ; i:= i + 1; write ( i ) ; i:= i + 1; write ( i ) ; i:= i + 1;end. Figura 5.6: Segunda solu¸˜o. ca A express˜o i:= 1 ´ mais um exemplo de um comando de atribui¸˜o. O resultado a e cada execu¸ao do comando ´ que a express˜o ` direita do s´ c˜ e a a ımbolo :=, no caso o 1, ´ ecolocado na posi¸ao de mem´ria acessada pela vari´vel i. c˜ o a A express˜o i + 1 ´ mais um exemplo de uma express˜o aritm´tica, que ´ cons- a e a e etitu´ conforme as regras do compilador. Uma express˜o aritm´tica resulta em um ıda a evalor num´rico, no caso deste exemplo do mesmo tipo da vari´vel i, que ´ integer. e a e Destacamos ent˜o que a linha de c´digo contendo i:= i + 1 tamb´m ´ uma atri- a o e ebui¸ao e funciona assim: resolve-se o valor da express˜o a direita do s´ c˜ a ` ımbolo :=, isto ´, eo valor da vari´vel i, que na primeira vez ´ 1, ´ somando com a constante 1, resultando a e eno n´mero 2. Em seguida, este valor por sua vez ´ colocado na posi¸ao da vari´vel u e c˜ aque aparece ` esquerda do s´ a ımbolo :=, casualmente a pr´pria vari´vel i, que passa a o ater o valor 2.
    • ˆ ´5.4. IMPRIMINDO SEQUENCIAS DE NUMEROS NA TELA 43 O que ocorre ´ que uma certa vari´vel i ´ iniciada com o valor 1 e sucessivamente e a eent˜o usa-se o comando de impress˜o para exibir o valor de i na tela, incrementando- a ase de 1 em 1 o valor da vari´vel, obtendo-se como resultado final a impress˜o do valor a a5 e sendo 6 o ultimo valor (n˜o impresso) da vari´vel i. ´ a a O programa foi feito de maneira a ter blocos de comandos repetidos, pois aindan˜o sabemos mudar o fluxo de execu¸ao de um programa, isto ´, ele executa “de cima a c˜ epara baixo”, ent˜o a solu¸ao foi repetir os mesmos blocos 5 vezes. a c˜ ´ poss´ for¸ar a mudan¸a do fluxo de execu¸˜o do programa? O que precisamos E ıvel c c ca´ de uma estrutura que permita repetir um determinado trecho de c´digo enquantoe ouma determinada condi¸˜o for verdadeira. ca Isto ´ conseguido com o uso de comandos de repeti¸˜o. A linguagem Pascal oferece e catrˆs maneiras de se fazer isto. Veremos apenas uma delas por enquanto. No decorrer edo curso voltaremos as outras formas. A figura 5.7 ilustra o uso deste conceito. `program contar ;var i : integer ;begin i:= 1; while i <= 30000 do begin write ( i ) ; i:= i + 1; end;end. Figura 5.7: Sexta solu¸˜o. ca O comando de repeti¸ao executa os comandos aninhados no bloco entre o begin e c˜o end; enquanto uma express˜o booleana for verdadeira. No primeiro momento em aque for falsa, o fluxo ´ alterado para depois do end. e A express˜o i ≤ 30000 ´ uma express˜o booleana, retorna verdadeiro ou falso a e aapenas, dependendo da avalia¸ao dos valores pelo computador. No caso, vai resultar c˜falso apenas quando i for estritamente maior do que 30000. Neste exemplo, a vari´vel i foi inicializada com o valor 1. Em seguida, os comandos ade impress˜o e incremento s˜o executados enquanto o valor de i for menor ou igual a a a30000. Desta forma, o n´mero 1 ´ impresso, i passa a valer 2, que ´ menor ou igual u e ea 30000, ent˜o 2 ´ impresso e i passa a valer 3, que por sua vez ainda ´ menor ou a e eigual a 30000. Ent˜o 3 ´ impresso na tela e i passa a valer 4, e assim por diante, at´ a e eo momento em que ser´ impresso na tela o valor 30000. Neste ponto i passar´ a valer a a30001, que n˜o ´ menor ou igual a 30000, por isto o fluxo de execu¸˜o do programa a e cavai para o comando que segue o bloco do comando while, isto ´, o fim do programa. e Nesta se¸˜o mostramos o conceito de comando de repeti¸˜o (while/do) e um exem- ca caplo de uso de uma express˜es booleanas. A pr´xima se¸ao apresentar´ a ultima es- o o c˜ a ´trutura b´sica que nos interessa. a
    • 44 CAP´ ITULO 5. CONCEITOS ELEMENTARES5.5 Imprimir os quadrados de uma faixa de n´ meros uAinda no contexto de problemas simples, este outro problema nos permite combinar ast´cnicas usadas nos problemas anteriores e resolver algo ligeiramente mais complicado. eProblema: Imprimir uma tabela com os valores de x e x2 para todos os valores de xtais que 1 ≤ x ≤ 30. O programa que ilustra a solu¸˜o para este problema ´ apresentado na figura 5.8 ca ee imprime todos os valores inteiros de 1 a 30. Observamos que o enunciado n˜o deixa aclaro, mas n˜o seria poss´ imprimir todos os reais. Seria? a ıvelprogram quadrados ;var i : integer ;begin i:= 1; while i <= 30 do begin write ( i ,’ ’ , i ∗ i ) ; i:= i + 1; end;end. Figura 5.8: Tabela com os quadrados dos n´meros de 1 a 30. u O programa inicia com o valor de i igual a 1 e para cada valor entre 1 e 30 imprimena tela o pr´prio valor, seguido de um espa¸o em branco e finalmente o quadrado do o cn´mero, calculado pela express˜o aritm´tica i*i, que significa i × i. u a e5.6 Imprimindo a soma de v´rios pares de n´ meros a uProblema: Ler v´rios pares de n´meros e imprimir a soma de cada par. a u Este ´ uma variante do problema da se¸ao 5.3. Naquele caso um unico par de e c˜ ´n´mero era lido do teclado e a soma deles impressa. Agora temos que fazer a mesma ucoisa para v´rios pares de n´meros dados como entrada. a u A solu¸˜o para um unico par j´ estando feita, basta que o programa repita o ca ´ amesmo trecho de c´digo v´rias vezes, usando o comando while/do. o a Apenas uma quest˜o deve ser resolvida: quantos pares de n´meros ser˜o dados a u acomo entrada? O enunciado diz “v´rios pares”, mas n˜o estabelece o n´mero preciso. a a uAlgoritmos n˜o sabem lidar com isto. Fazendo uma analogia com o problema do bolo ade chocolate, ´ como se o enunciado fosse “fazer um bolo”. O cozinheiro n˜o sabe que e atipo de bolo est´ sendo solicitado e n˜o consegue realizar a tarefa. a a ´ E necess´rio estabelecer uma condi¸˜o de parada e isto deve estar claro no enun- a caciado. Existem duas formas de se resolver isto:
    • ´ ´5.7. TESTAR SE UM NUMERO LIDO E POSITIVO 45 • ou o enunciado estabelece a quantidade exata de n´meros a serem lidos; u • ou o enunciado estabelece uma condi¸˜o de parada alternativa. ca No primeiro caso o enunciado deveria ser algo assim: “ler 30 pares de n´meros do uteclado e imprimir, para cada par, a soma deles”. No segundo caso poderia ser algo mais ou menos assim: “ler pares de n´meros do uteclado e imprimir, para cada par, a soma deles. O algoritmo deve parar a execu¸˜o caquando os dois n´meros lidos forem iguais a zero”. u A figura 5.9 ilustra as duas formas. A esquerda apresenta a solu¸˜o usando-se um cacontador, a da direita apresenta a solu¸ao com crit´rio de parada alternativo. c˜ eprogram soma2variasvezes v1 ; program soma2variasvezes v2 ;var a ,b, cont : integer ; var a ,b: integer ;(∗ cont conta os numeros lidos ∗)begin begin cont:= 1; read (a) ; while cont <= 30 do read (b) ; begin while (a < 0) or (b < 0) do > > read (a) ; begin read (b) ; writeln (a+b) ; writeln (a+b) ; read (a) ; cont:= cont + 1; read (b) ; end; end;end. end. Figura 5.9: Duas formas para somar pares de n´meros. u Este exemplo ´ extremamente interessante pois permite ver claramente que o ec´digo referente aos comandos de leitura e impress˜o s˜o os mesmos, apesar da ordem o a adiferente no segundo exemplo. O que difere ´ a estrutura de controle do la¸o, isto e c´, do bloco de comandos que se repete. No quadro da esquerda, o algoritmo precisaecontar at´ 30, por isto existe uma vari´vel cont que faz esta conta. No quadro da e adireita, o la¸o ´ controlado por uma express˜o booleana um pouco mais sofisticada c e aque a do exemplo anterior, pois faz uso do operador or. A express˜o em quest˜o se a atorna falsa apenas quando ambos os n´meros lidos forem nulos. Se um dois dois for un˜o nulo, o la¸o ´ executado. a c e O comando de impress˜o ficou aparentemente invertido pela simples raz˜o de que a ao teste depende de uma primeira leitura das vari´veis a e b antes do teste, sen˜o o a ateste n˜o pode ser feito. Mas, ressaltamos, o n´cleo do programa ´ exatamente o a u emesmo, lˆ dois n´meros e imprime a soma, o que muda ´ o controle do la¸o. e u e c5.7 Testar se um n´ mero lido ´ positivo u eProblema: Ler um unico n´mero do teclado e imprim´ apenas se ele for positivo. ´ u ı-lo Parece simples para o ser humano saber se um n´mero ´ positivo ou n˜o, mas u e a
    • 46 CAP´ ITULO 5. CONCEITOS ELEMENTARESpara o computador o que est´ em mem´ria ´ apenas uma sequˆncia de bits. Logo, a o e epara ele decidir se um n´mero ´ positivo deve usar uma express˜o booleana. Mas, u e acomo executar o comando de impress˜o apenas em um caso (do n´mero ser positivo) a ue ignorar a impress˜o caso n˜o seja? Este problema permitir´ introduzir a no¸ao de a a a c˜desvio condicional. Um desvio condicional produz exatamente o efeito desejado, faz um teste e depen-dendo do resultado executa ou n˜o o comando subsequente. A figura 5.10 ilustra a asolu¸ao deste problema. No caso, o comando writeln s´ ´ executado se a express˜o c˜ oe abooleana for verdadeira. Caso o n´mero lido seja nulo ou negativo o fluxo de execu¸ao u c˜do programa “pula” para o comando subsequente, que no caso ´ o fim do programa. eprogram imprime se positivo ;var a ,b: integer ;begin read (a) ; i f a > 0 then writeln (a) ; (∗ so executa se a for positivo ∗)end. Figura 5.10: Imprime se for positivo. O comando de desvio condicional admite uma segunda forma, que estabelece umfluxo alternativo ao programa dependendo do teste. Considere o seguinte problema.Problema: Ler um unico n´mero do teclado e imprim´ apenas se ele for positivo. ´ u ı-loSe n˜o for imprimir a mensagem “n´mero inv´lido”. a u a A solu¸˜o deste problema requer uma variante do comando if, conforme ilustrado cana figura 5.11. Apenas um comando de impress˜o ser´ executado. a aprogram imprime se positivo ;var a ,b: integer ;begin read (a) ; i f a > 0 then writeln (a) (∗ so executa se a for positivo ∗) else writeln (’numero invalido’) ; (∗ executa se a for nulo ou negativo ∗)end. Figura 5.11: Imprime se for positivo, segunda vers˜o. a
    • 5.8. RESUMO 475.8 ResumoNeste cap´ ıtulo vimos todas as estruturas elementares para qualquer algoritmo (ouprograma) presentes em qualquer linguagem de programa¸ao. S˜o eles: c˜ aComandos • Entrada e sa´ (read e write, respectivamente); ıda • Atribui¸˜o (:=); ca • Repeti¸ao (while/do); c˜ • Desvio condicional (if/then, ou if/then/else);Express˜es o • Aritm´ticas; e • Booleanas. Qualquer algoritmo ´ escrito como uma combina¸˜o destes comandos manipu- e calando dados em mem´ria (vari´veis) da maneira como o algoritmo estabelece. Como o asabemos, cada problema tem v´rias solu¸˜es poss´ a co ıveis, mas uma vez fixado uma, pode-se escrever o programa na forma como o computador entenda, usando-se apenas asno¸oes apresentadas neste cap´ c˜ ıtulo. A menos do uso de estruturas de dados sofisticadas, as quais veremos a partirdo cap´ıtulo 10, agora j´ ´ poss´ escrever qualquer algoritmo, e consequentemente, ae ıvelqualquer programa! O que muda de uma linguagem de programa¸ao para outra ´ basicamente a grafia c˜ edos comandos, as vezes com alguma ligeira modifica¸˜o na sintaxe e na semˆntica do ca acomando. Por exemplo, na linguagem C, o comando write ´ grafado printf, na linguagem eBASIC ´ grafado print. Cada linguagem tem um comportamento diferente, n˜o ´ e a eapenas o nome que muda. Por exemplo, se imprime e muda de linha ou n˜o, em qual aformato escreve, etc. Mas, estes s˜o os elementos b´sicos para se programar. No pr´ximo cap´ a a o ıtuloveremos como usar estes comandos de maneira inteligente para resolver problemasmais complexos. O leitor pode pular o apˆndice da pr´xima se¸ao sem preju´ da e o c˜ ızocompreens˜o do restante do texto. a5.9 Apˆndice eExiste mais um comando de controle de fluxo, presente em qualquer linguagem deprograma¸ao: o comando de desvio incondicional. Segundo o modelo de Von Neumann c˜estudado, isto nada mais ´ do que alterar o controlador de instru¸˜es para um endere¸o e co carbitr´rio (na verdade controlado) quando pensamos no modelo de baixo n´ a ıvel. A figura 5.12 ilustra o uso do desvio incondicional para resolver o problema de seimprimir todos os n´meros de 1 a 30. u
    • 48 CAP´ ITULO 5. CONCEITOS ELEMENTARESprogram contar ;label : 10;var i : integer ;begin i:= 1; 10:write ( i ) ; i:= i + 1; i f i <= 30 then goto 10;end. Figura 5.12: Exemplo do uso do desvio incondicional. Neste exemplo, a vari´vel i ´ inicializada com o valor 1 e em seguida ´ executado a e eo comando que imprime 1 na tela. Em seguida a vari´vel i ´ incrementada e, ap´s a e overificar que 1 ´ menor ou igual a 30, o fluxo do programa executa o comando de edesvio incondicional goto, que faz com que o fluxo de execu¸ao do programa v´ para c˜ aa linha indicada pelo r´tulo 10, isto ´, imprime o valor da vari´vel i, incrementa o i e o e aassim por diante. Quando i valer 31 o goto n˜o ´ executado, o que faz com que o end a efinal seja atingido e o programa termina. Em outras palavras, ´ uma outra maneira (mais estranha) de se implementar o emesmo programa da figura 5.7. A observa¸ao interessante ´ que, no n´ de m´quina, c˜ e ıvel ao que o compilador faz ´ gerar a partir do programa da figura 5.7, um c´digo de e om´quina implementado usando-se uma no¸˜o de desvio incondicional, implementada a cano repert´rio reduzido de instru¸oes, mas isto o programador n˜o ´ obrigado a saber o c˜ a eagora. O que ele deve saber ´ que o uso de comandos de desvio incondicional n˜o ´ e a erecomendado pois na medida em que os programas v˜o ficando com muitas linhas de ac´digo, digamos algumas centenas de linhas ou mais, o que ocorre ´ que o programador o etende a se perder e passa a ter muita dificuldade em continuar o desenvolvimento doprograma quando o uso do goto ´ feito de qualquer maneira e, em especial, de forma eexagerada. Isto tende a tornar o c´digo ileg´ e de dif´ manuten¸ao. o ıvel ıcil c˜ Como vimos, as linguagens de alto n´ ıvel permitem mecanismos mais elegantespara repetir trechos de c´digo sem necessidade do uso do goto, usando-se o while. oIsto ´ baseado no princ´ da programa¸˜o estruturada, que nasceu com a linguagem e ıpio caALGOL-60. Esta linguagem, apesar de n˜o ser mais usada, deu origem ` maior parte a adas linguagens modernas, entre elas o pr´prio Pascal. o Este comando est´ em um apˆndice pois n´s nunca mais o usaremos. a e o
    • 5.10. EXERC´ ICIOS 495.10 Exerc´ ıcios 1. Leia o mini guia da linguagem Pascal, dispon´ em http://www.inf.ufpr. ıvel br/cursos/ci055/pascal.pdf, em especial os cap´ ıtulos de 1 a 3, a se¸˜o 4.2 e ca o cap´ ıtulo 7. 2. Tente compilar e executar com v´rias entradas os programas Pascal vistos neste a cap´ ıtulo. 3. Modifique o programa Soma2 para que ele receba um n´mero inteiro N de en- u trada e imprima a seguinte sequˆncia (N˜o use multiplica¸ao. Apenas opera¸oes e a c˜ c˜ de soma): 1 x N 2 x N 3 x N 4 x N 5 x N Isto ´, suponha que N=3. Ent˜o a sa´ deve ser: e a ıda 3 6 9 12 15 Outro exemplo, para N=6 6 12 18 24 30 4. Dado um n´mero inteiro que representa uma quantidade de segundos, determi- u nar o seu valor equivalente em graus, minutos e segundos. Se a quantidade de segundos for insuficiente para dar um valor em graus, o valor em graus deve ser 0 (zero). A mesma observa¸ao vale em rela¸˜o aos minutos e segundos. Por c˜ ca exemplo: 3.600 segundos = 1 grau, 0 minutos, 0 segundos. ; 3.500 segundos = 0 graus, 58 minutos e 20 segundos. 5. Dadas duas fra¸oes ordin´rias a/b e c/d, determinar a sua soma e o seu produto, c˜ a no formato de fra¸˜es. A entrada de dados deve ser constitu´ de duas linhas, co ıda cada uma contendo dois inteiros, uma para a e b outra para c e d. A sa´ ıda dever´ ser tamb´m de duas linhas cada uma contendo um par que representa o a e numerador e o denominados da soma e produto calculadas.
    • 50 CAP´ ITULO 5. CONCEITOS ELEMENTARES 6. Ler uma sequˆncia de N n´meros e imprimir a m´dia aritm´tica. e u e e 7. Calcular o produto dos n´meros ´ u ımpares de N1 a N2 (incluindo ambos), onde N 1 ≤ N 2 s˜o lidos do teclado. a 8. Calcule o valor da soma dos quadrados dos primeiros 50 inteiros positivos n˜o a nulos. 9. Ler uma massa de dados onde cada linha cont´m um n´mero par. Para cada e u n´mero lido, calcular o seu sucessor par, imprimindo-os dois a dois em listagem u de sa´ ıda. A ultima linha de dados cont´m o n´mero zero, o qual n˜o deve ser ´ e u a processado e serve apenas para indicar o final da leitura dos dados. 10. Ler uma massa de dados onde cada linha cont´m um valor num´rico do tipo e e real. O programa deve calcular a m´dia aritm´tica dos diversos valores lidos, e e imprimindo cada valor lido e, ao final, a m´dia calculada. A ultima linha de e ´ dados cont´m o unico n´mero zero. Este zero n˜o deve ser considerado no e ´ u a c´lculo da m´dia. a e 11. Ler uma massa de dados contendo a defini¸˜o de v´rias equa¸˜es do segundo ca a co 2 grau da forma Ax + Bx + C = 0. Cada linha de dados cont´m a defini¸ao de e c˜ uma equa¸ao por meio dos valores de A, B e C do conjunto dos n´meros reais. A c˜ u ultima linha informada ao sistema cont´m 3 (trˆs) valores zero (exemplo 0.0 0.0 ´ e e 0.0). Ap´s a leitura de cada linha o programa deve tentar calcular as duas ra´ o ızes da equa¸ao. A listagem de sa´ em cada linha, dever´ conter sempre os valores c˜ ıda, a de A, B e C lidos, seguidos dos valores das duas ra´ ızes reais. Considere que o usu´rio entrar´ somente com valores A, B e C tais que a equa¸ao garantidamente a a c˜ tem duas ra´ reais. ızes 12. Dados dois n´meros inteiros positivos determinar quantas vezes o primeiro di- u vide exatamente o segundo. Se o primeiro n˜o divide o segundo o n´mero de a u vezes ´ zero. e 13. Fa¸a um programa em Pascal que imprima exatamente a sa´ especificada na c ıda figura 1 (abaixo) de maneira que, em todo o programa, n˜o apare¸am mais do a c que trˆs comandos de impress˜o. e a 14. Fa¸a um programa em P ascal que imprima exatamente a mesma sa´ solicitada c ıda no exerc´ anterior, mas que use exatamente dois comandos de repeti¸ao. ıcio c˜ 15. Fa¸a um programa em Pascal que receba dois n´meros inteiros N e M como c u entrada e retorne como sa´ N M OD M usando para isto apenas opera¸˜es de ıda co subtra¸ao. O seu programa deve considerar que o usu´rio entra com N sempre c˜ a maior do que N . 16. Adapte a solu¸ao do exerc´ anterior para que a sa´ seja exatamente con- c˜ ıcio ıda forme especificada na figura 2 (abaixo).
    • 5.10. EXERC´ ICIOS 51 17. Fa¸a um programa em Pascal que receba uma massa de dados contendo o saldo c banc´rio de alguns clientes de um banco e imprima aqueles que s˜o negativos. a a O ultimo saldo, que n˜o corresponde a nenhum cliente (e portanto n˜o deve ser ´ a a impresso), cont´m o valor –999.999,99. e 1 1 121 121 12321 12321 1234321 1234321 123454321 123454321 12345654321 12345654321 1234567654321 1234567654321 123456787654321 123456787654321 12345678987654321 12345678987654321 Figura 1 Figura 2 18. Para cada uma das express˜es aritm´ticas abaixo, determine o tipo de dados o e da vari´vel que est´ no lado esquerdo do comando de atribui¸˜o bem como o a a ca resultado da express˜o que est´ no lado direito: a a (a) A := 1 + 2 ∗ 3; (b) B := 1 + 2 ∗ 3/7; (c) C := 1 + 2 ∗ 3 DIV 7; (d) D := 3 DIV 3 ∗ 4.0; (e) E := A + B ∗ C − D 19. Indique qual o resultado das express˜es abaixo, sendo: o a=6; b=9.5; d=14; p=4; q=5; r=10; z=6.0 ; sim= TRUE • ((z/a)+b*a)-d DIV 2 • p*(r MOD q)-q/2 • NOT sim AND (z DIV y + 1 = x) • (x + y > z) AND sim OR (y >= x) 20. Indique qual o resultado das express˜es abaixo, sendo: o a=5; b=3; d=7; p=4; q=5; r=2; x=8; y=4; z=6; sim=TRUE (a) (z DIV a + b * a) - d DIV 2 (b) p / r MOD q - q / 2 (c) (z DIV y + 1 = x) AND sim OR (y >= x) 21. Escrever um programa em Pascal que leia do teclado uma sequˆncia de n´meros e u inteiros at´ que seja lido um n´mero que seja o dobro ou a metade do anterior- e u mente lido. O programa deve imprimir na sa´ os seguintes valores: ıda
    • 52 CAP´ ITULO 5. CONCEITOS ELEMENTARES • a quantidade de n´meros lidos; u • a soma dos n´meros lidos; u • os dois valores lidos que for¸aram a parada do programa. c Exemplos: Entrada -549 -716 -603 -545 -424 -848 Sa´da ı 6 -3685 -424 -848 Entrada -549 -716 -603 -545 -424 646 438 892 964 384 192 Sa´da ı 11 679 384 192 22. Escreva um programa que troque o conte´do de duas vari´veis inteiras sem u a utilizar vari´veis auxiliares. a 23. Escreva em Pascal as seguintes express˜es aritm´ticas usando o m´ o e ınimo poss´ ıvel de parˆnteses: e W2 (a) Ax2 +Bx+C P1 +P2 Y −Z R (b) W +R AB 24. Tente compilar este programa. Procure descobrir qual(is) ´ (s˜o) o(s) erro(s) e e a corrigi-lo(s). (∗ programa que le um numero e retorna o ultimo algarismo ∗) (∗ escrito por Marcos Castilho em 22/10/2002, com erros . ∗) program ultalgarismo ; begin read (A) writeln (A mod 10, A div 10) ; end. 25. Seja o seguinte programa em Pascal : program Misterio ; var nota1 , nota2 ,media: integer ; begin readln(nota1 , nota2) while nota1 < 0 do > media:=nota1+nota2/2; writeln(nota1 , nota2 ,media) ; readln(nota1 , nota2) ; end.
    • 5.10. EXERC´ ICIOS 53 (a) Quantos s˜o, e quais s˜o, os erros de compila¸˜o deste programa? a a ca (b) Considerando que vocˆ corrigiu os erros de compila¸ao corretamente, o que e c˜ faz este programa? (c) Considerando a estrutura do programa, os nomes das vari´veis e a en- a denta¸˜o usada, podemos afirmar que o programador cometeu alguns erros ca de l´gica. Quantos s˜o e quais s˜o estes erros? o a a (d) O que faz o programa faz ap´s estas corre¸˜es? o co 26. Enumere e explique todos os erros contidos no seguinte c´digo Pascal : o program misterio2 ; var m, g : real ; N1, N2: integer ; begin readln(N1, N2) ; i f (N1 > N2) then m := N2 else m := N1; g:= 1; while g do begin i f (N1 mod m = 0) A D (N2 mod m = 0) then N g := 0; else m := m − 1; end; i f (m := N1) then writeln(’O valor resultante eh: ’ m) ; end. 27. Dado o programa abaixo, mostre o acompanhamento de sua execu¸˜o para trˆs ca e valores de entrada (valores pequenos). Em seguida, descreva o que o programa faz, comprovando suas afirma¸oes. c˜ program questao1(input , output) ; var x: integer ; y, m: longint ; begin read(x) ; y := 0; m := 1; while x > 0 do begin y := y + (x mod 2) ∗ m; x := x div 2; m := m ∗ 10; end; writeln(y) end.
    • 54 CAP´ ITULO 5. CONCEITOS ELEMENTARES 28. Uma agˆncia governamental deseja conhecer a distribui¸˜o da popula¸ao do pa´ e ca c˜ ıs por faixa salarial. Para isto, coletou dados do ultimo censo realizado e criou um ´ arquivo contendo, em cada linha, a idade de um cidad˜o particular e seu sal´rio. a a As idades variam de zero a 110 e os sal´rios variam de zero a 19.000,00 unidades a da moeda local (sal´rio do seu dirigente m´ximo). a a As faixas salariais de interesse s˜o as seguintes: a • de 0 a 3 sal´rios m´ a ınimos • de 4 a 9 sal´rios m´ a ınimos • de 10 a 20 sal´rios m´ a ınimos • acima de 20 sal´rios m´ a ınimos. Sendo o sal´rio m´ a ınimo igual a 450,00 unidades da moeda local. Fa¸a um programa em Pascal que leia o arquivo de entrada e produza como c sa´ os percentuais da popula¸ao para cada faixa salarial de interesse. ıda c˜ 29. Aqui temos uma forma peculiar de realizar uma multiplica¸ao entre dois n´meros: c˜ u multiplique o primeiro por 2 e divida o segundo por 2 at´ que o primeiro seja e reduzido a 1. Toda vez que o primeiro for impar, lembre-se do segundo. N˜o a considere qualquer fra¸˜o durante o processo. O produto dos dois n´meros ´ ca u e igual a soma dos n´meros que foram lembrados. Exemplo: 53 × 26 = u 53 26 13 6 3 1 26 52 104 208 416 832 26 + 104 + 416 + 832 = 1378 Fa¸a uma fun¸ao em Pascal que receba dois reais e retorne a multiplica¸ao dos c c˜ c˜ dois, do modo como foi especificado acima. N˜o ´ permitido uso de array. a e 30. Fa¸a um programa em Pascal que some duas horas. A entrada deve ser feita da c seguinte maneira: 12 52 7 13 A sa´ deve ser assim: ıda 12:52 + 7:13 = 20:05
    • Cap´ ıtulo 6T´cnicas elementares eO objetivo deste cap´ ıtulo ´ o dom´ por parte do estudante das principais estruturas e ıniode controle de fluxo, em particular quando usadas de maneira combinada: atribui¸˜o; caentrada e sa´ ıda; desvio condicional e repeti¸ao, al´m do uso de express˜es. c˜ e o6.1 Atribui¸oes dentro de repeti¸˜es c˜ coNesta se¸ao veremos exemplos de problemas cujas solu¸˜es algor´ c˜ co ıtmicas requerem ouso de atribui¸˜es aninhadas em repeti¸˜es. co co6.1.1 Somando n´ meros uO problema abaixo servir´ para discutirmos v´rias maneiras de se resolver um mesmo a aproblema at´ chegarmos na maneira mais elegante. Aproveitamos para discutir a et´cnica dos acumuladores. eProblema: Ler 5 n´meros positivos do teclado e imprimir a soma deles. u A primeira e mais simples solu¸ao consiste em ler os 5 n´meros do teclado e c˜ uem seguida imprimir a soma deles. O programa da figura 6.1 mostra o algoritmoimplementado para esta primeira proposta.program soma valores ;var a1 , a2 , a3 , a4 , a5 : integer ;begin read (a1 , a2 , a3 , a4 , a5) ; writeln (a1 + a2 + a3 + a4 + a5) ;end. Figura 6.1: Primeira solu¸˜o. ca 55
    • 56 CAP´ ´ ITULO 6. TECNICAS ELEMENTARES O programa funciona e atende ao requisitado no enunciado. Mas a solu¸ao n˜o ´ c˜ a eboa. Imagine que fosse pedido a soma n˜o de 5 n´meros, mas de 50. Para manter a ua mesma ideia do algoritmo anterior, ter´ ıamos que escrever algo como ilustrado nafigura 6.2.program soma valores 50 ;var a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 , a10 , a11 , a12 , a13 , a14 , a15 , a16 , a17 , a18 , a19 , a20 , a21 , a22 , a23 , a24 , a25 , a26 , a27 , a28 , a29 , a30 , a31 , a32 , a33 , a34 , a35 , a36 , a37 , a38 , a39 , a40 , a41 , a42 , a43 , a44 , a45 , a46 , a47 , a48 , a49 , a50 : integer ;begin read (a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 , a10 , a11 , a12 , a13 , a14 , a15 , a16 , a17 , a18 , a19 , a20 , a21 , a22 , a23 , a24 , a25 , a26 , a27 , a28 , a29 , a30 , a31 , a32 , a33 , a34 , a35 , a36 , a37 , a38 , a39 , a40 , a41 , a42 , a43 , a44 , a45 , a46 , a47 , a48 , a49 , a50) ; writeln (a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a20 + a21 + a22 + a23 + a24 + a25 + a26 + a27 + a28 + a29 + a30 + a31 + a32 + a33 + a34 + a35 + a36 + a37 + a38 + a39 + a40 + a41 + a42 + a43 + a44 + a45 + a46 + a47 + a48 + a49 + a50) ;end. Figura 6.2: Imprimindo a soma de 50 n´meros lidos no teclado. u ´ o E ´bvio que esta t´cnica n˜o ´ adequada. Al´m disto, s´ pode ser usada quando e a e e ose sabe quantos n´meros ser˜o fornecidos. Para o problema abaixo, o algoritmo n˜o u a apode ser usado.Problema: Ler uma sequˆncia de n´meros positivos do teclado e imprimir a soma e udeles. O programa deve terminar quando o n´mero lido do teclado for zero. u Como usar uma vari´vel para cada valor lido? Uma vez que n˜o se sabe, a a aprinc´ıpio, quantos n´meros ser˜o digitados, n˜o h´ como fazer isto. Logo, a t´cnica u a a a ede solu¸˜o n˜o pode ser esta. ca a O algoritmo apresentado na figura 6.3 faz uso de uma t´cnica elementar em pro- egrama¸ao que ´ o uso de acumuladores. c˜ e Conv´m observar que a parte do algoritmo relativa a entrada de dados controlada epelo la¸o j´ foi estudada no cap´ c a ıtulo anterior. Desta forma, se eliminarmos todasas linhas que cont´m a vari´vel soma o que teremos ´ um programa que lˆ v´rios e a e e an´meros do teclado at´ que seja lido um zero. O programa n˜o faria nada com os u e an´meros lidos. u Usa-se uma vari´vel (soma) cujo papel ´ acumular valores, isto ´, a vari´vel ´ a e e a einicializada com um valor nulo e na sequˆncia, ela ´ atualizada para os outros valores e ea medida em que eles s˜o lidos do teclado.` a A inicializa¸ao do acumulador com o valor zero deve-se ao fato deste ser o elemento c˜
    • 6.2. DESVIOS CONDICIONAIS ANINHADOS 57neutro da adi¸˜o. Se fosse uma multiplica¸ao de v´rios n´meros, o acumulador deveria ca c˜ a user inicializado com o elemento neutro da multiplica¸˜o, isto ´, o 1. ca eprogram soma valores ;var numero, soma: integer ;begin soma:= 0; (∗ inicializa o acumulador ∗) read (numero) ; while numero < 0 do > begin soma:= soma + numero; (∗ atualiza o acumulador ∗) read (numero) ; end;end. Figura 6.3: T´cnica do acumulador. e Na figura 6.4 mostra-se como resolver o problema inicial usando a t´cnica dos eacumuladores. Notem que a solu¸˜o explora um comando de atribui¸ao sob o escopo ca c˜de um comando de repeti¸ao. c˜ Trocando-se o valor da constante MAX de 5 para 50, tem-se a solu¸ao para o c˜ ´ f´cil perceber que esta maneira ´ gen´rica, resolve problemas similaresproblema 2. E a e epara qualquer tamanho de entrada, bastando-se trocar o valor da constante MAX.program soma valores ;const max=5;var numero, i , soma: integer ;begin soma:= 0; i:= 1; while i <= max do begin read (numero) ; soma:= soma + numero; end;end. Figura 6.4: Solu¸˜o para o primeiro problema com acumuladores. ca6.2 Desvios condicionais aninhadosO problema a seguir nos permitir´ apresentar um algoritmo que o resolve de maneira aelegante atrav´s do uso de estruturas contendo aninhamentos de desvios condicionais. e
    • 58 CAP´ ´ ITULO 6. TECNICAS ELEMENTARES6.2.1 O menor de trˆs eProblema: Ap´s ler trˆs n´meros no teclado, imprimir o menor deles. o e u A solu¸˜o para este problema (figura 6.5) envolve uma s´rie de tomada de decis˜es ca e ocom diversos fluxos alternativos de c´digo. o Quando um comando est´ sob o controle de outro, diz-se que o comando mais ainterno est´ sob o escopo do mais externo. Neste caso, vamos usar um desvio condici- aonal que controla outro. No jarg˜o dos programadores, se diz que os comandos nesta aforma est˜o aninhados. aprogram imprime menor;var a , b, c : integer ;begin write(’entre com tres numeros inteiros: ’) ; read(a , b, c) ; i f a < b then i f a < c then writeln (’o menor dos tres eh ’ ,a) else writeln (’o menor dos tres eh ’ , c) else i f b < c then writeln (’o menor dos tres eh ’ ,b) else writeln (’o menor dos tres eh ’ , c)end. Figura 6.5: Imprimir o menor dentre 3 n´meros lidos. u6.3 Desvios condicionais dentro de repeti¸oes c˜Nesta se¸˜o veremos exemplos de problemas cujas solu¸˜es algor´ ca co ıtmicas requerem ouso de atribui¸˜es aninhadas em repeti¸oes. co c˜6.3.1 Imprimir apenas n´ meros positivos uNeste problema estudaremos como aninhar um comando de desvio condicional dentrodo escopo de um comando de repeti¸ao. Tamb´m aproveitaremos para iniciar o estudo c˜ esobre como pensar no problema global e nos poss´ ıveis subproblemas existentes.Problema: Ler do teclado 30 n´meros inteiros e imprimir na tela aqueles que s˜o u a
    • ¸˜6.3. DESVIOS CONDICIONAIS DENTRO DE REPETICOES 59positivos, ignorando os negativos ou nulos. Se o enunciado fosse simplesmente para ler e imprimir 30 n´meros, como far´ u ıamos?Provavelmente como ilustrado na figura 6.6. Observamos que este problema ´ muito esimilar a outros j´ estudados no cap´ a ıtulo anterior. Trata-se de um la¸o que precisa de cum contador para se determinar a sa´ ıda.program lereimprimir ;var i , a : integer ; (∗ i serve para contar quantos numeros foram lidos ∗)begin i:= 1; while i <= 30 do begin read (a) ; writeln (a) ; i:= i + 1; end;end. Figura 6.6: Lendo e imprimindo 30 n´meros. u O problema ´ que n˜o queremos imprimir todos os n´meros lidos, mas apenas e a uaqueles que s˜o positivos: se o n´mero lido for positivo, ent˜o queremos imprimir, a u asen˜o n˜o. Conforme j´ visto, o comando if faz exatamente isto, testa uma express˜o a a a abooleana que, caso satisfeita, executa o comando subsequente, sen˜o o pula, passando adiretamente para o seguinte, tal como ilustrado na figura 6.7.program lereimprimir ;var i , a : integer ;begin i:= 1; while i <= 30 do begin read (a) ; i f a > 0 then writeln (a) ; (∗ so eh executado quando a eh positivo ∗) i:= i + 1; end;end. Figura 6.7: Lendo e imprimindo os positivos apenas. Relembrando, o comando de desvio condicional tamb´m permite executar exclu- esivamente uma a¸ao alternativa, caso o teste da express˜o booleana resulte em falso. c˜ aPor exemplo, se o enunciado fosse “ler 30 n´meros e imprimir os que s˜o pares mas u aimprimir o quadrado dos que n˜o s˜o, incluindo o zero”. a a
    • 60 CAP´ ´ ITULO 6. TECNICAS ELEMENTARES Do ponto de vista l´gico, seria o mesmo que dizer o seguinte: “se o n´mero lido for o upositivo, imprim´ı-lo, caso contr´rio ele ´ zero ou negativo, ent˜o imprimir o quadrado a e adele”. Isto pode ser visto na figura 6.8. Destacamos mais uma vez que a estruturade controle do la¸o n˜o mudou, apenas os comandos que s˜o executados no la¸o c a a cmudaram, caracterizando-se dois subproblemas: um para controlar o la¸o, outro para cse decidir se o n´mero ´ positivo ou n˜o e o que fazer com ele. u e aprogram lereimprimir ;var i , a : integer ;begin i:= 1; while i <= 30 do begin read (a) ; i f a > 0 then writeln (a) (∗ so eh executado quando a for positivo ∗) else writeln (a∗a) ; (∗ so eh executado quando a <= 0 ∗) i:= i + 1; end;end. Figura 6.8: Lendo e imprimindo os positivos e os quadrados dos ´ ımpares. Agora, o comando que imprime a s´ ´ executado quando a > 0. Se isto n˜o for oe averdade, o que ´ impresso ´ o quadrado de a. Em ambos os casos o valor de i ´ e e eincrementado. Este ultimo programa pode facilmente ser modificado para se resolver o problema ´de se contar quantos n´meros lidos s˜o positivos e quantos n˜o s˜o. Basta, ao inv´s u a a a ede imprimir, contar, ou em outras palavras, acumular. Para isto s˜o necess´rias duas vari´veis adicionais, que iniciam em zero e que s˜o a a a aincrementadas a cada vez que um n´mero ´ identificado como positivo ou n˜o. Esta u e aideia pode ser vista na figura 6.9. Importante notar a similaridade das duas solu¸oes. c˜Os problemas s˜o ligeiramente diferentes, eles diferem em um dos subproblemas ape- anas: um deve imprimir, o outro deve acumular. Os outros problemas tais como ocontrole do la¸o e a leitura dos dados s˜o exatamente os mesmos problemas. c a Podemos usar o mesmo racioc´ ınio para resolver toda uma classe de problemassimilares, isto ´, imprimir a soma de n´meros que satisfazem alguma propriedade. e u No caso do problema anterior, a propriedade era “ser negativo” ou “ser positivo”.Mas poderia ser qualquer outra coisa, como por exemplo “ser diferente de zero”, “serprimo”, “ser m´ltiplo de 50” ou algo mais complexo como “ter saldo positivo nos uultimos 12 meses e n˜o estar devendo para o imposto de renda”.´ a Vejamos um problema similar para uma propriedade simples, cuja solu¸˜o pode caser facilmente adaptada do algoritmo anterior.
    • ¸˜6.3. DESVIOS CONDICIONAIS DENTRO DE REPETICOES 61program contar ;var i , (∗ serve para contar ate 30 ∗) conta positivos , (∗ serve para contar os positivos ∗) conta outros , (∗ serve para contar os nao positivos ∗) a : integer ; (∗ numeros lidos na entrada ∗)begin conta positivos:= 0; (∗ eh preciso inicializar a variavel ∗) conta outros:= 0; i:= 1; while i <= 30 do begin read (a) ; i f a > 0 then conta positivos:= conta positivos + 1 else conta outros:= conta outros + 1; i:= i + 1; end; writeln (’A quantidade de positivos lidos eh ’ , conta positivos ) ; writeln (’A quantidade de nao positivos lidos eh ’ , conta outros) ;end. Figura 6.9: Contando os positivos e os negativos e nulos.6.3.2 Somando pares e ´ ımparesProblema: Ler uma sequˆncia de n´meros e imprimir separadamente a soma dos e uque s˜o pares e a soma dos que s˜o ´ a a ımpares. O programa deve terminar quando on´mero lido for o zero. Este ultimo n´mero tamb´m deve ser ignorado. u ´ u e No programa ilustrado na figura 6.10, basicamente foi colocado no lugar do ifx > 0 then a tradu¸ao da express˜o if “x ´ par” then, tradu¸ao esta que envolve o uso c˜ a e c˜da opera¸˜o de resto de divis˜o inteira. Todo n´mero que, dividido por 2, resulta em ca a uresto 0 s´ pode ser par. Caso contr´rio ´ ´ o a e ımpar. Tamb´m foi feita uma mudan¸a no e cnome das vari´veis para facilitar a compreens˜o do c´digo. a a o A propriedade pode ser t˜o complexa quanto se queira, mas ´ importante observar a eque o c´digo de base n˜o muda muito. Observe que h´ uma leitura, o teste, algum o a aprocessamento e, por ultimo, a leitura do pr´ximo valor, repetindo-se o c´digo. ´ o oProblema: Ler n´meros do teclado, at´ ler um zero, e imprimir apenas os que s˜o u e aao mesmo tempo m´ltiplos de 7 mas n˜o s˜o m´ltiplos de 2. u a a u Solu¸ao similar (apresentada na figura 6.11). Um la¸o controla o t´rmino da c˜ c erepeti¸ao, e um desvio condicional verifica a propriedade e algum c´digo ´ executado c˜ o eem seguida (no caso uma simples impress˜o na tela). a
    • 62 CAP´ ´ ITULO 6. TECNICAS ELEMENTARESprogram somapareseimpares ;var x, somapares , somaimpares : integer ;begin somapares:= 0; somaimpares:= 0; read (x) ; while x < 0 do > begin i f x mod 2 = 0 then (∗ verdadeiro quando x eh par ∗) somapares:= somapares + x else somaimpares:= somaimpares + x; read (x) ; end; writeln (somapares , somaimpares) ;end. Figura 6.10: Soma pares e ´ ımpares.program somaquadradosperfeitos ;var a : integer ;begin read (a) ; while a < 0 do > begin i f (a mod 7 = 0) A D (a mod 2 < 0) then N > writeln (a) ; read (a) ; end;end. Figura 6.11: Imprime os m´ltiplos de 7 que n˜o s˜o m´ltiplos de 2. u a a u Um terceiro problema similar ´ apresentado a seguir. eProblema: Ler n´meros do teclado, at´ ler um zero, e imprimir apenas os que forem u em´ltiplos de 3 maiores do que 50 e menores ou iguais a 201. u Novamente, mesmo racioc´ ınio (solu¸˜o na figura 6.12). Apenas a propriedade a caser satisfeita ´ mais complexa, envolve uma express˜o booleana contendo conectivos e ade conjun¸˜o. E ca ´ importante para o estudante comparar os trˆs ultimos c´digos e e ´ operceber a enorme similaridade entre eles.6.3.3 Convertendo para bin´rio aEste problema ´ um desafio que pode ser resolvido com a mesma ideia de se aninhar eum desvio condicional sob o escopo de uma repeti¸ao, combinada com o uso dos c˜
    • ¸˜6.3. DESVIOS CONDICIONAIS DENTRO DE REPETICOES 63program somaquadradosperfeitos ;var a : integer ;begin read (a) ; while a < 0 do > begin i f (a mod 3 = 0) A D (a > 50) A D (a <= 201) then N N writeln (a) ; read (a) ; end;end. Figura 6.12: Imprime os m´ltiplos de 3 lidos entre 51 e 201. uacumuladores.Problema: Dado um n´mero inteiro entre 0 e 255 imprimir este n´mero em seu u uformato bin´rio. a Este ´ um exemplo cl´ssico em que o estudante esquece da teoria. Tradicional- e amente, o professor apresenta a defini¸ao de n´meros bin´rios, como sendo uma s´rie c˜ u a eespecial de potˆncias de 2. Em seguida apresenta o “algoritmo para convers˜o para e abin´rio”, baseado em uma sequˆncia de divis˜es por 2. O resultado se obt´m tomando- a e o ese os restos das sucessivas divis˜es por 2 “ao contr´rio”, isto ´, do ultimo resto de o a e ´divis˜o por 2 at´ o primeiro. Por exemplo, tomando o decimal 22 como entrada: a e22 div 2 0 11 div 2 1 5 div 2 1 2 div 2 0 1 div 2 1 0 Ent˜o o n´mero bin´rio correspondente ao 22 seria 10110. O programa ilustrado a u ana figura 6.13 mostra o c´digo para esta vers˜o do algoritmo. o a Ocorre que este algoritmo imprime o bin´rio ao contr´rio, isto ´, a sa´ para a a a e ıdaentrada 22 seria 01101 e n˜o 10110 como deveria. Na verdade, basta lembrar que adesde o in´ deste texto se insiste em afirmar que para um mesmo problema existem ıciodiversas solu¸oes. Neste caso, basta usar a defini¸ao de n´meros bin´rios.1 c˜ c˜ u a De fato, o n´mero decimal 22 pode ser escrito numa s´rie de potˆncias de 2 como u e esegue: 22 = 1 × 24 + 0 × 23 + 1 × 22 + 1 × 21 + 0 × 20 1 Este exemplo nos ocorreu ap´s trocas de emails com o Allan Neves, ent˜o aluno da disciplina. o aAgradecemos a ele por isto.
    • 64 CAP´ ´ ITULO 6. TECNICAS ELEMENTARESprogram converteparabinario ;const max=128;var n: integer ;begin write (’entre com um numero entre 0 e 255: ’) ; read (n) ; while n < 0 do > begin write (n mod 2) ; n:= n div 2; end;end. Figura 6.13: Convertendo para bin´rio, vers˜o 1. a a A quest˜o ´ saber quantas vezes cada potˆncia de 2 cabe no n´mero original. Este a e e uc´lculo ´ simples e a solu¸˜o ´ mostrada na figura 6.14. a e ca eprogram converteparabinario ;const max=128;var diferenca , n, pot2 : integer ;begin write (’entre com um numero entre 0 e 255: ’) ; read (n) ; pot2:= max; while pot2 < 0 do > begin diferenca:= n − pot2 ; i f diferenca >= 0 then begin write (1) ; n:= diferenca ; end else write (0) ; pot2:= pot2 div 2; end;end. Figura 6.14: Convertendo para bin´rio, vers˜o 2. a a6.3.4 Menor de 3, segunda vers˜o aGeneralizando o problema de imprimir o menor entre trˆs n´meros de entrada, vamos e uagora ler uma sequˆncia de trincas de n´meros e imprimir, para cada entrada, o menor e udeles. A entrada termina quando os trˆs n´meros lidos forem iguais. Veja como fica e uo programa na figura 6.15.
    • ¸˜ ¸˜6.4. REPETICOES DENTRO DE CONDICOES 65program imprime menor (input , utput) ;var a , b, c : Integer;begin write(’Entre com tres numeros inteiros: ’) ; read(a , b, c) ; while not ((a = b) and (b = c) ) do (∗ falso quando a=b=c ∗) begin i f a < b then i f a < c then writeln (’o menor dos tres eh ’ ,a) else writeln (’o menor dos tres eh ’ , c) else i f a < c then writeln (’o menor dos tres eh ’ ,b) else writeln (’o menor dos tres eh ’ , c) write(’entre com tres numeros inteiros: ’) ; read(a , b, c) ; end;end. Figura 6.15: Imprimir o menor dentre 3 n´meros lidos. u6.4 Repeti¸˜es dentro de condi¸˜es co coOs problemas da se¸ao anterior envolveram a mesma estrutura b´sica, isto ´, um c˜ a eteste sob controle do comando de repeti¸˜o, com ou sem a parte else do if. Agora caveremos o contr´rio, isto ´, um comando de repeti¸ao no escopo do comando de desvio a e c˜condicional.6.4.1 Calculo do MDCProblema: Imprimir o M´ximo Divisor Comum (MDC) entre dois n´meros dados. a u O conceito matem´tico de m´ximo divisor comum entre dois n´meros dados a e b a a uenvolve a fatora¸ao de cada n´mero como um produto de fatores primos, escolhendo-se c˜ uos fatores primos que se repetem com a potˆncia m´ e ınima. Exemplo: Calcular o MDC entre 24 e 45. 72 = 23 × 32 135 = 33 × 5
    • 66 CAP´ ´ ITULO 6. TECNICAS ELEMENTARES Da teoria conclui-se que o MDC entre 72 e 135 ´ 32 , pois o 3 ´ o unico fator primo e e ´que se repete em ambos os n´meros de entrada, e a menor potˆncia comum ´ 2. u e e Implementar este algoritmo para encontrar o MDC ´ complicado no momento pois en˜o sabemos ainda como obter uma sequˆncia de primos. Tamb´m n˜o sabemos ainda a e e ao quanto caro ´ calcular um n´mero primo. e u Euclides propˆs um algoritmo eficiente para se obter o MDC entre dois n´meros o uque n˜o requer o uso da fatora¸ao. Trata-se de um dos primeiros algoritmos conheci- a c˜dos, pois foi proposto por volta do ano 300 a.c. O algoritmo pode ser visto atualmenteem Pascal conforme est´ ilustrado na figura 6.16. aprogram mdcporeuclides ;var a , b, resto : integer ;begin read (a ,b) ; i f (a < 0) A D (b < 0)) then > N > begin resto:= a mod b; while resto < 0 do > begin a:= b; b:= resto ; resto:= a mod b; end; writeln (’mdc = ’ , b) ; end else writeln (’o algoritmo nao funciona para entradas nulas.’) ;end. Figura 6.16: Algoritmo de Euclides para c´lculo do MDC. a Este algoritmo mostra um caso em que o comando de repeti¸ao est´ dentro do c˜ aescopo do comando de desvio condicional. Efetivamente os c´lculos s˜o feitos somente a ase as entradas n˜o forem nulas. a6.5 Repeti¸˜es aninhadas coNesta se¸ao estudaremos problemas para os quais os algoritmos exigem o aninhamento c˜de repeti¸˜es. co6.5.1 TabuadaProblema: Imprimir as tabuadas do 1 ao 10.
    • ¸˜6.5. REPETICOES ANINHADAS 67program tabuada ;var i , j : integer ;begin i:= 1; while i <= 10 do begin j:= 1; while j <= 10 do begin writeln ( i ,’x’ , j ,’= ’ , i ∗j ) ; (∗ comando mais interno ∗) j:= j + 1; end; writeln ; i:= i + 1; end;end. Figura 6.17: Tabuadas do 1 ao 10. No c´digo apresentado na figura 6.17, para cada valor de i, os valores de j variam ode 1 a 10, o que faz com que o comando writeln mais interno seja executado 100 vezesao longo do programa. Se fˆssemos imprimir a tabuada do 1 ao 1000, este comando oseria executado um milh˜o de vezes. Em termos gen´ricos, para uma entrada de a etamanho n, o comando mais interno ´ executado da ordem de n2 vezes, por isto s˜o e aconhecidos como algoritmos de complexidade quadr´tica. Nos programas anteriores, ao m´ximo que t´ a ınhamos era uma complexidade linear com rela¸˜o ao tamanho da caentrada.6.5.2 FatorialO problema seguinte ´ bastante relevante neste ponto, pois nos permitir´ uma an´lise e a asobre a t´cnica usada para resolvˆ-lo. A t´cnica b´sica implementa diretamente a e e e adefini¸ao de fatorial e usa uma estrutura baseada em um aninhamento triplo: um c˜desvio condicional no escopo de um aninhamento duplo.Problema: Imprimir o valor do fatorial de todos os n´meros entre 1 e n, sendo n ufornecido pelo usu´rio. a O fatorial de n ´ assim definido: e n = n × (n − 1) × (n − 2) × . . . × 3 × 2 × 1 Logo, o c´lculo do fatorial de um n´mero tem complexidade linear com rela¸ao ao a u c˜tamanho da entrada e pode ser facilmente implementado usando a t´cnica elementar edos acumuladores, conforme ´ ilustrado na figura 6.18. e
    • 68 CAP´ ´ ITULO 6. TECNICAS ELEMENTARESprogram fatorial ;var i , n, fat : integer ;begin read (n) ; fat:= 1; (∗ inicializacao do acumulador ∗) i:= n; while i >= 1 do begin fat:= fat ∗ i ; i f i > 1 then write ( i ,’x’) else write ( i ,’= ’) ; i:= i − 1; end; writeln ( fat ) ;end. Figura 6.18: Obtendo o fatorial de n. Esta vers˜o resolve o problema para o c´lculo do fatorial de um unico n´mero a a ´ udado como entrada e portanto n˜o resolve o enunciado. Por´m, basta colocar este a etrecho sob o controle de outra repeti¸ao que se obt´m o efeito desejado. A solu¸ao ´ c˜ e c˜ eapresentada na figura 6.19. ´ E verdade que o programa funciona, mas ´ extremamente ineficiente e repleto de ec´lculos redundantes. De fato, o usu´rio que testou o programa para o valor de n = 7 a avai perceber que a multiplica¸ao de 2 × 1 ocorreu 6 vezes, a multiplica¸ao de 3 × 2 c˜ c˜ocorreu 5 vezes, a de 4 × 6 ocorreu 4 vezes e assim por diante. O programador n˜o aexplorou corretamente os c´lculos j´ feitos anteriormente. i a a Em outras palavras, o programa pode ficar mais eficiente se for feito como ilustradona figura 6.20, de maneira que o algoritmo, mais esperto, tem complexidade linear, en˜o quadr´tica como na vers˜o anterior. Interessante observar que a solu¸ao, eficiente, a a a c˜usa apenas uma atribui¸ao no escopo de uma repeti¸ao. c˜ c˜
    • ¸˜6.5. REPETICOES ANINHADAS 69program fatorial1 n ;var cont , i , n, fat : integer ;begin read (n) ; cont:= 1; while cont <= n do begin fat:= 1; (∗ inicializacao do acumulador ∗) i:= cont ; while i >= 1 do begin fat:= fat ∗ i ; i f i > 1 then write ( i ,’x’) else write ( i ,’= ’) ; i:= i − 1; end; writeln ( fat ) ; cont:= cont + 1; end;end. Figura 6.19: Obtendo v´rios fatoriais. aprogram fatorial1 n ;var cont , n, fat : integer ;begin read (n) ; cont:= 1; fat:= 1; (∗ inicializacao do acumulador ∗) while cont <= n do begin fat:= fat ∗ cont ; writeln (’fat(’ ,cont ,’)= ’ , fat ) ; cont:= cont + 1; end;end. Figura 6.20: Otimizando o c´lculo dos fatoriais. a
    • 70 CAP´ ´ ITULO 6. TECNICAS ELEMENTARES6.6 Exerc´ ıcios 1. Dados o primeiro termo e a raz˜o de uma progress˜o aritm´tica, determinar a a a e soma dos seus primeiros cinco termos. 2. Ler um inteiro positivo N diferente de zero e calcular a soma: 13 + 23 + ... + N 3 . 3. Dados dois n´meros inteiros positivos determinar o valor da maior potˆncia do u e primeiro que divide o segundo. Se o primeiro n˜o divide o segundo, a maior a potˆncia ´ definida igual a 1. e e 4. Dados dois n´meros reais positivos determinar o quociente inteiro do primeiro u pelo segundo usando apenas os operadores aritm´ticos reais. e 5. Dado um n´mero real positivo determinar sua parte inteira e sua parte fra- u cion´ria usando apenas os operadores aritm´ticos reais. a e 6. Fazer um programa em Pascal que leia uma sequˆncia de pares de n´meros e u inteiros quaisquer, sendo dois inteiros por linha de entrada. A entrada de dados termina quando os dois n´meros lidos forem nulos. Este par de zeros n˜o deve u a ser processado e serve apenas para marcar o t´rmino da entrada de dados. e Para cada par A, B de n´meros lidos, se B for maior do que A, imprimir a u sequˆncia A, A + 1, . . . , B − 1, B. Caso contr´rio, imprimir a sequˆncia B, B + e a e 1, . . . , A − 1, A. Exemplos: Entrada Saida 4 6 4 5 6 -2 1 -2 -1 0 1 2 -3 2 1 0 -1 -2 -3 0 0 7. Um inteiro positivo N ´ perfeito se for igual a soma de seus divisores positivos e diferentes de N . Exemplo: 6 ´ perfeito pois 1 + 2 + 3 = 6 e 1, 2, 3 s˜o todos os divisores positivos e a de 6 e que s˜o diferentes de 6. a Fa¸a um programa em Pascal que recebe como entrada um n´mero positivo K c u e mostre os K primeiros n´meros perfeitos. u 8. Dadas as popula¸oes PA e PB de duas cidades A e B em 2009, e suas respectivas c˜ taxas de crescimento anual XA e XB , fa¸a um programa em Pascal que receba c estas informa¸oes como entrada e determine: c˜ • se a popula¸˜o da cidade de menor popula¸ao ultrapassar´ a de maior ca c˜ a popula¸ao; c˜ • e o ano em que isto ocorrer´. a
    • 6.6. EXERC´ ICIOS 71 9. Escreva um programa em Pascal para ler uma sequˆncia de n´meros inteiros, e u terminada em −1. Para cada n´mero inteiro lido, o programa deve verificar se u este n´mero est´ na base bin´ria, ou seja, se ´ composto apenas pelos d´ u a a e ıgitos 0 e 1. Caso o n´mero esteja na base bin´ria, o programa deve imprimir seu valor u a na base decimal. Caso contr´rio, deve imprimir uma mensagem indicando que a o n´mero n˜o ´ bin´rio. Ao final do programa deve ser impresso, em formato u a e a decimal, o maior n´mero v´lido (bin´rio) da sequˆncia. u a a e Dica: dado o n´mero 10011 em base bin´ria, seu valor correspondente em base u a decimal ser´ dado por a 1.24 + 0.23 + 0.22 + 1.21 + 1.20 = 19 Exemplo: Entrada: Saida: 10011 19 121 numero nao binario 1010 10 101010101 341 0 0 -1 O maior numero binario foi 341 10. Dado o programa abaixo, mostre o acompanhamento de sua execu¸˜o para trˆs ca e valores de entrada (valores pequenos). Em seguida, descreva o que o programa faz, comprovando suas afirma¸oes. c˜ program questao1(input , output) ; var x: integer ; y, m: longint ; begin read(x) ; y := 0; m := 1; while x > 0 do begin y := y + (x mod 2) ∗ m; x := x div 2; m := m ∗ 10; end; writeln(y) end. 11. Considere o seguinte c´digo fonte escrito em Pascal : o
    • 72 CAP´ ´ ITULO 6. TECNICAS ELEMENTARES program prova (input , output) ; var i , j , VAL, N: integer ; begin for i:= 1 to 4 do begin read (VAL) ; writeln (VAL, i ) ; for j:= 3 to 5 do begin read (VAL) ; N:= VAL + i −j ; writeln (VAL, j ,N) ; end; read (VAL) ; end; end. Suponha que vocˆ dˆ como entrada de dados uma sequˆncia crescente 1, 2, 3, e e e 4, . . . , na medida em que forem sendo executados os comandos “read”. Qual a sa´ que ser´ mostrada na tela do computador? ıda a 12. Fa¸a um programa em Pascal que, dada uma sequˆncia de n´meros naturais c e u positivos terminada por 0 (zero), imprimir o histograma da sequˆncia dividido e em quatro faixas (o histograma ´ a contagem do n´mero de elementos em cada e u faixa): • Faixa 1: 1 – 100; • Faixa 2: 101 – 250; • Faixa 3: 251 – 20000; • Faixa 4: acima de 20001. Exemplo: Entrada: 347 200 3 32000 400 10 20 25 0 Sa´da: Faixa 1: ı 4 Faixa 2: 1 Faixa 3: 2 Faixa 4: 1 13. Sabe-se que um n´mero da forma n3 ´ igual a soma de n n´meros ´ u e u ımpares consecutivos. Exemplos: • 13 = 1 • 23 = 3 + 5 • 33 = 7 + 9 + 11
    • 6.6. EXERC´ ICIOS 73 • 43 = 13 + 15 + 17 + 19 Dado M , escreva um program em Pascal que determine os ´ ımpares consecutivos 3 cuja soma ´ igual a n para n assumindo valores de 1 a M . e 14. Fa¸a um programa em Pascal que dado um inteiro positivo n, escreva todos c os termos, do primeiro ao n-´simo, da s´rie abaixo. Vocˆ pode assumir que o e e e usu´rio nunca digita valores menores que 1 para n. a 5, 6, 11, 12, 17, 18, 23, 24, . . . 15. Fa¸a um programa em Pascal que, dado dois n´mero naturais m e n determinar, c u entre todos os pares de n´meros naturais (x, y) tais que x <= m e y <= n, um u par para o qual o valor da express˜o xy − x2 + y seja m´ximo e calcular tamb´m a a e esse m´ximo. a 16. Leia do teclado uma sequˆncia de N > 0 n´meros quaisquer. Para cada valor e u lido, se ele for positivo, imprimir os primeiros 10 m´ltiplos dele. u
    • 74 CAP´ ´ ITULO 6. TECNICAS ELEMENTARES
    • Cap´ ıtulo 7Aplica¸oes das t´cnicas elementares c˜ eNeste cap´ıtulo vamos escrever solu¸oes para problemas cujo grau de dificuldade ´ c˜ esimilar aos dos problemas do cap´ ıtulo anterior, com o objetivo de fixar conceitos.Nestes problemas as t´cnicas devem ser combinadas com inteligˆncia, pios deve-se e epensar em como resolver problemas complexos usando-se apenas os elementos b´sicos. aA partir de agora omitiremos os cabe¸alhos dos programas em Pascal. c7.1 N´ meros de Fibonacci uEsta ´ uma das mais famosas sequˆncias de n´meros que existe. Trata-se dos n´meros e e u u 1de Fibonacci . Esta sequˆncia ´ gerada de modo bastante simples. Os dois primeiros e evalores s˜o 1 e 1. Os seguintes s˜o obtidos pela soma dos dois anteriores. Assim, a a asequˆncia de Fibonacci ´: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, . . . e eProblema: Imprimir os primeiros n´meros da sequˆncia de Fibonacci. u e Como gerar e imprimir os elementos desta sequˆncia ´ o nosso desafio. A solu¸ao e e c˜exige que se guarde sempre os dois ultimos elementos gerados, sen˜o n˜o ´ poss´ ´ a a e ıvelresolver o problema. Observamos que a frase do par´grafo anterior d´ a dica: “os a aseguintes s˜o obtidos pela soma dos dois anteriores”. a Na solu¸ao apresentada na figura 7.1 consideramos duas vari´veis importantes, c˜ auma para armazenar o ultimo elemento j´ produzido pelo algoritmo, a outra para ´ aguardar o pen´ltimo. Com estes dois, ´ poss´ u e ıvel produzir a soma deles, isto ´, o epr´ximo elemento. o A atualiza¸ao destas vari´veis deve ser feita sempre que o pr´ximo elemento for c˜ a oobtido, pois a soma do ultimo com o pen´ltimo ´ agora o ultimo elemento gerado. ´ u e ´O que era o ultimo passa a ser o pen´ltimo. A ordem da atualiza¸ao destes valo- ´ u c˜res ´ relevante no c´digo em fun¸˜o do esquema de funcionamento de mem´ria do e o ca ocomputador. Trocando-se a ordem dos comandos o algoritmo para de funcionar. O algoritmo da figura 7.1 ´ normalmente o mais utilizado para este problema, eisto ´, define-se os dois primeiros e depois sucessivamente soma-se os dois ultimos e e ´ 1 Vale a pena ler: http://pt.wikipedia.org/wiki/N´mero de Fibonacci. u 75
    • 76 CAP´ ¸˜ ´ ITULO 7. APLICACOES DAS TECNICAS ELEMENTARESconst max=93; (∗ A partir do 94o estoura a capacidade do tipo qword ∗)begin ultimo:= 1; (∗ inicializacao das variaveis principais ∗) penultimo:= 1; writeln (’1 ’ ,penultimo) ; (∗ imprime os dois primeiros valores ∗) writeln (’2 ’ ,ultimo) ; cont:= 3 ; (∗ calcula do terceiro em diante ∗) while cont <= max do begin soma:= penultimo + ultimo ; writeln (cont , ’ ’ ,soma) ; penultimo:= ultimo ; (∗ a ordem destes dois comandos ∗) ultimo:= soma; (∗ eh relevante no codigo ∗) cont:= cont + 1; end;end. Figura 7.1: Gerando n´meros da sequˆncia de Fibonacci. u eatualiza-se o ultimo como sendo esta soma recentemente gerada e o pen´ltimo como ´ usendo o que era o ultimo. Existem v´rios outros que s˜o apresentados como exerc´ ´ a a ıcios. Um problema similar mas alternativo a este ´, por exemplo, saber qual ´ o primeiro e en´mero de Fibonacci maior do que um determinado valor. Uma pequena altera¸ao u c˜no controle de parada e no local do comando de impress˜o resolve o novo problema. aIsto ´ apresentado na figura 7.2. A diferen¸a b´sica ´ que neste caso n˜o ´ preciso e c a e a econtar os n´meros, pois o crit´rio de parada ´ diferente. Mas ´ importante observar u e e eque a parte da gera¸ao dos n´meros da sequˆncia n˜o mudou. c˜ u e aconst max=1000;begin ultimo:= 1; (∗ inicializacao das variaveis principais ∗) penultimo:= 1; soma:= penultimo + ultimo ; while soma <= max do (∗ calcula do terceiro em diante ∗) begin penultimo:= ultimo ; ultimo:= soma; soma:= penultimo + ultimo ; end; writeln (soma) ;end. Figura 7.2: Imprimindo o primeiro n´mero de Fibonacci maior do que 1000. u Uma das maiores belezas dos n´meros de Fibonacci ´ que a raz˜o entre dois u e atermos consecutivos converge para um n´mero irracional conhecido como n´mero u ua´ureo (tamb´m podendo ter outros nomes parecidos). Tamb´m ´ denotado pela letra e e egrega ϕ e ´ aproximadamente 1.6180339887499. e
    • 7.2. MAIOR SEGMENTO CRESCENTE 77 De fato, vejamos a raz˜o entre dois termos consecutivos para alguns n´meros a upequenos: 1 2 3 5 8 13 21 = 1, = 2, = 1.5, = 1.66, = 1.60, = 1.625, = 1.615, . . . 1 1 2 3 5 8 13 O algoritmo que calcula o n´mero aureo com a precis˜o desejada, mostrando u ´ aos valores intermedi´rios, ´ apresentado na figura 7.3. Notamos que ele verifica a a econvergˆncia da sequˆncia para a raz˜o aurea, fazendo as contas at´ que o erro seja e e a ´ emenor que a precis˜o desejada. A fun¸˜o abs ´ nativa do Pascal e retorna o valor a ca eabsoluto do n´mero dado como argumento. u Neste exemplo, novamente o c´lculo central n˜o mudou, isto ´, os n´meros con- a a e utinuam a ser gerados da mesma maneira. O que muda ´ o que fazer com eles. No ecaso, ´ preciso obter a raz˜o do ultimo pelo pen´ltimo. Tamb´m ´ o primeiro exemplo e a ´ u e eapresentado que usa n´meros reais ao inv´s de inteiros. u econst PRECISAO=0.00000000000001;begin ultimo:= 1; (∗ inicializacao das variaveis principais ∗) penultimo:= 1; naureo anterior:= −1; (∗ para funcionar o primeiro teste ∗) naureo:= 1; writeln (naureo:15:14) ; (∗ calcula do terceiro em diante ∗) while abs(naureo − naureo anterior ) >= PRECISAO do begin soma:= penultimo + ultimo ; naureo anterior:= naureo ; naureo:= soma/ultimo ; writeln (naureo:15:14) ; penultimo:= ultimo ; ultimo:= soma; end;end. Figura 7.3: Verificando a convergˆncia do n´mero ´ureo. e u a V´rias outras propriedades interessantes ser˜o deixadas como exerc´ a a ıcio.7.2 Maior segmento crescenteProblema: Dada uma sequˆncia de n n´meros naturais, imprimir o valor do com- e uprimento do segmento crescente de tamanho m´ximo dentre os n´meros lidos. a u • Por exemplo, se a sequˆncia for: 5, 10, 3, 2, 4, 7, 9, 8, 5, o comprimento crescente e m´ximo ´ 4, pois ´ o tamanho do segmento 2, 4, 7, 9. a e e
    • 78 CAP´ ¸˜ ´ ITULO 7. APLICACOES DAS TECNICAS ELEMENTARES • Na sequˆncia 10, 8, 7, 5, 2, o comprimento de um segmento crescente m´ximo ´ e a e 1. O algoritmo que resolve este problema ´ apresentado na figura 7.4. A solu¸˜o exige e caum conjunto de vari´veis que controlam o estado da computa¸ao, isto ´, que tentam a c˜ emanter uma certa mem´ria de que tipo de n´meros foi lido at´ o momento, segundo o u euma dada restri¸ao. Os coment´rios no c´digo ilustram como guardar o tamanho da c˜ a osequˆncia sendo lida no momento em compara¸ao com o maior tamanho lido at´ o e c˜ emomento. Em um certo sentido guarda a mesma ideia do algoritmo para a sequˆncia de eFibonacci, pois ´ necess´rio guardar o valor lido anteriormente para possibilitar a e acompara¸ao com o valor atual. Isto ´ necess´rio para saber se o valor atual ´ maior c˜ e a eque o anterior. Se for maior, estamos em uma sequˆncia crescente. Caso contr´rio, e atrata-se de outra sequˆncia. A vari´vel tamanho armazena o tamanho da sequˆncia e a ecrescente sendo lida, enquanto que maiortam registra a maior sequˆncia crescente que ej´ foi processada at´ o momento. a ebegin read (n) ; (∗ inicializa as variaveis principais ∗) tamanho:= 0; maiortam:= 0; a anterior:= 0; (∗ zero eh o primeiro numero natural ∗) i:= 1; while i <= n do begin read (a) ; i f a > a anterior then tamanho:= tamanho + 1 else begin i f tamanho > maiortam then (∗ lembra o maior tamanho ∗) maiortam:= tamanho; tamanho:= 1; (∗ reinicializa o contador ∗) end; a anterior:= a ; (∗ lembra do numero anterior ∗) i:= i + 1; end; (∗ este ultimo i f testa se a ultima sequencia nao eh a maior ∗) i f tamanho > maiortam then (∗ lembra o maior tamanho ∗) maiortam:= tamanho; writeln (’maior tamanho encontrado: ’ ,maiortam) ;end. Figura 7.4: Maior segmento crescente.
    • ´7.3. SERIES 797.3 S´ries eNesta se¸ao tratamos de problemas que envolvem o c´lculo de s´ries, normalmente c˜ a eutilizadas para c´lculos de fun¸˜es tais como seno, cosseno, logaritmo, etc. . . A t´cnica a co eutilizada ´ basicamente aquela dos acumuladores, por´m, o c´lculo dos novos termos e e asomados ´ ligeiramente mais sofisticado e exige aten¸˜o do estudante para a boa e cacompreens˜o da solu¸ao. a c˜7.3.1 N´ mero neperiano uProblema: Calcular o valor no n´mero e = 2.718281 . . . pela s´rie abaixo, conside- u erando apenas os vinte primeiros termos: 1 1 1 1 1 1 1 1 e= + + + + + + + + ... 0! 1! 2! 3! 4! 5! 6! 7! A figura 7.5 ilustra uma solu¸˜o baseada nas j´ estudadas t´cnicas dos acumula- ca a edores e no problema dos fatoriais. Basicamente, o novo termo ´ calculado em fun¸ao e c˜do fatorial, que, neste caso, aparece no denominador.const itmax=20;begin e:= 0; (∗ inicializacao das variaveis ∗) fat:= 1; i:= 1; (∗ calculo da serie ∗) while i <= itmax do begin novotermo:= 1/fat ; e:= e + novotermo; fat:= i ∗fat ; i:= i + 1; end; writeln (’e= ’ , e) ;end. Figura 7.5: C´lculo do n´mero neperiano. a u O programa poderia ter dispensado o uso da vari´vel novotermo, mas deixamos aassim pois facilita a compreens˜o de que a grande e nova dificuldade neste problema a´ “como gerar o novo termo a partir do anterior”? Isto vai ajudar na solu¸˜o dee caproblemas similares, na sequˆncia do texto. e Neste caso, o enunciado do problema determinou que o programa calculasse 20termos da s´rie. Alguns enunciados estabelecem como condi¸˜o de parada um crit´rio e ca ede erro, isto ´, se o c´lculo em uma itera¸˜o difere do c´lculo anterior por um valor e a ca apreviamente estabelecido, isto ´, uma precis˜o previamente determinada. Em alguns e acasos, quando o c´lculo da s´rie n˜o ´ convergente, este valor m´ a e a e ınimo nunca ´ atingido, e
    • 80 CAP´ ¸˜ ´ ITULO 7. APLICACOES DAS TECNICAS ELEMENTARESobrigando tamb´m o programa a testar um n´mero m´ximo de itera¸˜es. Segue a e u a comesma ideia discutida no caso de gerar o n´mero ´ureo. u a Suponhamos que o enunciado tivesse como condi¸ao de parada um destes dois c˜crit´rios: ou o erro ´ menor do que 10−7 ou o n´mero m´ximo de itera¸oes ´ 50. e e u a c˜ eSe o programa sair pelo crit´rio de erro, ent˜o o valor de e foi encontrado, sen˜o, e a ase saiu pelo crit´rio do n´mero m´ximo de itera¸˜es, ent˜o o programa avisa que e u a co an˜o conseguiu encontrar a solu¸˜o. A figura 7.6 ilustra a solu¸ao para este caso. E a ca c˜ ´importante observar que o que muda com rela¸ao a primeira solu¸˜o ´ apenas o crit´rio c˜ ` ca e ede parada. Os c´lculos internos s˜o os mesmos. a aconst itmax=50; precisao=0.0001;begin e:= 0; eanterior:= −1; fat:= 1; i:= 1; while ( i <= itmax) and (e − eanterior > precisao ) do begin novotermo:= 1/fat ; eanterior:= e ; e:= e + novotermo; fat:= i ∗fat ; i:= i + 1; end; i f i >= itmax then writeln (’solucao nao encontrada’) else writeln (’e= ’ , e) ;end. Figura 7.6: C´lculo do n´mero neperiano. a u7.3.2 C´lculo do seno aProblema: Calcular o valor de seno(x) pela s´rie abaixo, considerando apenas os evinte primeiros termos: x x3 x5 x7 x9 x11 x13 x15 seno(x) = − + − + − + − + ... 1! 3! 5! 7! 9! 11! 13! 15! Comparando esta s´rie com a do n´mero neperiano, observamos trˆs diferen¸as e u e cb´sicas: a primeira ´ o sinal, que a cada termo muda de positivo para negativo e vice- a ee-versa e antes era sempre positivo; a segunda ´ o numerador, que antes era a constante e1, agora ´ uma potˆncia de x; a terceira ´ que os fatoriais n˜o s˜o consecutivos em e e e a acada termo, aumentam de dois em dois.
    • ´7.3. SERIES 81 Trataremos de cada caso separadamente, construindo a solu¸ao para o seno base- c˜ada na do n´mero neperiano. Vamos tratar primeiro o mais simples, que ´ a quest˜o u e ados sinais. Considere a seguinte s´rie: e 1 1 1 1 1 1 1 1 tmp = − + − + − + − + ... 0! 1! 2! 3! 4! 5! 6! 7! O algoritmo da figura 7.7 modifica o anterior pela introdu¸ao de uma nova vari´vel c˜ aque controla a mudan¸a do sinal, produzindo como sa´ o c´lculo da fun¸ao tmp. c ıda a c˜const itmax=20;begin seno:= 0; fat:= 1; sinal:= 1; i:= 1; while i <= itmax do begin novotermo:= 1/fat ; seno:= seno + sinal∗novotermo; sinal:= −sinal ; (∗ nova variavel para sinal trocado ∗) fat:= i ∗fat ; i:= i + 1; end; writeln (’tmp= ’ ,seno) ;end. Figura 7.7: S´rie com troca de sinais. e Agora vamos corrigir o denominador, obtendo a seguinte s´rie: e 1 1 1 1 1 1 1 1 tmp2 = − + − + − + − + ... 1! 3! 5! 7! 9! 11! 13! 15! A atualiza¸˜o da vari´vel f at deve ser modificada, conforme apontado na fi- ca agura 7.8: Agora s´ resta a atualiza¸˜o correta do numerador, que depende da leitura de um o cavalor x do teclado. Uma vari´vel adicional cont´m o valor de x2 , para evitar c´lculos a e aredundantes. O programa ilustrado na figura 7.9 implementa corretamente o c´lculoado seno(x) para um x dado em radianos. Existem v´rias outras s´ries que podem ser implementadas com estas mesmas a eideias, vamos deixar isto como exerc´ ıcio. Basicamente, basta o estudante observarcomo os numeradores e denominadores podem ser atualizados em fun¸ao do termo c˜anteriormente calculado.
    • 82 CAP´ ¸˜ ´ ITULO 7. APLICACOES DAS TECNICAS ELEMENTARESconst itmax=20;begin seno:= 0; fat:= 1; sinal:= 1; i:= 1; while i <= itmax do begin novotermo:= 1/fat ; seno:= seno + sinal∗novotermo; fat:= 2∗ i ∗(2∗ i+1)∗fat ; (∗ esta eh a princial modificacao ∗) sinal:= −sinal ; i:= i + 1; end; writeln (’tmp2= ’ ,seno) ;end. Figura 7.8: S´rie com troca de sinais e fatorais no denominador corrigidos. econst itmax=20;begin seno:= 0; fat:= 1; sinal:= 1; read (x) ; x quadrado:= x∗x; numerador:= x; i:= 1; while i <= itmax do begin novotermo:= numerador/fat ; (∗ atualiza o termo ∗) seno:= seno + sinal∗novotermo; numerador:= numerador∗x quadrado ; (∗ atualiza o numerador ∗) fat:= 2∗ i ∗(2∗ i+1)∗fat ; sinal:= −sinal ; i:= i + 1; end; writeln (’seno(’ ,x,’)= ’ ,seno) ;end. Figura 7.9: C´lculo do seno de x. a
    • ´7.4. NUMEROS PRIMOS 837.4 N´ meros primos uEste ´ um dos mais completos problemas desta parte inicial da disciplina. A solu¸˜o e cadele envolve diversos conceitos aprendidos e, de certa forma, permite o estabelecimentode um ponto de checagem no aprendizado.Problema: Dado um n´mero natural n, determinar se ele ´ primo. u e N´meros naturais primos s˜o aqueles que s˜o divis´ u a a ıveis apenas por ele mesmo epor 1. Em outras palavras, se n ´ um n´mero natural, ent˜o ele ´ primo se, e somente e u a ese, n˜o existe outro n´mero 1 < p < n que divida n. a u Os n´meros primos s˜o de particular interesse em computa¸˜o, sobretudo nos dias u a cade hoje, pois est˜o por tr´s dos principais algoritmos de criptografia e transmiss˜o a a asegura na Internet. Nesta se¸˜o vamos estudar alguns algoritmos para se determinar case um n´mero ´ ou n˜o primo. u e a Aplicando-se diretamente a defini¸˜o, temos que verificar se algum n´mero entre ca u2 e n − 1 divide n. Se p divide n ent˜o o resultado da opera¸˜o nmod p ´ zero. a ca e O primeiro algoritmo, apresentado na figura 7.10, ´ bastante simples: basta variar ep de 2 at´ n − 1 e contar todos os valores para os quais p divide n. Se a contagem for ezero, o n´mero n˜o tem divisores no intervalo e ´ portanto primo. Sen˜o n˜o ´. u a e a a ebegin read (n) ; cont:= 0; (∗ contador de divisores de n ∗) i:= 2; while i <= n−1 do begin i f n mod i = 0 then cont:= cont + 1; (∗ achou um divisor ∗) i:= i + 1; end; i f cont = 0 then writeln (n,’ eh primo’)end. Figura 7.10: Verifica se n ´ primo contando os divisores. e Este algoritmo ´ bom para se determinar quantos divisores primos um dado en´mero tem, mas n˜o ´ eficiente para este problema pois basta saber se existe pelo u a emenos um divisor. Logo, basta parar logo ap´s o primeiro divisor ter sido encontrado. o A t´cnica utilizada ´ baseada em uma vari´vel booleana inicializada como sendo e e averdadeira. O algoritmo “chuta” que n ´ primo mas, em seguida, se os c´lculos e amostrarem que o chute estava errado, a informa¸ao ´ corrigida. c˜ e O la¸o principal do programa deve ter duas condi¸˜es de parada: (1) termina c coquando um divisor foi encontrado; (2) termina quando nenhum divisor foi encontrado,isto ´, quando i ultrapassou n − 1. Um teste na sa´ do la¸o encontra o motivo da e ıda csa´ e imprime a resposta correta. Este algoritmo pode ser visto na figura 7.11. ıda
    • 84 CAP´ ¸˜ ´ ITULO 7. APLICACOES DAS TECNICAS ELEMENTARESbegin read (n) ; eh primo:= true; (∗ inicia chutando que n eh primo ∗) i:= 2; while ( i <= n−1) and eh primo do begin i f n mod i = 0 then eh primo:= false ; (∗ se nao for , corrige ∗) i:= i + 1; end; i f eh primo then writeln (n,’ eh primo’)end. Figura 7.11: Testa se n ´ primo parando no primeiro divisor. e A an´lise deste algoritmo deve ser feita em duas situa¸˜es: (1) no pior caso, aquele a coem que o n´mero ´ primo; (2) no melhor caso, aquele em que o n´mero n˜o ´ primo, u e u a ede preferˆncia um primo bem baixo. e No segundo caso, o algoritmo vai terminar bem r´pido. No outro, ele vai testar atodas as possibilidades de ´ımpares. Mas o caso otimo ´ raro. De fato, nos problemas ´ eenvolvendo criptografia, estes n´meros primos tem duzentos ou mais d´ u ıgitos. Istopode fazer com que o computador fique bastante tempo processando a informa¸˜o. ca Percebemos ent˜o que se o n´mero for par ent˜o s´ tem uma chance dele ser a u a otamb´m primo, justamente se o n´mero for o 2. No caso dos ´ e u ımpares ´ necess´rio que e atodos sejam testados. A figura 7.12 ilustra o programa que implementa este racioc´ ınio. O algoritmo testa inicialmente se o n´mero ´ par. Se for, testa se ´ o 2, que ´ u e e eprimo. Se for ´ımpar, testa todos os ´ımpares entre 1 e n − 1, eliminando metade dosc´lculos, pois os pares foram descartados. a Melhorou, mas pode melhorar mais com um pouco mais de observa¸ao: n˜o ´ c˜ a enecess´rio se testar todos os ´ a ımpares, basta que se teste at´ a raiz no n´mero. e u De fato, todo n´mero natural pode ser decomposto como um produto de n´meros u uprimos. Se a entrada n˜o for um primo, ent˜o pode ser decomposta, no melhor caso, a aassim: n = p ∗ p, em que p ´ primo. O algoritmo que implementa esta solu¸˜o ´ e ca emostrado na figura 7.13. Para se ter uma ideia do ganho, vejam na tabela seguinte o quanto se ganha comas trˆs ultimas vers˜es do programa. e ´ o x √ x 2 x 1000000 500000 1000 1000000000 500000000 31622 1000000000000 500000000000 1000000 A tabela acima mostra que para entradas da ordem de 1012 , o n´mero de c´lculos u a 12feitos com o programa da figura 7.11 pode ser da mesma ordem de 10 . Os c´lculos ado programa da figura 7.12 pode ser da ordem de 1011 (ganho pequeno), enquantoque na ultima vers˜o, ele pode fazer c´lculos da ordem de “apenas” 106 . ´ a a
    • ´7.4. NUMEROS PRIMOS 85begin read (n) ; eh primo:= true; (∗ inicia chutando que n eh primo ∗) i f n mod 2 = 0 then (∗ n eh par ∗) i f n < 2 then > eh primo:= false (∗ n nao eh 2 ∗) else eh primo:= true else (∗ n nao eh par , testar todos os impares ∗) begin i:= 3; while ( i <= n−1) and eh primo do begin i f n mod i = 0 then eh primo:= false ; (∗ achamos um divisor impar ∗) i:= i + 2; end; end; i f eh primo then writeln (n,’ eh primo’)end. Figura 7.12: Testa se n ´ primo, tratando os pares em separado. ebegin read (n) ; eh primo:= true; (∗ inicia chutando que n eh primo ∗) i f n mod 2 = 0 then (∗ n eh par ∗) i f n < 2 then > eh primo:= false (∗ n nao eh 2 ∗) else eh primo:= true else begin (∗ n nao eh par , testar todos os impares ∗) i:= 3; while ( i <= trunc( sqrt (n) ) ) and eh primo do begin i f n mod i = 0 then eh primo:= false ; (∗ achamos um divisor impar ∗) i:= i + 2; end; end; i f eh primo then writeln (n,’ eh primo’)end. Figura 7.13: Testa se n ´ primo parando na raiz de n. e
    • 86 CAP´ ¸˜ ´ ITULO 7. APLICACOES DAS TECNICAS ELEMENTARES7.5 Exerc´ ıcios 1. Dado um n´mero de trˆs d´ u e ıgitos, construir outro n´mero de quatro d´ u ıgitos com a seguinte regra: a) os trˆs primeiros d´ e ıgitos, contados da esquerda para a direita, s˜o iguais aos do n´mero dado; b) o quarto d´ a u ıgito e’ um d´ ıgito de controle calculado da seguinte forma: primeiro d´ ıgito + 3*segundo d´ıgito + 5*terceiro d´ ıgito; o d´ ıgito de controle ´ igual ao resto da divis˜o dessa soma por 7. e a 2. Dado um n´mero inteiro de cinco d´ u ıgitos representando um n´mero bin´rio, u a determinar seu valor equivalente em decimal. Por exemplo, se a entrada for 10001, a sa´ deve ser 17. ıda 3. Considere o programa feito para resolu¸ao do c´lculo do n´mero neperiano c˜ a u (se¸ao 7.3.1. Quantas opera¸oes de multiplica¸˜o sao executadas no seu pro- c˜ c˜ ca grama? (a) Considerando 20 termos. (b) Considerando N termos. 4. Considere a progress˜o geom´trica 1, 2, 4, 8, 16, 32, ... e um inteiro positivo N. a e Imprimir os N primeiros termos desta PG e a soma deles. 5. Imprimir os N primeiros termos das sequˆncias definidas pelas rela¸˜es de re- e co corrˆncia: e (a) Y (k + 1) = Y (k) + k, k = 1, 2, 3..., Y (1) = 1 (b) Y (k + 1) = Y (k) + (2k + 1), k = 0, 1, 2, 3..., Y (0) = 1 (c) Y (k + 1) = Y (k) + (3k 2 + 3k + 1), k = 0, 1, 2, 3..., Y (0) = 1 (d) Y (k + 1) = 2Y (k), k = 1, 2, 3..., Y (1) = 1 6. Dado um n´mero inteiro N , tabelar N [k] para k variando de 1 at´ N . Considere u e que, por defini¸˜o, X[k] = X(X − 1)(X − 2)(X − 3)...(X − k + 1), X sendo ca um n´mero real, k um natural diferente de zero e X[0] = 1. Observe que se u X = N = k, ent˜o N [N ] = N !. a 7. Sabe-se que o valor do coseno de 1 (um) radiano pode ser calculado pela s´rie e infinita abaixo: 1 x2 x4 x6 coseno(x) = − + − + ... 0! 2! 4! 6! Fazer um programa que calcule o valor do cosseno de x obtido pela s´rie acima e considerando apenas os primeiros 14 termos da mesma.
    • 7.5. EXERC´ ICIOS 87 8. Considere o conjunto C de todos os n´meros inteiros com quatro algarismos u distintos, ordenados segundo seus valores, em ordem crescente: C = {1023, 1024, 1025, 1026, 1027, 1028, 1029, 1032, 1034, 1035, . . . } Fa¸a um programa em Pascal que leia um n´mero N , pertencente a este con- c u junto, e imprima a posi¸ao deste n´mero no conjunto. c˜ u Exemplos: • Entrada: 1026 • Entrada: 9876 Sa´ ıda: 4 Sa´ ıda: 4536 • Entrada: 1034 • Entrada: 1243 Sa´ ıda: 9 Sa´ ıda: 72 9. Fa¸a um programa em Pascal que calcule e imprima o valor de f (x), onde x ∈ c ´ lido no teclado e: e 5x 6x2 11x3 12x4 17x5 18x6 f (x) = − + − + − + ... 2! 3! 4! 5! 6! 7! O c´lculo deve parar quando abs(f (xn+1 ) − f (xn )) < 0.00000001, onde abs(x) ´ a e a fun¸ao em Pascal que retorna o valor absoluto de x. c˜ 10. O n´mero ´ureo ϕ (1,6180339...) pode ser calculado atrav´s de express˜es com u a e o s´ries de fra¸oes sucessivas do tipo: e c˜ 1 ϕ1 = 1 + = 2 1 1 ϕ2 = 1+ = 1, 5 1+ 1 1 1 ϕ3 = 1+ 1 = 1, 666 1 + 1+ 1 1 1 ϕ4 = 1 + 1 = 1, 6 1+ 1+ 1 1 1+ 1 onde ϕi indica a aproxima¸ao do n´mero ´ureo com i fra¸oes sucessivas. Estes c˜ u a c˜ valores variam em torno do n´mero aureo, sendo maior ou menor alternada- u ´ mente, mas sempre se aproximando deste quando o n´mero de fra¸oes cresce. u c˜ Fa¸a um programa em Pascal que leia um n´mero N e imprima o valor da c u aproxima¸˜o do n´mero aureo ϕN , que usa uma s´rie de N fra¸oes sucessivas. ca u ´ e c˜ 11. Dado um inteiro positivo N e dada uma sequˆncia de N n´meros reais x1 , . . . , xn e u fa¸a um programa em Pascal que calcule o quociente da soma dos reais pelo seu c produto. Isto ´: e N i=1 xi q= N i=1 xi
    • 88 CAP´ ¸˜ ´ ITULO 7. APLICACOES DAS TECNICAS ELEMENTARES Como n˜o pode haver divis˜o por zero, seu programa deve parar t˜o logo esta a a a situa¸ao seja verificada indicando uma mensagem apropriada para o usu´rio. c˜ a 12. Em Pascal o tipo CHAR ´ enumer´vel, e portanto est´ na classe dos tipos e a a chamados de ordinais, conforme o guia de referˆncia da linguagem estudado em e aula. A ordem de cada caracter ´ dada pela tabela ASCII. Assim ´ poss´ e e ıvel, por exemplo, escrever trechos de c´dico tais como: o IF ’A’ > ’B’ THEN WRITE (’A eh maior que B’) ELSE WRITE (’A n~o eh maior que B’); a que produziria a mensagem “A n˜o eh maior que B”, pois na tabela ASCII o a s´ ımbolo “A” tem ordem 64 enquanto que “B” tem ordem 65. Ou ainda: FOR i:= ’a’ TO ’z’ DO WRITE (i); que produziria como sa´ “abcdefghijklmnopqrstuvxwyz”. ıda Fa¸a um programa em Pascal que leia seu nome completo (nomes completos em c geral) constitu´ ıdos por apenas letras mai´sculas entre “A” e “Z” e espa¸os em u c branco terminadas em “.” e que retorne o n´mero de vogais e consoantes neste u nome. Exemplos: Entrada: FABIANO SILVA. Sa´da: ı Vogais: 6 Consoantes: 6 Entrada: MARCOS ALEXANDRE CASTILHO. Sa´da: ı Vogais: 9 Consoantes: 14 13. Fa¸a um programa em Pascal que leia um inteiro positivo n, e escreva a soma c dos n primeiros termos da s´rie: e 1000 997 994 991 − + − + ... 1 2 3 4
    • 7.5. EXERC´ ICIOS 89 14. Dizemos que uma sequˆncia de inteiros ´ k-alternante se for composta alterna- e e damente por segmentos de n´meros pares de tamanho k e segmentos de n´meros u u ´ ımpares de tamanho k. Exemplos: A sequˆncia 1 3 6 8 9 11 2 4 1 7 6 8 ´ 2-alternante. e e A sequˆncia 2 1 4 7 8 9 12 ´ 1-alternante. e e A sequˆncia 1 3 5 ´ 3-alternante. e e Escreva um programa Pascal que verifica se uma sequˆncia de tamanho n ´ e e 10-alternante. O programa deve ler n, o tamanho da sequˆncia, no inic´ do e ıo programa e aceitar somente valores m´ltiplos de 10. A sa´ do programa deve u ıda ser a mensagem “A sequencia eh 10-alternante” caso a sequˆncia seja 10- e alternante e “A sequencia nao eh 10-alternante”, caso contr´rio. a 15. Fa¸a um programa em Pascal que calcule o resultado da seguinte s´rie: c e x0 x4 x8 x12 x16 S= − + − + − ... 2! 6! 10! 14! 18! 16. Fa¸a um programa em Pascal que receba como entrada um dado inteiro N e c o imprima como um produto de primos. Exemplos: 45 = 3 × 3 × 5. 56 = 2 × 2 × 2 × 7. 17. Fa¸a um programa em Pascal que calcule e escreva o valor de S assim definido: c 1 2 4 8 16 32 64 S= − + − + − + − ··· 1! 2! 3! 2! 1! 2! 3! 18. Fazer um programa em Pascal que calcule e escreva o valor de S: 37 × 38 36 × 37 35 × 36 1×2 S= + + + ··· + 1 2 3 37
    • 90 CAP´ ¸˜ ´ ITULO 7. APLICACOES DAS TECNICAS ELEMENTARES
    • Cap´ ıtulo 8Refinamentos sucessivosNeste ponto consideramos que o estudante j´ domina as estruturas elementares de acontrole de fluxo de execu¸˜o de um programa, ent˜o podemos aplicar estes conceitos ca aem alguns algoritmos mais sofisticados, isto ´, em problemas para os quais as solu¸oes e c˜envolvem generaliza¸˜es dos conte´dos previamente ministrados. co u A partir de agora, vamos construir os programas passo a passo, iniciando pelaapresenta¸˜o de um pseudo-c´digo, que ´ um algoritmo de mais alto n´ que nor- ca o e ıvelmalmente n˜o pode ser compilado, mas pode progressivamente ser detalhado at´ se a eobter o c´digo final compil´vel. o a Vamos tamb´m introduzir uma t´cnica de se isolar os subproblemas, de maneira a e edefinir blocos que realizam c´lculos bem definidos: integrando-se os diversos peda¸os, a cteremos a solu¸˜o global do problema. Tamb´m n˜o nos preocuparemos mais com os ca e acabe¸alhos dos programas. c8.1 Primos entre siProblema: Imprimir todos os pares de n´meros (a, b) que s˜o primos entre si para u atodo 2 ≤ a ≤ 100 e a ≤ b ≤ 100. Este problema pode ser dividido em dois sub-problemas: (1) dado um par den´meros quaisquer, como saber se eles s˜o primos entre si? (2) como gerar todos os u apares ordenados no intervalo desejado? Nosso conhecimento deveria ser suficiente para resolvermos o segundo sub-problema.Por este motivo vamos iniciar a tentativa de solu¸ao por ele, neste ponto ignorando c˜completamente o primeiro sub-problema. A solu¸ao poderia ser tal como mostrado na figura 8.1, a qual apresenta um c´digo c˜ oglobal que gera todos os pares ordenados que interessam, isto ´, tais que 2 ≤ a ≤ 100 ee a ≤ b ≤ 100. Na parte central do pseudo-c´digo existe um desvio condicional que n˜o est´ escrito o a aem forma de linguagem de programa¸˜o, mas que pode ser considerado como um teste cafeito atrav´s de um or´culo que, por sua vez, sabe responder sim ou n˜o se cada par e a a´ ou n˜o ´ constitu´ por pares de n´meros primo entre si.e a e ıdo u 91
    • 92 CAP´ ITULO 8. REFINAMENTOS SUCESSIVOSbegin i:= 2; while i <= 100 do begin j:= i ; (∗ para gerar pares com j sendo maior ou igual a i ∗) while j <= 100 do begin i f {i e j sao primos entre si} then writeln ( i , j ) ; (∗ oraculo ∗) j:= j + 1; end; i:= i + 1; end;end. Figura 8.1: Pseudo-c´digo para o problema dos pares entre si. o Agora basta transformar o or´culo em c´digo propriamente dito. Lembramos que a oa e b s˜o n´meros primos entre si quando o m´ximo divisor comum entre eles ´ 1. Isto a u a e´, mdc(a, b) = 1. Na se¸ao 6.4.1 vimos como se calcula de forma eficiente o MDC entree c˜dois n´meros pelo m´todo de Euclides (figura 6.16. A vers˜o final est´ na figura 8.2. u e a abegin i:= 2; while i <= 100 do begin j:= i ; while j <= 100 do begin a:= i ; b:= j ; (∗ inicio do bloco euclides ∗) resto:= a mod b; (∗ ∗ ∗) while resto < 0 do > (∗ ∗ ∗) begin (∗ ∗ ∗) a:= b; (∗ ∗ ∗) b:= resto ; (∗ ∗ ∗) resto:= a mod b; (∗ ∗ ∗) end; (∗ termino do bloco euclides ∗) i f b = 1 then writeln ( i , j ) ; (∗ b=1 era o oraculo ∗) j:= j + 1; end; i:= i + 1; end;end. Figura 8.2: Gerando todos os primos entre si. O teste b = 1 no final do c´digo, logo ap´s o bloco que calcula o MDC por Euclides, o o´ exatamente o teste que o or´culo fazia na vers˜o anterior. A diferen¸a entre os doise a a cc´digos ´ exatamente o trecho inserido em destaque. o e
    • ´8.2. AMIGOS QUADRATICOS 938.2 Amigos quadr´ticos aNeste problema poderemos explorar a busca por uma solu¸ao usando v´rios n´ c˜ a ıveisde detalhamento, come¸ando pelo pseudo-c´digo de mais alto n´ c o ıvel, passando porum outro pseudo-c´digo intermedi´rio e finalmente, atrav´s de mais um passo de o a erefinamento, obtendo o c´digo final. oProblema: Dois n´meros naturais n e m s˜o ditos amigos quadr´ticos quando n ´ u a a e 2 2igual a soma dos d´ ıgitos de m e ao mesmo tempo m ´ igual a soma dos d´ e ıgitos de n .Imprimir todos os pares n e m que s˜o amigos quadr´ticos no intervalo 1 ≤ 10000 ≤ n a ae 1 ≤ 10000 ≤ m. Por exemplo, os n´meros 13 e 16 s˜o amigos quadr´ticos, pois 132 = 169 e u a a 21+6+9=16. Por outro lado, 16 = 256 e 2+5+6=13. Novamente usaremos a t´cnica de se resolver o problema por partes. Vamos iniciar egerando os pares de n´meros dentro do intervalo desejado, conforme fizemos na se¸ao u c˜anterior. Para cada par, alguns or´culos nos auxiliar˜o na busca pela solu¸ao. O a a c˜pseudo-c´digo para isto est´ na figura 8.3. o abegin n:= 1; while n <= 10000 do begin m:= 1; while m<= 10000 do begin i f {m e n sao amigos quadraticos} then writeln(n,’ e ’ , m, ’ sao amigos quadraticos.’) ; m:= m + 1; end; n:= n + 1; end;end. Figura 8.3: Pseudo-c´digo para o problema dos amigos quadr´ticos. o a Agora podemos nos concentrar exclusivamente no problema de se determinar seum par de n´meros m e n s˜o amigos quadr´ticos. u a a Para isto temos que resolver mais um subproblema, pois a defini¸ao de amigos c˜quadr´ticos exige que a soma dos d´ a ıgitos de um n´mero ao quadrado tem que ser uigual a soma dos d´ıgitos do quadrado do outro n´mero. u Isto envolve decompor o quadrado de um n´mero qualquer na soma dos d´ u ıgitosque o comp˜e. Isto pode ser feito como na figura 8.4. o Finalmente temos um terceiro subproblema: como podemos separar os d´ ıgitos deum n´mero inteiro qualquer dado, para depois som´-los? A t´cnica usada explora u a ea opera¸˜o aritm´tica de se pegar o resto da divis˜o inteira por 10. Vejamos um ca e aexemplo para o n´mero 169. u
    • 94 CAP´ ITULO 8. REFINAMENTOS SUCESSIVOSbegin {dados n e m} soma n:= {oraculo que soma os digitos de n} ; soma m:= {oraculo que soma os digitos de m} ; i f soma n = soma m then {sao amigos quadraticos}end. Figura 8.4: Pseudo-c´digo para decidir sobre amigos quadr´ticos. o a169 div 10 9 16 div 10 6 1 div 10 1 0 No exemplo acima o n´mero 169 foi sucessivamente dividido por 10 at´ virar zero. u eOs restos das divis˜es por 10 nos d˜o os d´ o a ıgitos do 169, a saber, 9, 6 e 1, obtidos nestaordem. Isto est´ implementado conforme ilustrado na figura 8.5. abegin {dado n inteiro} while n < 0 do > begin digito:= n mod 10; n:= n div 10; end;end. Figura 8.5: Separando os d´ ıgitos de um dado n´mero n. u A vari´vel digito cont´m, a cada itera¸ao, um d´ a e c˜ ıgito que faz parte do n´mero dado. uPara se obter a soma, basta usar a t´cnica do acumulador, conforme a figura 8.6. ebegin {dado N inteiro} soma:= 0; while N < 0 do > begin digito:= N mod 10; soma:= soma + digito ; N:= N div 10; end;end. Figura 8.6: Somando os d´ ıgitos de um dado n´mero n. u Por ultimo, n˜o resta mais nada a n˜o ser juntar os diversos peda¸os de c´digo em ´ a a c oum unico programa que executa a tarefa com sucesso. Isto ´ mostrado na figura 8.7. O ´ eleitor deve estudar atentamente a maneira como os diversos c´digos foram integrados. o
    • ´8.2. AMIGOS QUADRATICOS 95begin n:= 1; while n <= 10000 do begin m:= 1; while m<= 10000 do begin (∗ decompoe n ao quadrado ∗) n2:= n∗n; soma dig n2:= 0; while n2 < 0 do > begin digito:= n2 mod 10; soma dig n2:= soma dig n2 + digito ; n2:= n2 div 10; end; (∗ decompoe m ao quadrado ∗) m2:= m∗m; soma dig m2:= 0; while m2 < 0 do > begin digito:= m2 mod 10; soma dig m2:= soma dig m2 + digito ; m2:= m2 div 10; end; i f (soma dig n2 = m) and (soma dig m2 = n) then writeln(n,’ e ’ , m, ’ sao amigos quadraticos.’) ; m:= m + 1; end; n:= n + 1; end;end. Figura 8.7: Verificando se n´meros n e m s˜o amigos quadr´ticos. u a a
    • 96 CAP´ ITULO 8. REFINAMENTOS SUCESSIVOS ´ E poss´ contudo fazer menos c´lculos e economizar um la¸o, reduzindo de um ıvel a cmilh˜o para mil opera¸˜es se, para cada n, testarmos se a soma dos seus d´ a co ıgitos aoquadrado pode ser transformado novamente em n. Veja o algoritmo da figura 8.8 ecompare com a vers˜o anterior. aprogram amigosquad;var n, m, n2, m2, soma dig n2 , soma dig m2, unidade : integer ;begin n:= 1; while n <= 10000 do begin (∗ decompoe n ao quadrado ∗) n2:= n∗n; soma dig n2:= 0; while n2 < 0 do > begin unidade:= n2 mod 10; soma dig n2:= soma dig n2 + unidade ; n2:= n2 div 10; end; m:= soma dig n2 ; i f soma dig n2 <= 1000 then (∗ se estiver na faixa permitida ∗) begin (∗ decompoe soma dig n2 ∗) m2:= m∗m; soma dig m2:= 0; while m2 < 0 do > begin unidade:= m2 mod 10; soma dig m2:= soma dig m2 + unidade ; m2:= m2 div 10; end; i f soma dig m2 = n then writeln(n,’ e ’ , m, ’ sao amigos quadraticos.’) ; end; n:= n + 1; end;end. Figura 8.8: Tornando amigos quadr´ticos mais eficiente. a8.3 Pal´ ındromosEste problema, e o da se¸ao seguinte, nos permitir´ entender melhor a t´cnica usada c˜ a ena se¸˜o anterior, a de se decompor um n´mero qualquer na sequˆncia de d´ ca u e ıgitos queo comp˜e para depois poder fazer algum c´lculo com eles. A ideia ´ que os dados o a e
    • 8.3. PAL´ INDROMOS 97de c´lculo do programa s˜o gerados ao inv´s de lidos do teclado. Esta ´ a diferen¸a a a e e cb´sica. aProblema: Imprimir todos os n´meros pal´ u ındromos entre 1 e 1000. N´meros pal´ u ındromos s˜o aqueles que s˜o lidos da direita para a esquerda da a amesma maneira que da esquerda para a direita. Por exemplo o n´mero 12321 ´ u epal´ ındromo, enquanto que 123 n˜o ´. a e O algoritmo apresentado na figura 8.9 mostra a solu¸˜o, que exige um aninhamento caduplo de comandos de repeti¸ao e um teste dentro de um deles. Ele testa todos os c˜n´meros e imprime quando s˜o pal´ u a ındromos. Para testar se um n´mero ´ pal´ u e ındromo usamos a seguinte t´cnica: separamos eos d´ıgitos do n´mero em quest˜o, em seguida reconstru´ u a ımos o n´mero ao contr´rio, u ausando a t´cnica do acumulador, e finalmente comparamos com o n´mero original. e u Lembrando que um n´mero da forma d0 d1 d2 . . . dn ´ escrito da seguinte forma: u e do × 100 + d1 × 101 + d2 × 102 + . . . + dn × 10n Para gerar o n´mero ao contr´rio basta fazer multiplica¸˜es sucessivas por 10 u a coinvertendo-se os d´ ıgitos, assim: do × 10n + d1 × 10n−1 + d2 × 10n−2 + . . . + dn × 100const max=1000;begin i:= 1; while i <= max do (∗ laco que controla os numeros entre 1 e max ∗) begin invertido:= 0; (∗ inicializa aculumador ∗) n:= i ; while n < 0 do > begin invertido:= invertido∗10 + n mod 10; n:= n div 10; end; (∗ imprime se for palindromo , senao nao faz nada ∗) i f invertido = i then writeln ( i ) ; i:= i + 1; end;end. Figura 8.9: Imprimindo todos os pal´ ındromos de 1 a 1000.
    • 98 CAP´ ITULO 8. REFINAMENTOS SUCESSIVOS Testar pal´ ındromos pode ser muito caro dependendo da aplica¸ao. Em todo caso, c˜apresentamos um problema no m´ ınimo divertido, que ´ o de gerar os pal´ e ındromos,assim evitando que todos os n´meros sejam testados. De qualquer forma, este pro- ublema serve para o estudante perceber melhor o uso de contadores em diversos n´ ıveisde aninhamentos de comandos de repeti¸ao. c˜Problema: Gerar todos os n´meros pal´ u ındromos entre 1 e 1000. O algoritmo apresentado na figura 8.10 cont´m a solu¸ao para este problema. Ele e c˜tem por base o formato dos pal´ındromos, gerando todos os de um d´ıgito, depois todosos de dois d´ ıgitos e finalmente todos os de 3 d´ ıgitos. Um exerc´ interessante seria ıciogeneralizar este c´digo, mas deixamos isto como exerc´ o ıcio.begin i:= 1; (∗ gerando todos de um digito ∗) while i <= 9 do begin writeln ( i ) ; i:= i + 1; end; pal:= 11; (∗ gerando todos de 2 digitos ∗) i:= 2; while i <= 10 do begin writeln (pal) ; pal:= i ∗ 11; i:= i + 1; end; i:= 1; (∗ gerando todos os de 3 digitos ∗) while i <= 9 do begin j:= 0; while j <= 9 do begin pal:= i ∗100 + j∗10 + i ; writeln (pal) ; j:= j + 1; end; i:= i + 1; end;end. Figura 8.10: Gerando todos os pal´ ındromos de 1 a 1000.
    • 8.4. INVERTER UM NUMERO DE TRES D´ ´ ˆ IGITOS 998.4 Inverter um n´ mero de trˆs d´ u e ıgitosO pr´ximo problema vai nos permitir refor¸ar o uso da t´cnica do acumulador ao o c emesmo tempo em que continuamos a mostrar v´rias solu¸oes para o mesmo problema a c˜de maneira a evoluirmos na compreens˜o da arte de se construir algoritmos. aProblema: Ler um n´mero de 3 d´ u ıgitos do teclado e imprimir este n´mero invertido. uExemplo, se a entrada for “123” (cento e vinte e trˆs) a sa´ deve ser “321” (trezentos e ıdae vinte e um). A primeira solu¸ao, apresentada na figura 8.11, foi feita pelos alunos em sala c˜ ´de aula em um curso no segundo semestre de 2002. E um bom exemplo de comoparticularizar a solu¸ao leva, quase que necessariamente, a dificuldades imensas na c˜reimplementa¸˜o do c´digo para problemas similares. ca obegin write(’entre com o numero de tres digitos: ’) ; readln(numero) ; centena:= numero div 100; dezena:= (numero mod 100) div 10; unidade:= numero mod 10; inverso := unidade∗100 + dezena∗10 + centena ; writeln( inverso ) ;end. Figura 8.11: Primeira solu¸˜o para inverter um n´mero de 3 d´ ca u ıgitos. Os estudantes propuseram esta solu¸ao por considerarem que o ser humano faz c˜mais ou menos do mesmo modo, isto ´, ele separa os d´ e ıgitos mentalmente lendo on´mero de tr´s para frente ao mesmo tempo que os escreve na ordem desejada. u a A solu¸˜o ent˜o parte do princ´ de, primeiro separar o n´mero dado na entrada ca a ıpio uem trˆs d´ e ıgitos para, depois, imprimi-los na ordem inversa. Assim, os operadoresde divis˜o e resto de divis˜o inteira s˜o utilizados para a separa¸ao dos n´meros em a a a c˜ uunidade, dezena e centena. O programa funciona, ´ verdade, mas tem um grave problema. Ele s´ funciona e opara n´meros com 3 d´ u ıgitos. Se fosse pedido para resolver o mesmo problema paraum n´mero de 4 d´ u ıgitos, ent˜o a implementa¸˜o do mesmo m´todo implicaria na total a ca ereconstru¸ao do c´digo acima. Isto ´, ´ como se tiv´ssemos um novo problema para c˜ o e e eser resolvido e nunca tiv´ssemos pensado em nenhuma solu¸˜o parecida, o que n˜o ´ e ca a everdade. O c´digo da figura 8.12 ilustra a adapta¸ao desta mesma ideia, desta vez para 4 o c˜d´ıgitos. Al´m de ter que declarar mais uma vari´vel (milhar), houve altera¸˜o de prati- e a cacamente todas as linhas do c´digo. Aparentemente, separar a unidade e o primeiro od´ıgito (no caso o milhar) ´ f´cil, bastando uma divis˜o inteira por 10 e um resto de e a adivis˜o inteira por 10. Mas calcular a dezena e a centena come¸a a ficar complicado. a c ´ poss´ E ıvel imaginar o estrago no c´digo se for exigido que a entrada seja cons- otitu´ de 10 d´ ıda ıgitos ou mais, o que nos permite perceber claramente a dificuldade na
    • 100 CAP´ ITULO 8. REFINAMENTOS SUCESSIVOSbegin write(’entre com o numero de quatro digitos: ’) ; readln(numero) ; milhar:= numero div 1000; centena:= (numero mod 1000) div 100; dezena:= (numero mod 100) div 10; unidade:= numero mod 10; inverso := unidade∗1000 + dezena∗100 + centena∗10 + milhar ; writeln( inverso ) ;end. Figura 8.12: Mesmo algoritmo, agora para 4 d´ ıgitos.adapta¸ao da solu¸˜o ao mesmo tempo em que se percebe que, para o computador, c˜ canem sempre ´ f´cil resolver problemas da mesma maneira como o ser humano faria. e a Novamente, ´ preciso deixar que o computador fa¸a o trabalho, n˜o o programador. e c aSe este ultimo for esperto o suficiente, far´ um c´digo baseado num algoritmo mais ´ a oelaborado. Provavelmente o algoritmo n˜o ser´ mais t˜o intuitivo, mas se for bem a a afeito, vai nos permitir generalizar o c´digo para entradas de qualquer tamanho. o O que queremos aqui, assim como no problema da se¸˜o anterior, ´ tentar perceber ca ealgum racioc´ ınio que possa ser repetido um n´mero controlado de vezes. Deve-se utentar explorar uma mesma sequˆncia de opera¸˜es, que consiste em separar o ultimo e co ´d´ıgito e remover do n´mero original este d´ u ıgito que foi separado. Desta forma, a constru¸ao da resposta n˜o pode mais ser feita apenas no final do c˜ aalgoritmo. A ` medida que o n´mero original vai sendo separado, o seu inverso j´ deve u air sendo constru´ ıdo, tal como foi feito nas duas se¸oes anteriores. O c´digo final ´ c˜ o eapresentado na figura 8.13.begin write(’entre com o numero de tres digitos: ’) ; readln(numero) ; inverso := 0; i:= 1; while ( i <= 3) do begin unidade := numero mod 10; resto := numero div 10; inverso := inverso∗10 + unidade ; numero := resto ; i:= i + 1; end; writeln( inverso ) ;end. Figura 8.13: Solu¸ao com uso de acumuladores. c˜
    • ´ ¸˜8.5. CALCULO DO MDC PELA DEFINICAO 1018.5 C´lculo do MDC pela defini¸˜o a caNesta se¸ao apresentaremos a solu¸˜o do problema do MDC calculado pela defini¸ao. c˜ ca c˜O objetivo ´ motivar o cap´ e ıtulo seguinte, uma vez que sabemos que existe um algo-ritmo melhor, estudado na se¸ao 6.16. c˜ O MDC entre dois inteiros a e b foi definido matematicamente na se¸ao 6.4.1 e c˜envolve a fatora¸˜o de ambas as entradas como um produto de n´meros primos. O ca ualgoritmo b´sico, em pseudo-c´digo ´ apresentado na figura 8.14. a o ebegin read (a ,b) ; mdc:= 1; (∗ descobre quantas vezes o 2 divide as duas entradas ∗) cont a:= {numero de vezes que o 2 divide a} ; cont b:= {numero de vezes que o 2 divide b} ; menor cont:= {menor entre cont a e cont b} ; mdc:= mdc ∗ {2 elevado a potencia menor cont} ; a:= a div mdc; b:= b div mdc; (∗ repete o processo para todos os impares ∗) primo:= 3; while (a < 1) and (b < 1) do > > begin cont a:= {numero de vezes que primo divide a} cont b:= {numero de vezes que primo divide b} menor cont:= {menor entre cont a e cont b} ; mdc:= mdc ∗ {primo elevado a potencia menor cont} ; a:= a div mdc; b:= b div mdc; primo:= primo + 2; (∗ passa para o proximo impar ∗) end; writeln (mdc) ;end. Figura 8.14: Pseudo-c´digo para o calculo do MDC pela defini¸ao. o c˜ O princ´ ıpio do algoritmo ´ verificar quantas vezes cada n´mero primo divide as e uentradas e descobrir qual deles ´ o menor. O MDC ´ atualizado ent˜o para menor e e apotˆncia deste primo. E e ´ preciso separar o caso do 2 dos outros, por motivos que j´ adiscutimos. Os valores de a e de b s˜o atualizados, para n˜o haver c´lculos in´teis a a a ucom os ´ımpares m´ltiplos de primos que j´ foram previamente processados. u a O programa que implementa este algoritmo n˜o cabe em uma p´gina, por isto ´ a a eapresentado em duas partes nas figuras 8.15 e 8.16. Neste ponto deixamos claro ao leitor o motivo da apresenta¸ao deste problema c˜no final deste cap´ıtulo: este c´digo tem um n´ o ıvel muito alto de trechos de c´digo obastante parecidos. Observamos que, em quatro vezes, se calcula quantas vezes um
    • 102 CAP´ ITULO 8. REFINAMENTOS SUCESSIVOSdado primo p divide um n´mero n. Ainda, a atualiza¸˜o do MDC tamb´m aparece u ca eem dois trechos diferentes mas bastante similares. O reaproveitamento de c´digo ´ uma das motiva¸˜es para o uso de subprogramas o e conas linguagens de alto n´ ıvel. Mas n˜o ´ a unica, existem outras motiva¸˜es. No a e ´ copr´ximo cap´ o ıtulo vamos introduzir as importantes no¸˜es de procedure e function em coPascal, e poderemos reescrever o c´digo acima com muito mais elegˆncia. o abegin (∗ inicializacao das variaveis principais ∗) read (a ,b) ; mdc:= 1; (∗ descobre quantas vezes o 2 divide as duas entradas ∗) cont a:= 0; while a mod 2 = 0 do begin cont a:= cont a + 1; a:= a div 2; end; cont b:= 0; while b mod 2 = 0 do begin cont b:= cont b + 1; b:= b div 2; end; (∗ descobre qual dos contadores eh o menor ∗) i f cont a <= cont b then menor cont:= cont a else menor cont:= cont b ; (∗ atualiza o mdc para o 2 ∗) i:= 1; while i <= menor cont do begin mdc:= mdc ∗ 2; i:= i + 1; end; Figura 8.15: Calcula MDC entre a e b pela defini¸˜o (caso primo=2). ca
    • ´ ¸˜8.5. CALCULO DO MDC PELA DEFINICAO 103 (∗ repete o processo para todos os impares ∗) primo:= 3; while (a < 1) and (b < 1) do > > begin cont a:= 0; while a mod primo = 0 do begin cont a:= cont a + 1; a:= a div primo ; end; cont b:= 0; while b mod primo = 0 do begin cont b:= cont b + 1; b:= b div primo ; end; (∗ descobre qual dos contadores eh o menor ∗) i f cont a <= cont b then menor cont:= cont a else menor cont:= cont b ; (∗ atualiza o mdc para o primo impar da vez ∗) i:= 1; while i <= menor cont do begin mdc:= mdc ∗ primo ; i:= i + 1; end; (∗ passa para o proximo impar ∗) primo:= primo + 2; end; (∗ imprime o resultado final ∗) writeln (mdc) ;end. Figura 8.16: Calcula MDC entre a e b pela defini¸˜o (caso primo ´ ´ ca e ımpar).
    • 104 CAP´ ITULO 8. REFINAMENTOS SUCESSIVOS8.6 Exerc´ ıcios 1. Fazer um programa em Pascal que leia do teclado dois n´meros inteiros posi- u tivos e que imprima na sa´ um unico n´mero inteiro que ´ a soma dos dois ıda ´ u e primeiros. Entretanto, seu programa n˜o pode utilizar o operador de soma (+) a da linguagem Pascal para somar os dois inteiros lidos em uma unica opera¸ao. ´ c˜ Outrossim, o programa deve implementar a soma dos n´meros d´ u ıgito a d´ ıgito, iniciando pelo menos significativo at´ o mais significativo, considerando o “vai e um”, conforme costumamos fazer manualmente desde o ensino fundamental. Exemplo 1 Exemplo 2 11 ("vai um") 1111 ("vai um") 40912 (primeiro n´mero) u 52986 (primeiro n´mero) u 1093 (segundo n´mero) u 1058021 (segundo n´mero) u ----- ------- 42005 (soma) 1111007 (soma) 2. Um agricultor possui 1 (uma) espiga de milho. Cada espiga tem 150 gr˜os, e cada a gr˜o pesa 1g (um grama). Escreva um programa em Pascal para determinar a quantos anos ser˜o necess´rios para que o agricultor colha mais de cem toneladas a a de milho (1T = 1000Kg, 1Kg = 1000g), sendo que: • A cada ano ele planta todos os gr˜os da colheita anterior a • H´ apenas uma colheita por ano a • 10% (dez por cento) dos gr˜os n˜o germina (morre sem produzir) a a • Cada gr˜o que germina produz duas espigas de milho a Assuma que a quantidade de terra dispon´ ´ sempre suficiente para o plantio. ıvel e 3. Modifique a quest˜o anterior acrescentando na simula¸ao os seguintes fatos: a c˜ • H´ 8 (oito) CASAIS de pombas (16 pombas) que moram na propriedade a do agricultor. • Cada pomba come 30 gr˜os por dia, durante os 30 dias do ano em que as a espigas est˜o formadas antes da colheita; a • A cada ano, cada casal gera 2 novos casais (4 pombas), que se alimentar˜o a e reproduzir˜o no ano seguinte; a • Uma pomba vive tres anos; Ao final do programa, imprima tamb´m o n´mero de pombas que vivem na e u propriedade quando o agricultor colher mais de 100T de milho
    • 8.6. EXERC´ ICIOS 105 4. Considere um n´mero inteiro com 9 d´ u ıgitos. Suponha que o ultimo d´ ´ ıgito seja o “d´ ıgito verificador” do n´mero formado pelos 8 primeiros. Fa¸a um programa u c em Pascal que leia uma massa de dados terminada por 0 (zero) e que imprima os n´meros que n˜o s˜o bem formados, isto ´, aqueles que n˜o satisfazem o d´ u a a e a ıgito verificador. Implemente o seguinte algoritmo para gerar o d´ ıgito verificador: Conforme o esquema abaixo, cada d´ ıgito do n´mero, come¸ando da direita para u c a esquerda (menos significativo para o mais significativo) ´ multiplicado, na e ordem, por 2, depois 1, depois 2, depois 1 e assim sucessivamente. N´mero exemplo: 261533-4 u +---+---+---+---+---+---+ +---+ | 2 | 6 | 1 | 5 | 3 | 3 | - | 4 | +---+---+---+---+---+---+ +---+ | | | | | | x1 x2 x1 x2 x1 x2 | | | | | | =2 =12 =1 =10 =3 =6 +---+---+---+---+---+-> = (16 / 10) = 1, resto 6 => DV = (10 - 6) = 4 Ao inv´s de ser feita a somat´ria das multiplica¸oes, ser´ feita a somat´ria e o c˜ a o dos d´ ıgitos das multiplica¸oes (se uma multiplica¸ao der 12, por exemplo, ser´ c˜ c˜ a somado 1 + 2 = 3). A somat´ria ser´ dividida por 10 e se o resto (m´dulo 10) for diferente de zero, o a o o d´ ıgito ser´ 10 menos este valor. a 5. Escreva um programa Pascal que leia dois valores inteiros positivos A e B. Se A for igual a B, devem ser lidos novos valores at´ que sejam informados valores e distintos. Se A for menor que B, o programa deve calcular e escrever a soma dos n´meros ´ u ımpares existentes entre A(inclusive) e B(inclusive). Se A for maior que B, o programa deve calcular e escrever a m´dia aritm´tica dos m´ltiplos de e e u 3 existentes entre A(inclusive) e B(inclusive). 6. Fa¸a um programa em Pascal que dado uma sequˆncia de n´meros inteiros c e u terminada por zero (0), determinar quantos segmentos de n´meros iguais con- u secutivos comp˜em essa sequˆncia. o e Ex.: A sequˆncia 2,2,3,3,5,1,1,1 ´ formada por 4 segmentos de n´meros iguais. e e u 7. Fa¸a um programa em Pascal que imprima a seguinte sequˆncia de n´meros: 1, c e u 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, . . . 8. Fa¸a um programa em Pascal que receba como entrada um dado inteiro N e c o imprima como um produto de primos. Exemplos: 45 = 3 × 3 × 5. 56 = 2 × 2 × 2 × 7.
    • 106 CAP´ ITULO 8. REFINAMENTOS SUCESSIVOS 9. Fa¸a um programa em Pascal que, dado um n´mero inteiro N , escreva o maior c u divisor de N que ´ uma potˆncia de um dos n´meros primos fatorados. Ex: e e u N = 45 = 32 .51 escreve 9 = 32 N = 145 = 52 .71 escreve 25 = 52 N = 5616 = 24 .33 .13 escreve 27 = 33
    • Cap´ ıtulo 9Fun¸˜es e procedimentos coAt´ agora vimos as no¸˜es b´sicas de algoritmos, fundamentalmente como funciona e co ao computador de verdade (modelo Von Neumann) e como isto pode ter uma repre-senta¸˜o em um n´ mais alto, guardadas as limita¸˜es da m´quina. ca ıvel co a A maneira de se resolver problemas do ponto de vista algoritmico envolve a ela-bora¸ao de constru¸oes com apenas quatro tipos de estruturas de controle de fluxo: c˜ c˜comandos de entrada e sa´ ıda, comandos de atribui¸ao, comandos de repeti¸˜o e co- c˜ camandos de desvio condicional, al´m do uso de express˜es l´gicas e aritm´ticas. Para e o o ea efetiva programa¸ao ainda ´ necess´rio dominar a arte de escrever os algoritmos em c˜ e afun¸ao das limita¸˜es dos compiladores. c˜ co O problema ´ que a medida em que os problemas exigem c´digos com muitas e ` olinhas, os programas gerados v˜o se tornando cada vez mais complexos tanto para aserem desenvolvidos quanto para serem mantidos em funcionamento. O exemplo dofinal do cap´ıtulo anterior d´ uma ideia dessa dificuldade. a Por isto, os programas devem ser constru´ ıdos de maneira a facilitar o trabalhodos programadores e analistas. E ´ preciso que os c´digos sejam elaborados com partes obem definidas, em m´dulos que contenham peda¸os coerentes do problema geral que o cse est´ tentando modelar. As no¸˜es de fun¸oes e procedimentos s˜o o caminho para a co c˜ ase construir c´digos elegantes, robustos e de f´cil manuten¸˜o. o a ca9.1 Motiva¸˜o caOs procedimentos e fun¸˜es s˜o nada mais do que subprogramas, isto ´, peda¸os de co a e cprogramas dentro de programas. Mas, bem explorados, permitem a constru¸ao dec˜c´digos altamente elaborados. Existem trˆs motiva¸˜es para se usar subprogramas: o e co • modularidade; • reaproveitamento de c´digo; o • legibilidade do c´digo. o Vamos detalhar cada t´pico nos pr´ximos itens. o o 107
    • 108 CAP´ ¸˜ ITULO 9. FUNCOES E PROCEDIMENTOS9.1.1 ModularidadeA no¸ao de modularidade ´ relacionada com a capacidade de se escrever programas c˜ eem peda¸os de c´digo que executam opera¸˜es bem definidas. Cada m´dulo possui c o co ovari´veis e estruturas pr´prias, independentes do restante do programa. A ideia ´ que a o emodifica¸oes em trechos de c´digo (necess´rias para manuten¸˜o e continuidade de c˜ o a cadesenvolvimento) n˜o causem reflexos no comportamento do resto do programa. a ´ a E f´cil conceber um programa dividido em trˆs partes: entrada de dados, c´lculos e e aimpress˜o dos resultados. Uma entrada de dados textual poderia ser modificada para aoutra em modo gr´fico sem que o peda¸o que faz os c´lculos perceba a modifica¸ao. a c a c˜Idem para a sa´ de dados. Mesmo nos c´lculos, pode-se mudar toda uma estrutura ıda ado programa e garantir que a entrada e sa´ v˜o continuar a se comportar como ıda aantes. Isto ´ tarefa ´rdua sem o uso de fun¸˜es e procedimentos. e a co ´ importante notar que a linguagem Pascal n˜o fornece todos os meios para se E aimplementar um programa totalmente modular, mas ´ o suficiente para os estudantes eem primeiro curso de computa¸ao perceberem a importˆncia do conceito. Na verdade, c˜ aa evolu¸ao destas ideias deu origem ao conceito de Programa¸ao Orientada a Objetos, c˜ c˜hoje na moda. Mas isto ´ tema para outras disciplinas. e9.1.2 Reaproveitamento de c´digo oVez por outra nos deparamos com situa¸˜es onde temos que escrever c´digos muito, co omas muito, parecidos em trechos diferentes do programa. As vezes a diferen¸a de um cpara outro ´ quest˜o de uma ou outra vari´vel que muda. Ocorre frequentemente que e a ao trecho ´ exatamente o mesmo. e Ent˜o faz sentido que possamos estruturar o c´digo repetido de maneira a cons- a otituir um subprograma e, no programa propriamente dito, fazer o c´digo do subpro- ograma ser executado para diferentes valores de vari´veis. Isto provoca uma grande aeconomia de c´digo escrito, ao mesmo tempo em que facilita a manuten¸˜o do pro- o cagrama.9.1.3 LegibilidadeOs dois aspectos acima, somados com o bom uso de nomes apropriados para os iden-tificadores, endenta¸ao e uso racional de coment´rios no c´digo, implicam necessari- c˜ a oamente em um c´digo leg´ o ıvel, isto ´, compreens´ para quem o lˆ e at´ mesmo para e ıvel e equem o escreveu.1 De fato, ´ comum algu´m fazer um programa, as vezes simples, e depois de alguns e emeses ler o c´digo e n˜o entender o que l´ est´ escrito. Um c´digo leg´ permite o a a a o ıveluma r´pida compreens˜o e viabiliza sua manuten¸ao, corre¸ao e expans˜o, seja pelo a a c˜ c˜ apr´prio programador ou por outras pessoas. o 1 Recomendamos a leitura do mini-guia da linguagem Pascal, dipon´ no site oficial da disciplina ıvelCI055.
    • ¸˜9.2. NOCOES FUNDAMENTAIS 1099.1.4 Coment´rio adicional aNesta se¸ao, vamos tentar convencer o aprendiz a usar bem e a dar valor a estas c˜no¸oes, estudando exemplos simples, mas did´ticos. c˜ a9.2 No¸˜es fundamentais coExistem trˆs conceitos que devem ser dominados pelo estudante: e 1. quando usar fun¸˜o e quando usar procedimento? ca 2. quando usar vari´veis locais ou vari´veis globais? a a 3. quando usar passagem de parˆmetros por valor ou por referˆncia? a e Nas pr´ximas se¸oes vamos detalhar cada um destes itens. o c˜9.2.1 Exemplo b´sico aVamos tomar como base um programa bem simples, estudado nas primeiras aulasdesta disciplina. Trata-se do problema de se ler uma sequˆncia de valores inteiros eterminada por zero e que imprima somente aqueles que s˜o pares. a Quando resolvemos este problema, o c´digo foi escrito como na figura 9.1. oprogram imprime pares ;var a : integer ;begin read (a) ; while a < 0 do > begin i f a mod 2 = 0 then writeln (a) ; read (a) ; end;end. Figura 9.1: Programa que imprime os n´meros da entrada que s˜o pares. u a9.2.2 O programa principal´E o c´digo do programa propriamente dito. Tem in´ no begin e t´rmino no end. o ıcio e No exemplo anterior, s˜o todos os comandos que aparecem no programa, desde ao de leitura da vari´vel a at´ o end ; do comando while. O resto que l´ aparece ´ o a e a ecabe¸alho do programa e a declara¸ao de vari´veis globais. c c˜ a
    • 110 CAP´ ¸˜ ITULO 9. FUNCOES E PROCEDIMENTOS9.2.3 Vari´veis globais aS˜o todas as vari´veis declaradas logo ap´s o cabe¸alho do programa, antes do begin a a o cdo programa principal. Como sabemos, vari´veis s˜o abstra¸˜es de endere¸os de mem´ria. As vari´veis a a co c o aglobais s˜o endere¸os vis´ a c ıveis em todo o programa, mesmo nos subprogramas, comoveremos logo mais. No exemplo acima, existe uma unica vari´vel global, ela tem o identificador a e ´ ´ a edo tipo integer.9.2.4 Fun¸˜es coNo miolo do programa exemplo, existe um trecho onde se lˆ: a mod 2 = 0. Hoje esabemos que isto ´ uma express˜o booleana que calcula o resto da divis˜o inteira de e a aa por 2, se o resultado for zero ent˜o a ´ par, sen˜o ´ impar. Mas, esta express˜o a e a e apoderia ser bem mais complexa, exigindo muitas linhas de c´digo, por exemplo, se oquis´ssemos imprimir os n´meros que fossem primos ao inv´s dos pares. e u e O importante ´ que a express˜o booleana resulta em um valor do tipo booleano. e aO mesmo efeito pode ser conseguido com uma fun¸ao que resulta em um valor do tipo c˜booleano. Isto pode ser feito definindo-se um subprograma que ´ chamado pelo programa eprincipal e que recebe os dados necess´rios para os c´lculos (os parˆmetros). Os a a ac´lculos devem computar corretamente se o n´mero enviado pelo programa principal a u´ par. Se for, de alguma maneira deve retornar um valor true para quem chamou. Seen˜o for, deve retornar false. a O que acaba de ser escrito estabelece uma esp´cie de “contrato” entre o programa eprincipal e o subprograma. Em termos de linguagem de programa¸˜o, este contrato ´ ca edenominado de prot´tipo ou assinatura da fun¸ao. Ele ´ constitu´ por trˆs coisas: o c˜ e ıdo e • O nome da fun¸ao; c˜ • A lista de parˆmetros, que s˜o identificadores tipados (no caso da linguagem a a Pascal ); • O tipo do valor de retorno contendo o c´lculo feito na fun¸ao. a c˜ Para o problema em quest˜o, vamos assumir que poder´ a ıamos estabelecer o seguinteprot´tipo para a fun¸ao que calcula se um dado n´mero ´ par retornando true em o c˜ u ecaso positivo e false em caso contr´rio. Vejamos como fica: afunction a eh par : boolean; A palavra reservada function ´ para avisar o programa que se trata de uma fun¸˜o. e caO identificador a eh par procura representar o fato de que a vari´vel a pode ser par. a O c´digo da fun¸˜o n˜o importa muito no momento, mas apenas com o prot´tipo o ca a o´ poss´ reescrever o programa exemplo como apresentado na figura 9.2.e ıvel
    • ¸˜9.2. NOCOES FUNDAMENTAIS 111program imprime pares ;var a : integer ;(∗ funcao que calcula se a variavel global a eh par ∗)function a eh par : boolean;begin (∗ codigo da funcao , ainda nao escrito por razoes didaticas ∗)end;begin (∗ programa principal ∗) read (a) ; while a < 0 do > begin i f a eh par then writeln (a) ; read (a) ; end;end. Figura 9.2: Programa que imprime os n´meros da entrada que s˜o pares. u a Desde que o c´digo da fun¸˜o seja corretamente implementado, o programa princi- o capal continua funcionando! Al´m disto ´ um c´gido mais leg´ e e o ıvel, j´ que ´ mais simples a epara algu´m ler o programa principal e perceber o significado do identificador deno- eminado a eh par ao inv´s do obscuro “a mod 2 = 0”. e Obviamente ´ necess´rio em algum momento se escrever o c´digo da fun¸˜o. Vamos e a o camostrar quatro maneiras diferentes de se devolver o valor correto para o programaprincipal. (∗ primeira versao da funcao ∗) (∗ segunda versao da funcao ∗) i f a mod 2 = 0 then i f a mod 2 < 0 then > a eh par:= true a eh par:= false else else a eh par:= false ; a eh par:= true; (∗ terceira versao da funcao ∗) (∗ quarta versao da funcao ∗) i f a mod 2 < 1 then > i f a mod 2 = 1 then a eh par:= true a eh par:= false else else a eh par:= false ; a eh par:= true; (∗ quinta versao da funcao ∗) (∗ sexta versao da funcao ∗) a eh par:= false ; a eh par:= true; i f a mod 2 = 0 then i f a mod 2 = 1 then a eh par:= true a eh par:= false
    • 112 CAP´ ¸˜ ITULO 9. FUNCOES E PROCEDIMENTOS (∗ setima versao da funcao ∗) (∗ oitava versao da funcao ∗) a eh par:= true; a eh par:= true; i f a mod 2 < 1 then > i f a mod 2 < 0 then > a eh par:= true a eh par:= false Em tempo, um detalhe da linguagem Pascal. Segundo a defini¸ao da linguagem, c˜estabelecida por seu autor Niklaus Wirth ainda nos anos 1970, a maneira como o valordo retorno ´ feita para o programa principal exige que o nome da fun¸ao apare¸a pelo e c˜ cmenos uma vez no c´digo da fun¸ao do lado esquerdo de um comando de atribui¸˜o. o c˜ caIsto funciona diferente em outras linguagens de programa¸˜o, para isto, se o estudante caresolver mudar de linguagem, deve observar o respectivo guia de referˆncia. e Ainda um coment´rio adicional sobre a linguagem Pascal, a fun¸˜o ´ executada at´ a ca e eo final, isto ´, at´ encontrar o comando end; que a termina. Isto pode ser diferente e eem outras linguagens.9.2.5 Parˆmetros por valor aConforme dissemos, atendemos a quest˜o da modularidade ao usarmos a fun¸ao a c˜a eh par. Mas n˜o atendemos a outra: a quest˜o do reaproveitamento de c´digo. a a o De fato, suponhamos que o enunciado tivesse estabelecido que seriam dados comoentrada pares de n´meros a e b e para imprimir apenas os que fossem pares. Na uvers˜o atual do programa, ter´ a ıamos que escrever uma outra fun¸˜o de nome prov´vel ca ab eh par que teria o c´digo absolutamente idˆntico ao da fun¸ao a eh par exceto pela o e c˜troca da vari´vel a pela vari´vel b. Isto ´ inadmiss´ em programa¸ao de alto n´ a a e ıvel c˜ ıvel! Logo, deve existir uma maneira melhor para se programar a fun¸ao. Felizmente c˜existe: basta passar um parˆmetro, isto ´, basta informar ` fun¸˜o que os c´lculos a e a ca aser˜o feitos para um dado n´mero inteiro, n˜o importando o nome da vari´vel que a u a acont´m o valor sobre o qual ser´ feito o c´lculo da paridade. Isto ´ conseguido e a a emudando-se o prot´tipo da fun¸˜o para o seguinte: o cafunction eh par (n: integer) : boolean; Em outras palavras, a fun¸ao vai receber um n´mero inteiro, no caso denominado c˜ un (mas poderia ser a, b ou qualquer outro identificador, o importante ´ que seja do etipo integer. O tipo do retorno ´ o mesmo, isto ´, boolean. e e Com isto, conseguimos escrever o programa (j´ com a fun¸˜o recebendo parˆmetros a ca apor valor), da maneira como est´ apresentado na figura 9.3. a Esta maneira de passar parˆmetros caracteriza uma passagem por valor, tamb´m a econhecida como passagem de parˆmetros por c´pia. O que ocorre ´ que o identificador a o en da fun¸˜o recebe uma c´pia do valor da vari´vel a do programa principal. As ca o aaltera¸oes em n s˜o feitas nesta c´pia, mantendo-se intactos os dados da vari´vel a no c˜ a o aprograma principal. Isto ocorre pois esta c´pia ´ feita em area separada de mem´ria, o e ´ odenominada pilha.
    • ¸˜9.2. NOCOES FUNDAMENTAIS 113program imprime pares ;var a : integer ;(∗ funcao que calcula se a variavel global a eh par ∗)function eh par (n: integer) : boolean;begin i f n mod 2 = 0 then eh par:= true else eh par:= false ;end;begin (∗ programa principal ∗) read (a) ; while a < 0 do > begin i f eh par (a) then writeln (a) ; read (a) ; end;end. Figura 9.3: Programa que imprime os n´meros da entrada que s˜o pares. u a9.2.6 Parˆmetros por referˆncia a ePara passar parˆmetros por referˆncia, o prot´tipo da fun¸ao difere ligeiramente da- a e o c˜quele exibido acima. A chamada ´ assim: efunction eh par (var n: integer) : boolean; A diferen¸a sint´tica ´ caracterizada pela palavra var antes do nome do identifica- c a edor do parˆmetro.2 Pode parecer sutil, mas com uma semˆntica totalmente diferente a adaquela da passagem de parˆmetros por valor. a O que antes era uma c´pia, agora ´ uma referˆncia ao endere¸o da vari´vel do o e e c aprograma principal. Isto ´, no momento da ativa¸ao da fun¸˜o, o identificador n e c˜ cada fun¸ao ´ associado com o mesmo endere¸o da vari´vel a no programa principal. c˜ e c aConsequentemente, qualquer altera¸˜o associada a n na fun¸ao provocar´ altera¸˜o ca c˜ a cado valor da vari´vel a no programa principal. a Vejamos na figura 9.4 como fica a modifica¸ao no programa em estudo do ponto de c˜vista meramente sint´tico. Deixamos o ponto de vista semˆntico para ser explicado a ano pr´ximo exemplo. o 2 Com todo o respeito ao Niklaus Wirth, usar a palavra var para este fim n˜o foi uma boa escolha, apois para um principiante ´ f´cil confundir com uma passagem de parˆmetros por referˆncia com e a a euma declara¸˜o de uma vari´vel, o que n˜o ´ definitivamente o caso aqui. ca a a e
    • 114 CAP´ ¸˜ ITULO 9. FUNCOES E PROCEDIMENTOSprogram imprime pares ;var a : integer ;(∗ funcao que calcula se a variavel global a eh par ∗)function eh par (var n: integer) : boolean;begin i f n mod 2 = 0 then eh par:= true else eh par:= false ;end;begin (∗ programa principal ∗) read (a) ; while a < 0 do > begin i f eh par (a) then writeln (a) ; read (a) ; end;end. Figura 9.4: Vers˜o com parˆmetros por referˆncia. a a e9.2.7 ProcedimentosUm procedimento difere de uma fun¸ao basicamente pois n˜o tem um valor de retorno c˜ aassociado. Isto faz com que ele se comporte como um comando extra da linguagem aopasso que a fun¸˜o tem um comportamento mais parecido com o de uma express˜o ca aaritm´tica ou booleana. Um prot´tipo para um procedimento ´ definido ent˜o com e o e abase em apenas duas informa¸˜es: co 1. o identificador do procedimento (nome); 2. a lista de parˆmetros (que podem ser por valor ou referˆncia). a e Para explicar corretamente a no¸˜o de procedimentos, e tamb´m de vari´veis lo- ca e acais, ´ importante mudar de exemplo. Vamos considerar o problema de se ler dois en´meros reais x e y do teclado, fazer a troca dos conte´dos e depois imprimir. u u Vamos considerar o seguinte prot´tipo para um procedimento que recebe os dois ovalores x e y e tem a finalidade de realizar a troca dos conte´dos destas vari´veis: u aprocedure troca (var a , b: real) ; Observe que, assim como no caso da fun¸ao, n˜o importa muito o nome dos identi- c˜ aficadores dos parˆmetros, apenas importa que eles definam conte´dos do tipo REAL. a u Podemos ent˜o tentar escrever um programa que leia dois valores e os imprima atrocados, conforme ilustrado na figura 9.53 : 3 Um exerc´ interessante ´ passar os parˆmetros por valor e compreender o efeito disso. ıcio e a
    • ¸˜9.2. NOCOES FUNDAMENTAIS 115program imprimetrocado ;var x, y,temp: real ; (∗ variaveis globais ∗)(∗ procedimento que troca os conteudos da variaveis ∗)procedure troca (var a , b: real) ;begin temp:= a ; a:= b; b:= temp;end;begin (∗ programa principal ∗) read (x,y) ; troca (x,y) ; writeln (x,y) ;end. Figura 9.5: Vers˜o com parˆmetros por referˆncia. a a e Este programa usa uma vari´vel global (temp) para auxiliar a troca, o que n˜o a afaz muito sentido. Os subprogramas devem funcionar independentemente de vari´veis aglobais.9.2.8 Vari´veis locais aVari´veis locais s˜o declaradas nos subprogramas e tˆm escopo local, isto ´, elas s´ s˜o a a e e o aconhecidas durante a execu¸ao do subprograma. Consequentemente n˜o interferem c˜ ano programa principal. O programa modificado da figura 9.6 faz uso da vari´vel local atemp e torna o c´digo mais robusto. oprogram imprimetrocado ;var x,y: real ; (∗ variaveis globais ∗)(∗ procedimento que troca os conteudos da variaveis ∗)procedure troca (var a , b: real) ;var temp: real ; (∗ variavel local , temporaria para uso exclusivo neste procedimento ∗)begin temp:= a ; a:= b; b:= temp;end;begin (∗ programa principal ∗) read (x,y) ; troca (x,y) ; writeln (x,y) ;end. Figura 9.6: Vers˜o com uma vari´vel local. a a
    • 116 CAP´ ¸˜ ITULO 9. FUNCOES E PROCEDIMENTOS9.3 Alguns exemplosNesta se¸˜o vamos implementar dois problemas simples para exercitar. ca9.3.1 Calculando d´ ıgito verificadorVamos fazer um programa que recebe um n´mero de N d´ u ıgitos, sendo o ultimo deles ´o “d´ıgito verificador” do n´mero formado pelos N − 1 primeiros. Devemos calcular se uo d´ıgito verificador fornecido pelo usu´rio est´ correto segundo o esquema de c´lculo a a aseguinte: cada d´ ıgito do n´mero, come¸ando da direita para a esquerda (menos sig- u cnificativo para o mais significativo) ´ multiplicado, na ordem, por 1, depois 2, depois e1, depois 2 e assim sucessivamente. O n´mero de entrada do exemplo ´ 261533-4. u e +---+---+---+---+---+---+ +---+ | 2 | 6 | 1 | 5 | 3 | 3 | - | 4 | +---+---+---+---+---+---+ +---+ | | | | | | x2 x1 x2 x1 x2 x1 | | | | | | =4 =6 =2 =5 =6 =3 +---+---+---+---+---+-> = 26 Como 26 tem dois d´ıgitos, vamos repetir o processo acima at´ gerarmos um n´mero e ude um unico d´ ´ ıgito. Assim: +---+---+ | 2 | 6 | +---+---+ | | x2 x1 | | =4 =6 +---+ = 10 Como 10 ainda tem dois d´ ıgitos, o algoritmo roda ainda mais uma vez: +---+---+ | 1 | 0 | +---+---+ | | x2 x1 | | =2 =0 +---+ = 2 Assim, o d´ıgito verificador calculado (2) difere daquele fornecido (4) e o programadeveria acusar o erro. O programa da figura 9.7 ilustra uma poss´ solu¸˜o. ıvel ca
    • 9.3. ALGUNS EXEMPLOS 117program digitoverificador ;var numero, n: longint ; dv, dv correto : integer ;procedure le (var n: longint ) ;begin {$i−} repeat read (n) ; until ioresult = 0; {$i+}end;procedure separa numero e dv (n: longint ; var num: longint ; var dv: integer) ;begin num:= n div 10; dv:= n mod 10;end;function calcula dv correto (n: longint ) : integer ;var soma, mult, ultimo : integer ;begin repeat soma:= 0; mult:= 1; while n < 0 do > begin ultimo:= n mod 10; n:= n div 10; soma:= soma + mult ∗ ultimo ; i f mult = 1 then mult:= 2 else mult:= 1; end; n:= soma; until (n > 0) and (n <= 9) ; calcula dv correto:= soma;end;begin (∗ programa principal ∗) le (numero) ; separa numero e dv (numero, n, dv) ; dv correto:= calcula dv correto (n) ; i f dv correto < dv then > writeln (’digito verificador invalido.’)end. Figura 9.7: Calculando d´ ıgito verificador.
    • 118 CAP´ ¸˜ ITULO 9. FUNCOES E PROCEDIMENTOS O importante para se observar neste c´digo ´ a clareza do algoritmo no programa o eprincipal. O leitor pode acompanhar este trecho e perceber claramente as diversasetapas em uma linguagem de bastante alto n´ ıvel: leitura do n´mero, separa¸ao deste u c˜em duas partes, uma contendo os primeiros d´ ıgitos a outra contendo o dv de entrada.Em seguida o c´lculo do d´ a ıgito verificador correto e finalmente a compara¸ao dos c˜dados calculados com o de entrada, gerando a mensagem final. No programa principal pode-se ignorar completamente como s˜o feitas todas as aopera¸oes nas fun¸oes e procedumentos: n˜o importa como os dados s˜o lidos, nem c˜ c˜ a acomo os d´ ıgitos s˜o separados, e muito menos como ´ feito o c´lculo do d´ a e a ıgito verifi-cador correto. No programa principal o importante ´ o algoritmo em alto n´ e ıvel. ´ E claro que em algum momento ser´ necess´rio escrever c´digo para cada uma das a a ofun¸oes e procedimentos, mas quando isto for feito o programador estar´ resolvendo c˜ aum subproblema de cada vez, o que facilita muito a constru¸ao do c´digo para o c˜ oproblema global. Por exemplo, a leitura poderia ser feita em uma interface gr´fica ou textual. Foi es- acolhida nesta vers˜o uma interface textual, mas que permite testes de consistˆncia dos a edados de entrada. Isto, feito separadamente, mant´m o c´digo global independente. e oNo caso, o programador usou diretivas do compilador para alterar o comportamentopadr˜o que aborta o programa se o usu´rio digitar um tipo n˜o esperado. Trata corre- a a atamente o erro e quando tudo est´ certo, termina o procedimento. Importante notar aque, para leitura de dados, o parˆmetro tem que ser passado por referˆncia, e n˜o por a e avalor, sen˜o o valor seria lido em uma c´pia da vari´vel do programa principal. a o a Considera¸oes similares s˜o feitas para a outra fun¸ao e o procedimento, ambos c˜ a c˜possuem c´digo pr´prio e fazem com que a aten¸˜o do programador fique voltada o o caexclusivamente para o subproblema da vez. Desde que o prot´tipo da fun¸˜o ou pro- o cacedimento esteja corretamente especificado, n˜o h´ problema em se alterar o c´digo a a ointerno. Notamos tamb´m que no caso da fun¸ao, foram usadas vari´veis locais para e c˜ aaux´ no c´lculo do d´ ılio a ıgito verificador. Tudo para o bem da clareza do c´digo prin- ocipal. Se um dia mudarem a defini¸˜o de como se calcula o d´ ca ıgito verificador, bastaalterar a fun¸˜o que o programa principal continuar´ a funcionar corretamente. ca a Na ultima fun¸˜o ´ importante notar a passagem de parˆmetros por valor. Isto ´ ca e apermitiu o la¸o que controla o loop interno usar o pr´prio parˆmetro como condi¸ao c o a c˜de parada, pois ele ´ dividido por 10 a cada itera¸ao. Se o parˆmetro fosse passado e c˜ apor referˆncia isto n˜o poderia ser feito, pois estar´ e a ıamos estragando o valor da vari´vel aque ser´ ainda usada no programa principal. a Ainda uma ultima observa¸˜o, no procedimento que separa o n´mero de seu d´ ´ ca u ıgitoverificador, atentar para a sintaxe, em Pascal, que se usa quando se quer passar doisparˆmetros do mesmo tipo, um por valor e outro por referˆncia. No caso, eles devem a eser separados pelo s´ ımbolo do ponto-e-v´ ırgula, o segundo deles contendo a palavra varpara indicar referˆncia. e
    • ´ ¸˜9.4. CALCULO DO MDC PELA DEFINICAO 1199.4 C´lculo do MDC pela defini¸˜o a caNesta se¸˜o vamos revisitar o c´lculo do MDC pela defini¸˜o estudado na se¸ao 8.5. ca a ca c˜Deixamos propositalmente em aberto a quest˜o de que aquele c´digo continha trechos a ode c´digo similares que tinham que ser repetidos por causa de um n´mero de entrada o uvariante no programa. De fato, naquele c´digo exibido na figura 8.15 o c´lculo para saber se o n´mero a o a uera par difere do c´lculo para saber se o n´mero b ´ par apenas por conta do valor de a u ea ou b. O mesmo ocorre para o c´digo da figura 8.16 no caso de n´meros ´ o u ımpares. Na verdade, os quatro trechos de c´digo est˜o ali apenas para se saber quantas o avezes um dado n´mero n pode ser dividido por um n´mero primo p, seja ele o 2 ou u uqualquer ´ımpar primo. Este c´lculo pode ser feito em um subprograma que recebe os n´meros de entrada a ude alguma maneira e que devolva o valor correto tamb´m segundo uma conven¸ao. e c˜ Esta conven¸˜o, em Pascal, ´ dada pelo prot´tipo de uma fun¸ao que ´ constitu´ ca e o c˜ e ıdopor trˆs parˆmetros: o nome da fun¸ao, os n´meros n e p envolvidos e, finalmente, o e a c˜ utipo do valor devolvido pelo subprograma, isto ´, um tipo que contenha o n´mero de e uvezes em que n ´ dividido por p. efunction num vezes que divide(p,n : integer) : integer ; Outro trecho de c´digo repetido ´ a atualiza¸ao do MDC para receber a menor o e c˜potˆncia do primo sendo calculado, na primeira vez ´ o 2, nas outras vezes ´ um primo e e e´ımpar. Basta criarmos um segundo prot´tipo de fun¸ao que calcule a potˆncia do primo o c˜ eelevado ao valor do menor contador. Este pode ser o seguinte:function potencia(n, i : integer) : integer ; Estas interfaces nos permitem modificar o programa do c´lculo do MDC pela adefini¸ao conforme mostra a figura 9.8. c˜ Observamos que o uso de fun¸˜es e procedimentos permite muita flexibilidade ao coprogramador, pois ele pode alterar o c´digo da fun¸oes, se quiser, tornando-as mais o c˜eficientes (caso n˜o fossem) sem que haja efeito colateral no programa principal. As afiguras 9.9 e 9.10 mostram sugest˜es de c´digo para as fun¸oes. o o c˜ Na verdade, este c´digo n˜o ´ muito apropriado, pois exige um comportamento n˜o o a e amuito elegante na fun¸˜o num vezes que divide, ela tem o efeito colateral de alterar cao valor da vari´vel n, o que n˜o ´ natural dado o nome da fun¸˜o. Deveria apenas a a e cacontar o n´mero de vezes que divide e n˜o fazer mais nada. O problema n˜o pode ser u a aresolvido com este mesmo algoritmo sem este efeito colateral. Em todo caso, sabemosque o algoritmo de Euclides ´ mais eficiente, mais simples de implementar e sobretudo emais elegante!
    • 120 CAP´ ¸˜ ITULO 9. FUNCOES E PROCEDIMENTOSprogram mdcpeladefinicao ; (∗ pela definicao de mdc ∗)var a , b, primo, mdc: longint ; cont a , cont b , menor cont : integer ;function num vezes que divide(p: integer ; var n: longint ) : integer ;(∗ codigo da funcao num vezes que divide ∗)function potencia(n,p : integer) : integer ;(∗ codigo da funcao potencia ∗)begin (∗ programa principal ∗) read (a ,b) ; mdc:= 1; cont a:= num vezes que divide(2 ,a) ; cont b:= num vezes que divide(2 ,b) ; i f cont a <= cont b then menor cont:= cont a else menor cont:= cont b ; mdc:= mdc ∗ potencia (2 ,menor cont) ; writeln (’mdc= ’ ,mdc) ; primo:= 3; while (a < 1) and (b < 1) do > > begin writeln (primo) ; cont a:= num vezes que divide(primo, a) ; cont b:= num vezes que divide(primo,b) ; i f cont a <= cont b then menor cont:= cont a else menor cont:= cont b ; mdc:= mdc ∗ potencia(primo, menor cont) ; primo:= primo + 2; end; writeln (mdc) ;end. Figura 9.8: Calcula MDC entre a e b pela defini¸˜o usando fun¸oes. ca c˜
    • ´ ¸˜9.4. CALCULO DO MDC PELA DEFINICAO 121function num vezes que divide(p: integer ; var n: longint ) : integer ;var cont : integer ;begin (∗ descobre quantas vezes o 2 divide as duas entradas ∗) cont:= 0; while n mod p = 0 do begin cont:= cont + 1; n:= n div p; end; writeln (’num_vezes_que_divide= ’ ,cont) ; num vezes que divide:= cont ;end; Figura 9.9: Calcula quantas vezes um n´mero divide outro. ufunction potencia(n,p : integer) : integer ;var pot : longint ; i : integer ;begin pot:= 1; i:= 1; while i <= p do begin pot:= pot ∗ n; i:= i + 1; end; writeln (’potencia= ’ ,pot) ; potencia:= pot ;end; Figura 9.10: Calcula a potˆncia de um n´mero elevado a outro. e u9.4.1 Calculando ra´ ızes de equa¸˜es do segundo grau coPara refor¸armos os conceitos em estudo, consideremos aqui o problema de se ler os ccoeficientes a, b e c que definem uma equa¸ao do segundo grau ax2 + bx + c = 0 e c˜imprimir as ra´ızes calculadas pela f´rmula de B´skara. O programa deve imprimir o amensagens corretas no caso de n˜o haverem ra´ a ızes reais bem como n˜o deve aceitar aentradas cujo valor para o coeficiente a sejam nulas. O programa da figura 9.11 cont´m eo c´digo que resolve este problema. o A figura 9.12 ilustra o programa principal modificado para se dar a ideia de que asfun¸oes se comportam como express˜es aritm´ticas, ao contr´rio dos procedimentos, c˜ o e aque se comportam como comandos. Na verdade, o programa principal poderia ser apenas o c´digo da figura 9.13, osem preju´ do funcinamento, mas com bem menos legilidade e ainda por cima sem ıjotratamento do delta negativo. Apresentamos esta vers˜o apenas para ilustrar o uso adas fun¸˜es dentro de fun¸˜es, mas observamos que o c´lculo do delta ´ feito duas co co a evezes.
    • 122 CAP´ ¸˜ ITULO 9. FUNCOES E PROCEDIMENTOSprogram raizes eq 2o grau ;var a , b, c , delta , x1, x2 : real ;procedure ler (var a , b, c : real) ;begin {$i−} repeat read (a , b, c) ; until ( ioresult = 0) and (a < 0) ; > {$i+}end;function calcula delta (a , b, c : real) : real ;begin calcula delta:= b∗b − 4∗a∗c ;end;function menor raiz (a , b, delta : real) : real ;begin menor raiz:= (−b − sqrt ( delta ) )/(2∗a) ;end;function maior raiz (a , b, delta : real) : real ;begin maior raiz:= (−b + sqrt ( delta ) )/(2∗a) ;end;begin (∗ programa principal ∗) ler (a , b, c) ; (∗ garante−se que a nao eh nulo ∗) delta:= calcula delta (a , b, c) ; i f delta >= 0 then begin x1:= menor raiz (a , b, delta ) ; writeln (x1) ; x2:= maior raiz (a , b, delta ) ; writeln (x2) ; end else writeln (’raizes complexas’) ;end. Figura 9.11: Calculando ra´ de equa¸˜o do segundo grau. ızes ca
    • ´ ¸˜9.4. CALCULO DO MDC PELA DEFINICAO 123begin (∗ programa principal ∗) ler (a , b, c) ; (∗ garante−se que a nao eh nulo ∗) delta:= calcula delta (a , b, c) ; i f delta >= 0 then begin writeln (menor raiz (a , b, delta ) , maior raiz (a , b, delta ) ) ; end else writeln (’raizes complexas’) ;end. Figura 9.12: Calculando ra´ de equa¸˜o do segundo grau. ızes cabegin (∗ programa principal ∗) ler (a , b, c) ; (∗ garante−se que a nao eh nulo ∗) writeln (menor raiz (a , b, calcula delta (a ,b, c) ) , maior raiz (a , b, calcula delta (a ,b, c) ) ) ;end. Figura 9.13: Calculando ra´ de equa¸˜o do segundo grau. ızes ca Terminamos aqui a primeira parte do curso, no qual as no¸oes fundamentais sobre c˜algoritmos est˜o estabelecidas. Nos pr´ximos estudaremos as principais estruturas de a odados b´sicas para um curso introdut´rio de algoritmos. a o
    • 124 CAP´ ¸˜ ITULO 9. FUNCOES E PROCEDIMENTOS9.5 Exerc´ ıcios 1. Fazer uma fun¸ao em Pascal que receba como parˆmetro dois n´meros intei- c˜ a u ros n˜o nulos e retorne TRUE se um for o contr´rio do outro e FALSE em a a caso contr´rio. Isto ´, se os parˆmetros forem 123 (cento e vinte e trˆs) e 321 a e a e (trezentos e vinte e um), deve-se retornar TRUE. Usar apenas opera¸oes sobre c˜ inteiros. 2. Fazer uma fun¸ao em Pascal que receba como parˆmetro um n´mero inteiro c˜ a u representando um n´mero bin´rio e retorne seu valor equivalente em decimal. u a Por exemplo, se a entrada for 10001, a sa´ deve ser 17. ıda 3. Fazer uma fun¸ao em Pascal que receba como parˆmetro um n´mero inteiro e c˜ a u retorne TRUE se ele for primo e FALSE em caso contr´rio. Use esta fun¸˜o a ca para imprimir todos os n´meros primos entre 0 e 1000. u 4. Implemente fun¸oes para seno e cosseno conforme definidos em cap´ c˜ ıtulos an- teriores e use-as em uma terceira fun¸ao que calcule a tangente. O programa c˜ principal deve imprimir os valores de tg(x) para um certo valor fornecido pelo usu´rio. a 5. Implemente um procedimento para gerar mais de um milh˜o de n´meros inteiros. a u Os n´meros gerados dever˜o ser impressos em um arquivo texto. u a 6. Fa¸a uma fun¸ao em Pascal que some dois n´meros representando horas. A c c˜ u entrada deve ser feita da seguinte maneira: 12 52 7 13 A sa´ deve ser assim: ıda 12:52 + 7:13 = 20:05 7. Fa¸a uma fun¸ao que receba como parˆmetros seis vari´veis DIA1, MES1 e c c˜ a a ANO1, DIA2, MES2 e ANO2, todas do tipo integer. Considerando que cada trinca de dia, mˆs e ano representa uma data, a fun¸ao deve retornar true se a e c˜ primeira data for anterior a segunda e false caso contr´rio. ` a
    • Cap´ ıtulo 10Estruturas de dadosAt´ aqui apresentamos as t´cnicas b´sicas para constru¸˜o de algoritmos, incluindo as e e a cano¸oes de fun¸oes e procedimentos. Podemos dizer que ´ poss´ c˜ c˜ e ıvel, com este conte´do, uprogramar uma vasta cole¸ao de algoritmos, inclusive alguns com alta complexidade. c˜ Contudo, o estudo geral da disciplina de “Algoritmos e Estrurutas de Dados”envolve algoritmos que trabalham dados organizados em mem´ria de maneira mais osofisticada do que as simples vari´veis b´sicas que foram estudadas at´ o momento. a a e´ algo mais ou menos parecido como manter um guarda-roupas organizado no lugarEde um monte de coisas atiradas no meio do quarto de qualquer jeito. A organiza¸˜o de dados em mem´ria permite a constru¸ao de algoritmos sofistica- ca o c˜dos e eficientes. Neste textp estudaremos trˆs estruturas de dados elementares. S˜o e aelas: • vetores (ou array unidimencional); • matrizes (ou array multidimencional); • registros. Nas se¸oes seguintes explicaremos cada uma delas, sempre motivados por proble- c˜mas que exigem seu uso ou que facilitam a implementa¸ao. Tamb´m veremos nos c˜ epr´ximos cap´ o ıtulos algumas estruturas que misturam estas trˆs. e10.1 VetoresPara motivar, vamos considerar o problema seguinte: ler uma certa quantidade devalores inteiros e os imprimir na ordem inversa da leitura. Isto ´, se os dados de eentrada forem: 2, 5, 3, 4, 9, queremos imprimir na sa´ ıda: 9, 4, 3, 5, 2. Este tipo de problema ´ imposs´ e ıvel de ser resolvido com o uso de apenas umavari´vel pois, quando se lˆ o segundo n´mero, j´ se perdeu o primeiro da mem´ria. a e u a oExigiria o uso de tantas vari´veis quantos fossem os dados de entrada, mas notem que aisto deve ser conhecido em tempo de compila¸˜o! O que faz com que simplesmente can˜o seja poss´ resolver este problema para uma quantidade indefinida de valores. a ıvel 125
    • 126 CAP´ ITULO 10. ESTRUTURAS DE DADOS De fato, quando se aloca, por exemplo, um n´mero inteiro em uma vari´vel de u anome a, o que ocorre ´ que o computador reserva uma posi¸ao de mem´ria em algum e c˜ oendere¸o da RAM (conforme sabemos pelo modelo Von Neumann). Um inteiro exige c(dependendo da implementa¸ao) 2 bytes. c˜ Mas, digamos que ´ preciso alocar espa¸o para 100 n´meros inteiros. Sabendo e c uque cada um deles ocupa 2 bytes, precisar´ ıamos encontrar uma maneira de reservar100 × 2 = 200 bytes e fazer com que este espa¸o de mem´ria pudesse ser acessado c otamb´m por um unico endere¸o, ou em outras palavras, por uma unica vari´vel. e ´ c ´ a Os vetores s˜o estruturas de dados que permitem o acesso a uma grande quantidade ade dados em mem´ria usando-se apenas um nome de vari´vel. Esta vari´vel especial o a a´ declarada de tal maneira que o programador passa a ter acesso a muitas posi¸oese ` c˜de mem´ria, de maneira controlada. o Sem ainda entrar em detalhes da linguagem Pascal, vamos tentar entender o pro-cesso.Como funciona isto em mem´ria? oSeguindo no exemplo de se alocar 200 espa¸os em mem´ria para n´meros inteiros, c o usuponhamos que o seguinte comando faz esta aloca¸ao: c˜var V: array[1..200] of integer ; Em Pascal isto resulta na aloca¸˜o de 200 vezes 2 bytes. Pela vari´vel V temos o ca acontrole deste espa¸o. c O problema ´ como se faz para se escrever um valor qualquer neste espa¸o. Outro e cproblema ´ onde se escreve, j´ que temos 200 possibilidades de escolha. O simples uso e a a a ´da vari´vel, como est´vamos acostumados, n˜o serve. E preciso uma outra informa¸ao a c˜adicional para se dizer em qual das 200 posi¸˜es se quer escrever. co Na verdade, a vari´vel V aponta para o in´ do segmento reservado, da mesma a ıciomaneira que se fazia para vari´veis b´sicas j´ estudadas. Para se escrever em algum a a alugar deste segmento, ´ preciso informar, al´m do nome da vari´vel, uma segunda e e ainforma¸ao: a posi¸˜o (ou o deslocamento) dentro do espa¸o reservado. c˜ ca c Ora, sabemos que foram reservadas 200 posi¸oes, cada uma delas com espa¸o para c˜ cconter um n´mero inteiro. Se quisermos escrever na quinta posi¸ao, basta informar u c˜ao computador que o in´ do segmento ´ dado pela vari´vel V e que, antes de se ıcio e aescrever, ´ preciso realizar um deslocamento de 5 posi¸˜es, cada uma delas para um e cointeiro. Isto d´ um deslocamento de 10 bytes. Ap´s esta informa¸ao, o valor pode ser a o c˜escrito. Se o desejo ´ escrever na d´cima quarta posi¸ao, o deslocamento deve ser de e e c˜14 × 2 bytes, isto ´, 28 bytes. e Para se recuperar a informa¸ao, por exemplo para se imprimir, ou para se fazer c˜algum c´lculo com estes dados, basta usar o mesmo processo: os dados s˜o acessados a apelo nome da vari´vel e pelo deslocamento. a Este processo foi apresentado em muito baixo n´ ıvel. Como de costume, precisamosde uma outra forma de representa¸ao de mais alto n´ c˜ ıvel. Isto ´, cada linguagem de e
    • 10.1. VETORES 127programa¸ao que implementa a no¸ao de vetores tem que encontrar uma maneira para c˜ c˜se mascarar para o programador este processo que ´ baseado em deslocamentos (ou esomas de endere¸os). c Na pr´xima se¸ao veremos como a linguagem Pascal lida com isto. o c˜Vetores em PascalPara se declarar um vetor de 200 posi¸oes inteiras, a linguagem Pascal usa a seguinte c˜sintaxe (lembre-se que em outras linguagens a sintaxe pode ser diferente):var v: array [1..200] of integer ; A constru¸˜o “1..200” indica que existem 200 posi¸oes controladas pela vari´vel ca c˜ av. O “of integer” indica que cada posi¸˜o ´ para se guardar um n´mero inteiro, isto ca e u´, 2 bytes (dependendo da implementa¸˜o).e ca A rigor, a linguagem Pascal permite que se reserve 200 posi¸˜es de v´rias maneiras. co aBasta que o intervalo “a..b” contenha 200 posi¸oes. Apresentamos 6 variantes dentre c˜as milhares poss´ ıveis:var v: array [0..199] of integer ;var v: array [201..400] of integer ;var v: array [ −199..0] of integer ;var v: array [−300..−99] of integer ;var v: array [ −99..100] of integer ;const min=11, max=210;var v: array [min . .max] of integer ; Em todas estas variantes, o intervalo define 200 posi¸˜es. Em termos gerais, existe couma restri¸ao forte. O intervalo deve ser definido em termos de n´meros de algum c˜ utipo ordinal (em Pascal ), isto ´, integer, logint, . . . , at´ mesmo char. Tamb´m em e e ePascal, o limite inferior deve ser menor ou igual ao limite superior. Na sequˆnciaedesta se¸ao, vamos considerar a vers˜o que usa o intervalo de 1 a 200. c˜ a Agora, para guardar um valor qualquer, digamos 12345, na posi¸ao 98 do vetor v, c˜em Pascal, se usa um dos dois comandos seguintes:v[98]:= 12345;read(v[98]) ; (∗ e se digita 12345 no teclado ∗)
    • 128 CAP´ ITULO 10. ESTRUTURAS DE DADOS Em termos gerais, vejamos os seguintes exemplos, para fixar o conceito:read (v[ 1 ] ) ; (∗ le do teclado e armazena na primeira posicao de v ∗)i:= 10;v[ i+3]:= i ∗ i ; (∗ armazena o quadrado de i (100) na posicao 13 de v ∗)write ( i , v[ i ] ) ; (∗ imprime o par (10, 100) na tela ∗)write (v[v[ 1 3 ] ] ) ; (∗ imprime o valor de v[100] na tela ∗)v[201]:= 5; (∗ gera erro , pois a posicao 201 nao existe em v ∗)v[47]:= sqrt (4) ; (∗ gera erro , pois sqrt retorna um real , mas v eh de inteiros ∗)var x: real ;v[x]:= 10; (∗ gera erro , pois x eh do tipo real , deveria ser ordinal ∗) Note que a constru¸ao (v[v[13]]) s´ ´ poss´ pois o vetor v ´ do tipo integer. Se c˜ oe ıvel efosse um vetor de reais isto n˜o seria poss´ (em Pascal ). a ıvel10.1.1 Primeiros problemas com vetoresPara iniciarmos nossa saga pelos algoritmos sofisticados que usam vetores, vamosapresentar uma s´rie de problemas j´ conhecidos para vermos como eles podem ser e aresolvidos usando vetores. Aproveitaremos para fixar conceitos j´ ensinados sobre pro- acedimentos e fun¸oes. Desta forma o estudante poder´, resolvendo exerc´ c˜ a ıcios simples,se concentrar na novidade, isto ´, no uso de vetores. eLendo vetoresPara resolvermos o problema apontado acima, isto ´, um programa que leia 10 n´meros e ureais e os imprima na ordem inversa da leitura, precisamos inicialmente ler os elemen-tos do vetor. O c´digo da figura 10.1 ilustra uma solu¸ao poss´ o c˜ ıvel. Quando executado,considerando que no teclado foi digitada a sequˆncia 15, 12, 27, 23, 7, 2, 0, 18, 19 e e21, teremos em mem´ria algo como ilustrado na figura seguinte: o 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 197 198 199 200 15 12 27 23 7 2 0 18 19 21 ? ? ? ? ? ... ? ? ? ? ´ E importante, neste momento, atentar para alguns fatos: 1. este vetor tem 200 elementos, pois seu tamanho foi definido em tempo de com- pila¸ao. Como s´ foram lidos os 10 primeiros elementos, o restante do ve- c˜ o tor cont´m valores indefinidos que j´ estavam em mem´ria quando programa e a o come¸ou a executar. Isto ´ o que chamamos de lixo de mem´ria e est´ repre- c e o a sentado com interroga¸oes na figura acima; c˜
    • 10.1. VETORES 129program lendo vetores ;var v: array [1..200] of real ; (∗ define um vetor de reais ∗) i : integer ;begin i:= 1; while i <= 10 do begin read (v[ i ] ) ; i:= i + 1; end;end. Figura 10.1: Lendo elementos e colocando no vetor. 2. o enunciado n˜o especifica onde se armazenar os valores, como o vetor v tem a 200 posi¸oes, poder´ c˜ ıamos ter usado qualquer intervalo, mas normalmente se usa um vetor a partir da posi¸˜o 1, e os algoritmos n˜o podem deixar “buracos” no ca a vetor; 3. o uso da vari´vel auxiliar i no programa facilita muito a manipula¸ao de vetores. a c˜ Sen˜o ter´ a ıamos que usar comandos do tipo: read (v[1]), read (v[2]), read (v[3]), . . . , recaindo nos problemas do in´ do curso; ıcio 4. a t´ ıtulo de exemplo, mostramos a vers˜o deste programa usando os comando a repeat e for. Os trechos de c´digo duas figuras 10.2 e 10.3, abaixo, ilustram o estas duas variantes.begin for i:= 1 to 10 do read (v[ i ] ) ;end. Figura 10.2: Lendo elementos e colocando no vetor, usando for.begin i:= 1; repeat read (v[ i ] ) ; i:= i + 1; until i > 10;end. Figura 10.3: Lendo elementos e colocando no vetor, usando repeat. Uma vez que se leu o vetor, pode-se agora manipular os dados da maneira ne-cess´ria para se resolver o problema desejado. Nas se¸oes seguintes vamos exemplificar a c˜usando diversos algoritmos j´ conhecidos. a
    • 130 CAP´ ITULO 10. ESTRUTURAS DE DADOSImprimindo vetoresO programa ilustrado na figura 10.4 mostra como ler 10 n´meros reais do teclado e uimprim´ı-los na tela. Usaremos o comando for nos exemplos seguintes pois ele faci-lita muito a reda¸ao dos programas que manipulam vetores. Os c´digos ficam mais c˜ ocompactos e leg´ıveis.program lendo e imprimindo vetores ;var v: array [1..200] of real ; i : integer ;begin for i:= 1 to 10 do begin read (v[ i ] ) ; writeln (v[ i ] ) ; end;end. Figura 10.4: Lendo e imprimindo. ´ E importante observar que este programa poderia ter sido resolvido sem o uso devetores, como mostrado na figura 10.5.program lendo e imprimindo vetores ;var x: real ; i : integer ;begin for i:= 1 to 10 do begin read (x) ; writeln (x) ; end;end. Figura 10.5: Lendo e imprimindo. Mostramos esta vers˜o para o leitor poder comparar os dois c´digos e perceber a oque a principal diferen¸a entre as duas solu¸oes ´ que, na vers˜o com vetores, todos c c˜ e aos n´meros lidos do teclado continuam em mem´ria ap´s a leitura do ultimo n´mero u o o ´ udigitado, enquanto que na vers˜o sem vetores, a vari´vel x teria armazenado apenas a ae t˜o somente o ultimo n´mero lido. a ´ u Uma outra maneira de escrever c´digo para resolver o mesmo problema ´ separar o o eprograma em duas partes: uma para a leitura e a outra para a impress˜o. O resultado a´ o mesmo, apenas a maneira de fazer difere. A figura 10.6 ilustra esta solu¸ao.e c˜
    • 10.1. VETORES 131program lendo e imprimindo vetores ;var v: array [1..200] of real ; i : integer ;begin (∗ este pedaco de codigo trata apenas da leitura dos dados ∗) for i:= 1 to 10 do read (v[ i ] ) ; (∗ este outro pedaco de codigo trata apenas da impressao ∗) for i:= 1 to 10 do writeln (v[ i ] ) ;end. Figura 10.6: Lendo e imprimindo. O c´digo apresenta uma certa modularidade, pois pode ser facilmente visualizado ocomo contendo uma parte que se ocupa da leitura dos dados separada da outra parteque se ocupa da impress˜o dos dados. a Apesar do fato deste programa funcionar, insistimos que ele merece ser escritoseguindo as boas t´cnicas de programa¸ao. Neste sentido o uso de fun¸˜es e procedi- e c˜ comentos pode ser explorado para que os dois m´dulos do programa (leitura e impress˜o) o apossam ficar claramente destacados de maneira independente um do outro. O resultado final ´ o mesmo em termos de execu¸ao do programa e de seu resul- e c˜tado final na tela, exibido para quem executa o programa. Por outro lado, para oprogramador, o c´digo ´ mais elegante. Por isto, vamos reescrever mais uma vez o o eprograma, desta vez usando procedimentos. Antes disto, por´m, ´ importante destacar uma limita¸ao da linguagem Pascal : in- e e c˜felizmente, o compilador n˜o aceita um parˆmetro do tipo array. Assim, a constru¸ao a a c˜seguinte gera um erro de compila¸ao: c˜procedure ler (var v: array [1..200] of real) ; Para contornar este problema, a linguagem Pascal permite a defini¸ao de novos c˜tipos de dados baseados em outros tipos pr´-existentes. Isto se consegue com o uso eda declara¸ao type. c˜type vetor= array [1..200] of real ; O que ocorre com o uso da declara¸˜o type ´ que o nome do tipo vetor passa a ca eser conhecido pelo compilador, que por default s´ conhece os tipos pr´-definidos da o elinguagem. O compilador Pascal foi um dos primeiros a permitir que o programadorpudesse definir seus pr´prios tipos. o
    • 132 CAP´ ITULO 10. ESTRUTURAS DE DADOS Assim, para reescrevermos o programa da figura 10.1 usando todo o nosso arse-nal de conhecimentos adquiridos sobre procedimentos, fun¸oes, uso de constantes no c˜c´digo, coment´rios no c´digo, . . . , far´ o a o ıamos como apresentado na figura 10.7.program ler e imprimir ao contrario ;const min=1; max=200;type vetor= array [min . .max] of real ;var v: vetor ;procedure ler (var w: vetor) ; (∗ leitura dos dados ∗)var i : integer ;begin for i:= 1 to 10 do read (w[ i ] ) ;end;procedure imprimir (var w: vetor) ; (∗ impressao dos dados ∗)var i : integer ;begin for i:= 1 to 10 do write (w[ i ] ) ;end;begin (∗ programa principal ∗) ler (v) ; imprimir (v) ;end. Figura 10.7: Lendo e imprimindo, agora com procedimentos. Agora estamos prontos para resolver o problema proposto no in´ deste cap´ ıcio ıtulo,aquele de ler uma sequˆncia de n´meros e imprim´ e u ı-los ao contr´rio. Uma vez que os adados est˜o carregados em mem´ria, ap´s a execu¸ao do procedimento ler(v), podemos a o o c˜manipular os dados da maneira que for necess´rio. No nosso caso, para imprimir ao acontr´rio, basta modificar o procedimento de impress˜o para percorrer o vetor do final a aao in´ ıcio. A figura 10.8 cont´m esta modifica¸ao. Basta agora modificar o programa e c˜principal trocando a chamada imprimir(v) por imprimir ao contrario(v).procedure imprimir ao contrario (var w: vetor) ;var i : integer ;begin for i:= 10 donwto 1 do write (w[ i ] ) ;end; Figura 10.8: Procedimento que imprime os elementos do vetor ao contr´rio. a
    • 10.1. VETORES 133 Algumas observa¸oes importantes: c˜ 1. A leitura ´ feita obrigatoriamente usando-se passagem de parˆmetros por re- e a ferˆncia. A impress˜o pode usar passagem por valor. Contudo, conhecendo o e a fato de que existe uma c´pia de elementos que ´ feita na pilha de mem´ria, isto o e o evidentemente provocar´ uma computa¸ao extra que pode custar caro, especial- a c˜ mente no caso em que os vetores s˜o grandes. Imagine copiar, a toa, um milh˜o a a de elementos. Assim, em geral, vetores s˜o passados sempre por referˆncia. a e 2. O c´digo seria generalizado facilmente se tiv´ssemos passado como parˆmetro o e a o tamanho usado (ou util) do vetor, e n˜o o n´mero fixo 10, al´m do endere¸o ´ a u e c dele. Neste caso, o c´digo da figura 10.9 seria a solu¸ao mais elegante para o o c˜ problema. Observar que o tamanho do vetor ´ lido dentro do procedimento, o e que exige um parˆmetro por referˆncia. a eprogram ler e imprimir ao contrario ;const min=0; max=50;type vetor= array [min . .max] of real ;var v: vetor ; n: integer ;procedure ler (var w: vetor ; var tam: integer) ; (∗ leitura ∗)var i : integer ;begin read (tam) ; (∗ 1 <= tam <= 200, define o tamanho u t i l do vetor ∗) for i:= 1 to tam do read (w[ i ] ) ;end;procedure imprimir ao contrario (var w: vetor ; tam: integer) ; (∗ impressao ∗)var i : integer ;begin for i:= tam donwto 1 do write (w[ i ] ) ;end;begin (∗ programa principal ∗) ler (v, n) ; imprimir ao contrario (v, n) ;end. Figura 10.9: Lendo e imprimindo ao contr´rio, vers˜o final. a a Neste ponto esgotamos o assunto de ler e imprimir vetores e estamos prontos paranovos problemas cujas solu¸oes requerem o uso de vetores, ou tornam o c´digo mais c˜ oelegante.
    • 134 CAP´ ITULO 10. ESTRUTURAS DE DADOS Nas se¸˜es que seguem, vamos considerar dois vetores de tamanhos diferentes, um code inteiros o outro de reais. Nas apresenta¸oes dos algoritmos vamos omitir sempre c˜que poss´ıvel a reda¸˜o dos cabe¸alhos dos programas e nos concentrar apenas na ca csolu¸ao dos novos problemas, sempre usando fun¸oes e procedimentos. As seguintes c˜ c˜defini¸oes ser˜o usadas at´ o final deste cap´ c˜ a e ıtulo:const min r=0; max r=50; min i=1; max i=10;type vetor r= array [ min r . . max r] of real ; vetor i= array [ min i . . max i ] of integer ; Uma ultima observa¸ao, antes de continuarmos. Quando usamos vetores, estamos ´ c˜limitados ao tamanho dele, que deve ser conhecido em tempo de compila¸˜o! Isto pode cacausar dificuldades na resolu¸˜o de problemas que envolvem um n´mero desconhecido ca ude valores de entrada. Mas n˜o tem outro jeito a n˜o ser, em tempo de compila¸ao, se a a c˜estimar um valor m´ximo para o n´mero de elementos no vetor e, durante a execu¸ao, a u c˜testar se este valor nunca foi ultrapassado. Se o n´mero for maior, ent˜o deve-se u amodificar o tamanho do vetor e recompilar. A quest˜o de qual o tamanho ideal para ser o escolhido na hora de compilar ´ a equest˜o de bom-senso e envolve saber de qual aplica¸˜o se est´ falando. Por exemplo, a ca ase for um vetor para armazenar jogos da mega-sena, ent˜o o n´mero 10 ´ suficiente. a u eSe for para guardar saldos de clientes do banco, melhor saber quantos clientes existemhoje e estimar uma margem de erro que depende tamb´m do crescimento m´dio do e en´mero de clientes nos ultimos anos. E assim por diante. u ´Imprimindo os que s˜o pares aVamos retornar ao velho e conhecido problema de se ler uma massa de dados dequantidade indefinida e imprimir apenas aqueles que s˜o pares. a O programa da figura 10.10 ilustra uma procedure com uma poss´ solu¸˜o. A ıvel caleitura dos dados ´ muito similar ao que j´ foi mostrado no exemplo anterior, basta e aadaptar o tipo e dados vetor de reais para vetor de inteiros e por isto apresentamosapenas o que ´ diferente. Observemos a similaridade deste programa com rela¸˜o ao e cac´digo apresentado na figura 9.3. oprocedure imprimir pares (var v: vetor i ; tam: integer) ;var i : integer ;begin for i:= 1 to tam do i f eh par (v[ i ] ) then write (v[ i ] ) ;end; Figura 10.10: Imprimindo os elementos do vetor que s˜o pares. a
    • 10.1. VETORES 135 Aqui se faz uso da fun¸ao booleana “eh par”, que foi estudada na se¸ao 9.2.5. Com c˜ c˜isto conclu´ ımos que os problemas s˜o os mesmos, apenas o uso deles ´ ligeiramente a ediferente por dois motivos: usa-se fun¸oes ou procedimentos, e tamb´m se resolve c˜ eusando-se vetores. O resto n˜o muda. a Um problema que pode parecer o mesmo, mas n˜o ´, seria imprimir os elemen- a etos das posi¸oes pares do vetor, e n˜o mais os elementos cujos conte´dos s˜o pares. c˜ a u aPerceber esta diferen¸a ´ fundamental no estudo de vetores. Consideremos o seguinte c evetor v com tamanho 10 como exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 197 198 199 200 15 12 27 23 7 2 0 18 19 21 ? ? ? ? ? ... ? ? ? ? O c´digo da figura 10.10 produziria como sa´ o seguinte: 12, 2, 0 e 18, que est˜o o ıda arespectivamente nas posi¸oes 2, 6, 7 e 8 do vetor. Se, na linha 5 do programa, n´s c˜ otestarmos se o ´ ındice ´ par (e n˜o o conte´do): e a u i f eh par ( i ) then // no lugar de : i f eh par (v[ i ] ) thenent˜o a sa´ seria: 12, 23, 2, 18 e 21, respectivamente para os elementos das posi¸˜es a ıda co2, 4, 6, 8 e 10 do vetor. Oberve com aten¸ao esta diferen¸a, ´ importante. c˜ c e Como antes, a fun¸ao “eh par” pode ser substitu´ por qualquer outra, como c˜ ıdapor exemplo, ser primo, se divis´ ıvel por n, pertencer ` sequˆncia de Fibonacci, ou a equalquer outra propriedade mais complexa que se queira.Encontrando o menor de uma sequˆncia de n´ meros e uVamos considerar o problema de se ler uma sequˆncia de N > 1 n´meros do teclado e ue imprimir o menor deles. J´ sabemos resolvˆ-lo sem o uso de vetores, conforme a eilustrado na figura 10.11.program menor dos lidos ;var N, i : integer ; x, menor: real ;begin read (N) ; read (x) ; menor:= x; for i:= 2 to N do begin read (x) ; i f x < menor then menor:= x; end; writeln (menor) ;end; Figura 10.11: Encontrando o menor de N n´meros lidos, sem vetor. u
    • 136 CAP´ ITULO 10. ESTRUTURAS DE DADOS Vamos reimplement´-lo em termos de uma fun¸ao que considera que os elementos a c˜digitados no teclado j´ foram lidos em um vetor. A figura 10.12 permite percebermos aque a t´cnica usada foi rigorosamente a mesma: o primeiro n´mero lido ´ considerado e u eo menor de todos. Na leitura dos dados subsequentes, quando um n´mero ainda umenor ´ encontrado, atualiza-se a informa¸˜o de quem ´ o menor de todos. e ca efunction menor dos lidos (var v: vetor r ; N: integer) : real ;var i : integer ; x, menor: real ;begin menor:= v [ 1 ] ; for i:= 2 to N do i f v[ i ] < menor then menor:= v[ i ] ; menor dos lidos:= menor;end; Figura 10.12: Encontrando o menor de N n´meros lidos, com vetor. u10.1.2 Soma e produto escalar de vetoresNesta se¸ao vamos explorar algoritmos ligeiramente mais sofisticados, envolvendo c˜no¸oes novas sobre vetores1 . c˜Somando vetoresNesta se¸ao vamos implementar o algoritmo que soma dois vetores. Para isto preci- c˜samos antes entender como funciona o processo. Sejam v e w dois vetores. Para som´-los, ´ preciso que eles tenham o mesmo a etamanho. Isto posto, o algoritmo cria um novo vetor v + w no qual cada elemento(v + w)[i] do novo vetor ´ a soma dos respectivos elementos v[i] e w[i]. O esquema ´ e econforme a figura seguinte, que apresenta dois vetores de 6 elementos cada: 1 2 3 4 5 6 v: 2 6 1 5 3 3 + + + + + + w: 1 3 2 4 3 5 = = = = = = v+w: 3 9 3 9 6 8 Assim, o algoritmo que soma os dois vetores dever´, para cada i fixo, somar os arespectivos elementos em v e w e guardar em v + w. Variar i de 1 at´ o tamanho do evetor resolve o problema. O programa da figura 10.13 implementa esta ideia. 1 N˜o t˜o novas, j´ que s˜o conceitos estudados no ensino m´dio. a a a a e
    • 10.1. VETORES 137procedure soma vetores (var v, w, soma v w: vetor i ; tam: integer) ;(∗ este procedimento considera que os dois vetores tem o mesmo tamanho ∗)var i : integer ;begin for i:= 1 to tam do soma v w[ i ]:= v[ i ] + w[ i ] ;end; Figura 10.13: Somando dois vetores. Importante notar que i ´ vari´vel local, isto ´, serve apenas para controlar o e a ecomando for interno do procedimento. Tamb´m digno de nota ´ a passagem de e eparˆmetros: no caso de v e w, poder´ a ıamos perfeitamente ter passado por valor, poisn˜o s˜o alterados no procedimento. Isto vale tamb´m para o tamanho do vetor. Mas a a esoma v w deve ser obrigatoriamente passado por referˆncia. e Se, por acaso, os dois vetores tivessem eventualmente tamanhos diferentes o prot´tipo omudaria um pouco e poderia ser assim (desde que na implementa¸ao se teste se c˜tam v = tam w):procedure soma vetores (var v: vetor i ; tam v: integer ; var w: vetor i ; tam w: integer ; var soma v w: vetor i ; tam soma: integer) ;Produto escalarNesta se¸ao vamos implementar o algoritmo que calcula o produto escalar de dois c˜vetores. Para isto precisamos antes entender como funciona o processo. Sejam v e w dois vetores. Para se obter o produto escalar ´ preciso que eles tenham eo mesmo tamanho. Isto posto, o algoritmo gera um n´mero real (ou inteiro, depende udo tipo de dados do vetor) obtido pela soma das multiplica¸˜es de cada elemento i codos vetores dados, respectivamente. O esquema ´ conforme a figura seguinte, que eapresenta dois vetores de 6 elementos cada: 1 2 3 4 5 6 v: 2 6 1 0 3 3 × × × × × × w: 1 0 2 4 3 5 = = = = = = 2 0 2 0 9 15 Os n´meros obtidos a partir das multiplica¸˜es para todos os i fixos devem ser u cosomados: 2 + 0 + 2 + 0 + 9 + 15 = 28. Logo, 28 ´ o produto escalar de v e w. e
    • 138 CAP´ ITULO 10. ESTRUTURAS DE DADOS Assim, o algoritmo que calcula o produto escalar de dois vetores dever´, para cada ai fixo, multiplicar os respectivos elementos em v e w e usar a t´cnica do acumulador epara armazenar as somas parciais. Variar i de 1 at´ o tamanho do vetor resolve o eproblema. O programa que implementa esta ideia ´ apresentado na figura 10.14. efunction prod escalar (var v, w: vetor r ; tam: integer) : real ;var i : integer ; soma: real ;begin soma:= 0; for i:= 1 to tam do soma:= soma + v[ i ] ∗ w[ i ] ; prod escalar:= soma;end; Figura 10.14: Produto escalar de dois vetores. Como procuramos mostrar, programar usando vetores, fun¸˜es e procedimentos con˜o ´ muito diferente de se programar os algoritmos elementares tais como os que a eforam estudados at´ ent˜o. Pelo menos at´ agora. A pr´xima se¸˜o vai apresentar e a e o canovas t´cnicas usando-se estes novos conceitos. e10.1.3 Busca em vetoresNesta se¸ao vamos estudar alguns algoritmos para o importante problema de busca c˜em vetores. Em outras palavras, estamos interessados em saber se um dado elementox ´ um dos elementos de um vetor v e, caso seja, tamb´m podemos querer saber a e eposi¸ao onde este elemento se encontra. c˜ Este problema ´ extremamente importante em computa¸ao e n˜o ´ dif´ imaginar e c˜ a e ıcilaplica¸oes no nosso dia a dia. Por exemplo, localizar um livro na biblioteca, localizar c˜um filme na videolocadora, saber se um dado CPF est´ cadastrado em alguma lista ade cheques, e por ai vai. O tema de busca em vetores ´ t˜o importante que ´ estudado de diversas maneiras e a eao longo de um curso de ciˆncia da computa¸ao. Em um curso introdut´rio iremos e c˜ oestudar os mais elementares para o caso de vetores de reais ou inteiros. Ao longo desta se¸˜o, vamos considerar sempre que um dado vetor v j´ foi lido em ca amem´ria de alguma maneira. Assim, vamos elaborar algoritmos na forma de fun¸˜es o coou procedimentos. A ideia ´, como tem sido at´ aqui, inicar por algo trivial e evoluir e ea qualidade da solu¸ao. c˜ N´s iremos convencionar que as fun¸˜es ter˜o sempre o mesmo prot´tipo, que ´ o co a o eassim definido:(∗ Recebe um valor x que deve ser procurado no vetor v que tem tamanho n. ∗)(∗ Se for encontrado , retorna a posicao do elemento , senao retorna zero . ∗)function busca (x: real ; var v: vetor r ; n: integer) : integer ;
    • 10.1. VETORES 139 O algoritmo mais ingˆnuo poss´ ´ mostrado na figura 10.15. e ıvel efunction busca (x: real ; var v: vetor r ; n: integer) : integer ;var i : integer ;begin busca:= 0; for i:= 1 to n do i f v[ i ] = x then busca:= i ;end; Figura 10.15: Busca em vetores, primeira vers˜o. a Este algoritmo sempre acha o elemento x em v se ele estiver presente, pois elevarre todo o vetor comparando cada elemento com x. Caso x esteja presente duasvezes ou mais, ele retorna a posi¸ao da ultima ocorrˆncia. O algoritmo sempre faz n c˜ ´ ecompara¸oes, por causa do comando for. Por isto diz-se que o n´mero de compara¸oes c˜ u c˜que o algoritmo realiza ´ proporcional ao tamanho do vetor. e De fato, em qualquer programa sempre ´ interessante analisar o que custa mais ecaro no c´digo. Entendemos por “custar caro” como sendo o comando que ´ executado o eo maior n´mero de vezes durante uma rodada do programa. u Neste caso, temos um comando if, que faz um teste de igualdade (uma com-para¸ao), dentro do escopo de um comando for, o qual ´ controlado pela vari´vel n. c˜ e aLogo, esta compara¸˜o ser´ executada sempre n vezes. ca a Apesar do algoritmo funcionar, ele faz compara¸oes demais: mesmo quando o c˜elemento j´ foi encontrado o vetor ´ percorrido at´ o final. Obviamente ele poderia a e eparar na primeira ocorrˆncia, pois n˜o foi exigido no enunciado que fossem localizadas e atodas as ocorrˆncias (este ´ outro problema). Ent˜o podemos modificar o c´digo para e e a oa vers˜o apresentada na figura 10.16, simplesmente trocando-se o for por um while aque termina a execu¸ao t˜o logo o elemento seja encontrado (se for encontrado). c˜ a Este algoritmo ´ mais r´pido, na m´dia, do que o anterior, embora o n´mero de e a e ucompara¸oes feitas possa ser a mesma no caso do elemento n˜o estar presente no c˜ avetor. Mas, se dermos sorte, o elemento pode estar no in´ do vetor e terminar bem ıcior´pido. Na m´dia, espera-se que ele pare mais ou menos na metade do vetor, isto ´, a e econsiderando-se uma distribui¸ao uniforme dos elementos. c˜ Mas como o la¸o faz dois testes, no caso do elemento n˜o ser encontrado ele ser´ c a aum pouco mais lento. Notem que o duplo teste no la¸o ´ necess´rio pois deve parar c e aou porque achou o elemento ou porque o vetor terminou. Este segundo teste s´ vai odar true uma unica vez, o que ´ um desped´ ´ e ıcio. Se pudesse haver garantia de que sempre o elemento procurado estivesse presente,ent˜o poder´ a ıamos construir um teste simples, o que pode nos economizar algumacomputa¸ao. Esta garantia n˜o pode existir, certo? Mais ou menos. Digamos que o c˜ aprogramador deliberadamente coloque o elemento no vetor. Neste caso, h´ a garantia a
    • 140 CAP´ ITULO 10. ESTRUTURAS DE DADOSfunction busca (x: real ; var v: vetor r ; n: integer) : integer ;var i : integer ; achou : boolean;begin achou:= false ; i:= 1; while ( i <= n) and not achou do begin i f v[ i ] = x then achou:= true; i:= i + 1; end; i f achou then busca:= i − 1;end; Figura 10.16: Busca em vetores, segunda vers˜o. ade que ele est´ presente. Mas algu´m pode perguntar: assim n˜o vale, se eu coloco a e an˜o significa que ele j´ estava presente, eu vou sempre encontrar o elemento “falso”. a a Novamente, depende de onde o programador coloque o elemento. Digamos que eleo coloque logo ap´s a ultima posi¸ao. Ent˜o, das duas uma: ou o elemento n˜o estava o ´ c˜ a ano vetor original, e neste caso a busca pode terminar pois o elemento ser´ encontrado aap´s a ultima posi¸ao; ou o elemento estava presente e ser´ encontrado antes daquele o ´ c˜ aque foi adicionado. Um teste final resolve a d´vida. Se for encontrado em posi¸˜o u cav´lida, ´ porque estava presente, sen˜o, n˜o estava. a e a a Este elemento adicionado logo ap´s o final do vetor ´ denominado sentinela e seu o euso ´ ilustrado na vers˜o apresentada na figura 10.17. e afunction busca (x: real ; var v: vetor r ; n: integer) : integer ;var i : integer ;begin v[n+1]:= x; i:= 1; while v[ i ] < x do > i:= i + 1; i f i <= n then busca:= i else busca:= 0;end; Figura 10.17: Busca em vetores com sentinela. Apesar da melhoria, este algoritmo sempre faz um n´mero de compara¸˜es que u copode atingir n no pior caso, isto ´, quando o elemento n˜o est´ presente no vetor. e a a O caso ´timo e o caso m´dio n˜o mudam, embora o algoritmo, conforme explicado, o e a
    • 10.1. VETORES 141fa¸a metade das compara¸˜es quando comparado com a vers˜o anterior. Desta forma c co aele ´ apenas ligeiramente melhor do que o anterior. e Ainda, o programador deve garantir que a posi¸ao usada pelo sentinela nunca seja c˜usada como sendo um elemento v´lido, pois n˜o ´. O programador colocou o elemento a a eali de maneira controlada, mas n˜o se trata de um elemento v´lido. Isto significa que a ao n´mero de elementos uteis do vetor agora n˜o ´ mais max r (ou max i), mas sempre u ´ a eum a menos. Normalmente se modifica a defini¸ao do tipo para prever este espa¸o c˜ cadicional para o programador.const min r=0; max r=50; min i=1; max i=10;type vetor r= array [ min r . . max r+1] of real ; vetor i= array [ min i . . max i+1] of integer ; ´ E poss´ tornar o algoritmo mais eficiente? ıvel A resposta ´ sim2 . Mas, para tornar a busca mais eficiente ´ preciso impor algumas e erestri¸oes extra na forma como os dados s˜o organizados em mem´ria.. c˜ a o Esta maneira consiste em considerar que os dados est˜o de alguma forma respei- atando uma ordem lexicogr´fica em mem´ria. Por exemplo, se forem nomes, est˜o a o aem ordem alfab´tica. Se forem n´meros, est˜o em ordem crescente (ou descrescente). e u aPorque isto ´ necess´rio? Pois pode-se explorar a informa¸˜o de ordena¸˜o para tornar e a ca cao m´todo mais eficiente. e No caso, podemos modificar a solu¸˜o anterior para que o algoritmo termine a cabusca sempre que encontrar um elemento que j´ ´ maior do que aquele que se est´ ae aprocurando, pois o vetor est´ ordenado. O programa da figura 10.18 foi implementado acom esta ideia.function busca (x: real ; var v: vetor r ; n: integer) : integer ;var i : integer ;begin v[n+1]:= x; i:= 1; while v[ i ] < x do i:= i + 1; i f (v[ i ] = x) and ( i <= n) then busca:= i else busca:= 0;end; Figura 10.18: Busca em vetores ordenados. Apesar de termos explorado uma propriedade adicional que faz com que no caso 2 Em disciplinas avan¸adas de algoritmos se estudam m´todos bastante eficientes para este pro- c eblema. No nosso caso veremos apenas um deles.
    • 142 CAP´ ITULO 10. ESTRUTURAS DE DADOSm´dio a busca seja mais eficiente, no pior caso, aquele em que o elemento procurado en˜o pertence ao vetor, ainda temos um algoritmo que faz tantas compara¸˜es quanto a coo tamanho do vetor. E´ poss´ fazer melhor? A resposta novamente ´ sim. ıvel e Como exemplo, considere o problema de se encontrar um verbete no dicion´rio. aSabemos que estes verbetes se encontram em ordem alfab´tica. Por este motivo, eningu´m em s˜ consciˆncia procura um nome em ordem sequencial desde o in´ e a e ıcio, amenos que esteja procurando algo que come¸a com a letra “A”. c Suponha que o verbete inicia com a letra “J”. Normalmente se abre o dicion´rio amais ou menos no meio. Se o nome presente no in´ da p´gina for “menor” lexico- ıco agraficamente falando do que aquele que se busca, por exemplo, algo come¸ando com ca letra “D”, ent˜o, pode-se tranquilamente rasgar o dicion´rio, eliminando-se tudo o a aque est´ antes do “D” e continuar o processo com o que restou. a Na segunda tentativa abre-se novamente mais ou menos na metade do que sobrou.Suponha que ca´ ımos na letra “M”. Como estamos procurando o “J”, pode-se semproblemas rasgar novamente o dicion´rio eliminando-se tudo o que segue o “M”, at´ a eo fim. Resta procurar “apenas” entre o “D” e o “M”. Aplicando-se consistentemente este processo repetidas vezes, sempre teremos umdicion´rio dividido mais ou menos por 2. Se ele tinha 500 p´ginas no in´ a a ıcio, na segundavez ter´ 250 e na terceira 125, na quarta algo pr´ximo de 70 p´ginas. E assim por a o adiante. Por isto que costumamos localizar rapidamente verbetes em um dicion´rio. a O algoritmo mostrado na figura 10.20, denominado de busca bin´ria, implementa aesta ideia. Procura-se o elemento no meio do vetor. Se encontrou, ent˜o pode parar. aSe n˜o encontrou, basta verificar se o valor encontrado ´ maior ou menor do que o a eprocurado. Se for maior, joga-se a metade superior fora e trabalha-se apenas coma metade inferior. Se for menor, joga-se fora a metade inferior e trabalha-se apenascom a metade superior. Novamente procura-se na metade do que sobrou e assim pordiante, at´ que se encontre o elemento ou at´ que se determine que n˜o ´ mais poss´ e e a e ıvelencontr´-lo. a Vamos agora comparar estas ultimas quatro vers˜es para o algoritmo de busca. ´ oA tabela 10.19 resume o n´mero de compara¸oes feitas para diversos tamanhos de u c˜entrada, sempre analisando o pior caso. O caso m´dio exige um pouco mais de cui- edado para se calcular e n˜o ser´ estudado aqui. O caso otimo ´ sempre uma unica a a ´ e ´compara¸ao para os casos: o algoritmo acha o elemento na primeira tentativa. c˜ Vers˜o a n = 10 n = 102 n = 104 n = 108 Busca simples (fig. 10.16) 20 200 20000 200000000 Busca com sentinela (fig. 10.17) 10 100 10000 100000000 Busca em vetor ordenado (fig. 10.18) 10 100 10000 100000000 Busca bin´ria (fig. 10.20) a 3 5 10 19Figura 10.19: Tabela resumindo n´mero de compara¸oes para algoritmos de busca. u c˜
    • 10.1. VETORES 143function busca (x: real ; var v: vetor r ; n: integer) : integer ;var inicio , fim , meio : integer ;begin inicio :=1; (∗ aponta para o inicio do vetor ∗) fim:= n; (∗ aponta para o fim do vetor ∗) meio:= ( inicio + fim) div 2; (∗ aponta para o meio do vetor ∗) while (v[ meio ] < x) and (fim >= inicio ) do > begin i f v[ meio ] > x then (∗ vai jogar uma das duas metades fora ∗) fim:= meio − 1 (∗ metade superior foi jogada fora ∗) else inicio:= meio + 1; (∗ metade inferior foi jogada fora ∗) meio:= ( inicio + fim) div 2; (∗ recalcula apontador para meio ∗) end; (∗ o laco termina quando achou ou quando o fim ficou antes do inicio ∗) i f v[ meio ] = x then busca:= meio else busca:= 0;end; Figura 10.20: Busca bin´ria. a O importante do m´todo da busca bin´ria ´ que ela apresenta um car´ter lo- e a e agar´ ıtmico para o pior caso com rela¸ao ao tamanho da entrada, o que ´ bastante c˜ esignificativo. Contudo, ´ absolutamente relevante destacar que este m´todo s´ pode e e oser aplicado em vetores ordenados, sen˜o n˜o funciona. A quest˜o ´ saber qual o a a a ecusto de se ordenar, ou de se manter ordenado, um vetor. Isto ser´ estudado a frente. a `Manipulando vetores ordenadosQuando opera¸˜es de inser¸˜o e remo¸ao s˜o feitas em vetores ordenados ´ impor- co ca c˜ a etante que estas altera¸oes em seus elementos preservem a propriedade do vetor estar c˜ordenado, por exemplo, para que se possa usar uma busca bin´ria. a A seguir apresentamos solu¸oes para se remover ou inserir um elemento de um c˜vetor, iniciando pela remo¸ao. O procedimento da figura 10.21 garante a remo¸ao do c˜ c˜elemento que est´ na posi¸˜o pos do vetor v que tem tamanho n. a caprocedure remove (pos : integer ; var v: vetor r ; var n: integer) ;var i : integer ;begin for i:= pos to n−1 do v[ i ]:= v[ i +1]; n:= n − 1;end; Figura 10.21: Removendo de um vetor ordenado.
    • 144 CAP´ ITULO 10. ESTRUTURAS DE DADOS Remover elementos n˜o ´ t˜o trivial quanto parece, pois n˜o podemos deixar a e a a“buracos” no vetor. Este algoritmo ent˜o copia todos os elementos que est˜o a frente a a `daquele que foi removido uma posi¸ao para tr´s. Tomemos como exemplo o seguinte c˜ avetor ordenado: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 197 198 199 200 0 2 7 12 15 18 19 21 23 27 ? ? ? ? ? ... ? ? ? ? Para remover o elemento 12, que est´ na posi¸˜o 4, todos os outros s˜o copiados, a ca aum por um. Para n˜o perdermos elementos, este processo tem que iniciar da posi¸ao a c˜onde houve a remo¸˜o at´ a pen´ltima posi¸ao. O vetor resultante ´ o seguinte: ca e u c˜ e 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 197 198 199 200 0 2 7 15 18 19 21 23 27 27 ? ? ? ? ? ... ? ? ? ? O detalhe ´ que o elemento 27 que estava na posi¸ao 10 continua l´, mas, como o e c˜ avetor agora tem tamanho 9 (pois um elemento foi removido) este ultimo 27 agora ´ ´ elixo de mem´ria. o Com rela¸˜o ao algoritmo de inser¸ao de um elemento em um vetor ordenado, ca c˜deve-se primeiro determinar a posi¸ao correta de inser¸˜o, logo, um processo de busca c˜ cadeve ser feito, iniciando do come¸o do vetor (posi¸ao 1) at´ que seja encontrado um c c˜ eelemento maior que aquele que est´ se inserindo. Para facilitar esta busca, usamos auma sentinela. Tomemos novamente como exemplo o vetor abaixo e consideremos que vamosinserir o elemento 17. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 197 198 199 200 0 2 7 12 15 18 19 21 23 27 ? ? ? ? ? ... ? ? ? ? A posi¸ao correta do 17 ´ logo ap´s o elemento 15, isto ´, na posi¸ao 6. Para c˜ e o e c˜abrirmos espa¸o no vetor e ao mesmo tempo n˜o perdermos o 18 que l´ est´ devemos c a a acopiar todos os elementos, um por um, uma posi¸˜o para frente. Isto deve ser feito cade tr´s para frente, isto ´, copia-se o ultimo uma posi¸ao adiante para abrir espa¸o a e ´ c˜ cpara colocar o pen´ltimo, e assim por diante. O resultado seria um vetor assim: u 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 197 198 199 200 0 2 7 12 15 18 18 19 21 23 27 ? ? ? ? ... ? ? ? ? Observe que agora temos duas vezes o 18 no vetor. O primeiro deles agora podeser substitu´ pelo novo elemento, o 17, assim: ıdo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 197 198 199 200 0 2 7 12 15 17 18 19 21 23 27 ? ? ? ? ... ? ? ? ?
    • 10.1. VETORES 145procedure insere (x: real ; var v: vetor r ; var n: integer) ;var i : integer ;begin v[0]:= x; i:= n + 1; while x < v[ i ] do begin v[ i+1]:= v[ i ] ; i:= i − 1; end; n:= n + 1;end; Figura 10.22: Inserindo em um vetor ordenado. O procedimento da figura 10.22 insere um elemento x no vetor v que tem tamanhon de maneira que ele continue ordenado. Apenas uma passagem no vetor ´ feita: ao emesmo tempo em que ele est´ procurando a posi¸ao correta do elemento ele j´ vai a c˜ aabrindo espa¸o no vetor. c No caso de vetores n˜o ordenados, os processo de inser¸˜o e remo¸˜o s˜o mais a ca ca asimples. Pode-se sempre inserir um elemento novo no final do vetor e para remover,basta copiar o ultimo sobre o que foi removido. ´ H´ um ultimo algoritmo interessante que trabalha com vetores ordenados: a ideia a ´ 3´ fundir dois vetores ordenados em um terceiro, obtendo-se um vetor ordenado comoeresultado contendo os mesmos elementos dos vetores anteriores. O princ´ıpio deste algoritmo ´: atribui-se a duas vari´veis i e j o ´ e a ındice 1. Emseguida se compara os respectivos elementos das posi¸˜es i em um vetor e j no outro. coSe o elemento do primeiro vetor ´ menor do que o do segundo, ele ´ copiado no terceiro e evetor e o apontador i ´ incrementado de 1, passando a observar o pr´ximo elemento. e oSen˜o, o elemento do segundo vetor ´ menor e portanto este que ´ copiado para o a e eterceiro vetor e o apontador j que ´ incrementado. Quando um dos dois vetores eacabar, basta copiar o restante do outro no terceiro vetor. Um apontador k controlao terceiro vetor. Este ´ sempre incrementado a cada c´pia. e o Vejamos isto atrav´s de um exemplo. Consideremos os seguintes dois vetores eordenados e um terceiro que vai receber a fus˜o dos dois. a i=1 2 3 4 5 v: 2 4 5 7 9 j=1 2 3 w: 1 3 6 k=1 2 3 4 5 6 7 8 r: 3 Em inglˆs, merge e
    • 146 CAP´ ITULO 10. ESTRUTURAS DE DADOScomparam-se o elementos apontados por i e j. Como 1 < 2, copia-se o 1 no vetor r eincrementa-se o apontador j, assim: i=1 2 3 4 5 v: 2 4 5 7 9 1 j=2 3 w: 1 3 6 1 k=2 3 4 5 6 7 8 r: 1Agora comparam-se o elementos apontados por i e j. Como 2 < 3, copia-se o 2 novetor r e incrementa-se o apontador i, assim: 1 i=2 3 4 5 v: 2 4 5 7 9 1 j=2 3 w: 1 3 6 1 2 k=3 4 5 6 7 8 r: 1 2Repetindo-se este processo mais algumas vezes chegaremos no seguinte estado: 1 2 3 i=4 5 v: 2 4 5 7 9 1 2 j=3 w: 1 3 6 1 2 3 4 k=5 6 7 8 r: 1 2 3 4 5 Neste ponto o 6 ser´ copiado em r e o vetor w termina. Basta copiar o que sobrou ade v e terminar o processo, o que resultar´ no seguinte: a 1 2 3 4 5 i=6 v: 2 4 5 7 9 1 2 3 j=4 w: 1 3 6 1 2 3 4 5 6 7 8 k=9 r: 1 2 3 4 5 6 7 9 O algoritmo da figura 10.23 implementa o que foi discutido, ´ eficiente e varre os edois vetores apenas uma vez.
    • 10.1. VETORES 147procedure merge (var v: vetor r ; n: integer ; var w: vetor r ; m: integer ; r : vetor r ) ;var i , j , k, l : integer ;begin i:= 1; j:= 1; k:= 1; (∗ i vai controlar os elementos de v ∗) (∗ j vai controlar os elementos de w ∗) (∗ k vai controlar os elementos do vetor resultante da fusao , r ∗) while ( i <= n) and ( j <= m) do begin i f v[ i ] <= w[ j ] then (∗ se o elemento de v dh menor que o de w ∗) begin r [k]:= v[ i ] ; i:= i + 1; end else (∗ o elemento de w eh menor que o de v ∗) begin r [k]:= w[ j ] ; j:= j + 1; end; k:= k + 1; (∗ k eh sempre incrementado ∗) end; (∗ quando sai do laco , um dos dois vetores acabou ∗) i f i <= n then (∗ w acabou, copiar o restante de v em r ∗) for l:= i to n do begin r [k]:= v[ l ] ; k:= k + 1; end; else (∗ v acabou, copiar o restante de w em r ∗) for l:= i to m do begin r [k]:= w[ l ] ; k:= k + 1; end;end; Figura 10.23: Fundindo dois vetores ordenados.
    • 148 CAP´ ITULO 10. ESTRUTURAS DE DADOS10.1.4 Ordena¸˜o em vetores caOrdenar vetores ´ extremamente importante em computa¸ao, pois ´ muito comum e c˜ eque uma sa´ de um programa seja dado com algum tipo de ordem sobre os dados. ıdaNesta se¸ao vamos apresentar dois algoritmos para este problema: os m´todos da c˜ eordena¸ao por sele¸ao e por inser¸ao. c˜ c˜ c˜Ordena¸˜o por sele¸˜o ca caA ordena¸ao por sele¸ao ´ um m´todo bastante simples de se compreender e tamb´m c˜ c˜ e e ede se implementar. O princ´ıpio ´ selecionar os elementos corretos para cada posi¸ao do vetor, da´ o e c˜ ınome do m´todo. Para um vetor de N elementos, existem N − 1 etapas. Em cada eetapa i o i-´simo menor elemento ´ selecionado e colocado na posi¸ao i. e e c˜ Assim, na primeira etapa, o menor elemento de todos ´ localizado (selecionado) e ecolocado na primeira posi¸ao do vetor. Na segunda etapa localiza-se o segundo menor c˜e coloca-se na segunda posi¸ao, e assim por diante, at´ que, por fim, o pen´ltimo c˜ e umenor elemento (isto ´, o segundo maior) ´ colocado na pen´ltima posi¸˜o. Con- e e u casequentemente, como j´ temos N − 1 elementos em seus devidos lugares, o ultimo a ´tamb´m est´. Vejamos um exemplo de um vetor com 10 elementos. e a 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 197 198 199 200 15 12 27 23 7 2 0 18 19 21 ? ? ? ? ? ... ? ? ? ? Para localizarmos o menor elemento, que ´ o zero que est´ na posi¸ao 7 do vetor, e a c˜s´ h´ uma maneira, que ´ percorrer todo o vetor e localizar o menor. Este deve ser o a ecolocado na primeira posi¸˜o. Este ultimo (o 15), por sua vez, deve ser trocado de ca ´posi¸ao com o da posi¸˜o 7. Por isto a busca pelo menor deve nos retornar o ´ c˜ ca ındice domenor elemento e n˜o o elemento em s´ O resultado da primeira etapa deste processo a ı.est´ mostrado na figura abaixo, com destaque para os elementos trocados. a 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 197 198 199 200 0 12 27 23 7 2 15 18 19 21 ? ? ? ? ? ... ? ? ? ? Neste ponto precisamos do segundo menor. Por constru¸ao l´gica do algoritmo, c˜ obasta percorrer o vetor a partir da segunda posi¸ao, pois o primeiro j´ est´ em seu c˜ a alugar. O menor de todos agora ´ o 2, que est´ na posi¸˜o 6. Basta troc´-lo pelo e a ca asegundo elemento, que ´ o 12. E o processo se repete: e 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 197 198 199 200 0 2 27 23 7 12 15 18 19 21 ? ? ? ? ? ... ? ? ? ? 0 2 7 23 27 12 15 18 19 21 ? ? ? ? ? ... ? ? ? ? 0 2 7 12 27 23 15 18 19 21 ? ? ? ? ? ... ? ? ? ? 0 2 7 12 15 23 27 18 19 21 ? ? ? ? ? ... ? ? ? ? 0 2 7 12 15 18 27 23 19 21 ? ? ? ? ? ... ? ? ? ? 0 2 7 12 15 18 19 23 27 21 ? ? ? ? ? ... ? ? ? ? 0 2 7 12 15 18 19 21 27 23 ? ? ? ? ? ... ? ? ? ? 0 2 7 12 15 18 19 21 23 27 ? ? ? ? ? ... ? ? ? ?
    • 10.1. VETORES 149procedure selecao (var v: vetor r ; n: integer) ;var i , j : integer ; aux: real ;begin for i:= 1 to n−1 do begin (∗ acha a posicao do menor a partir de i ∗) pos menor:= i ; for j:= i+1 to n do (∗ inicia a partir de i+1 ∗) i f v[ j ] < v[ pos menor ] then pos menor:= j ; aux:= v[ pos menor ] ; (∗ troca os elementos ∗) v[ pos menor]:= v[ i ] ; v[ i ]:= aux; end;end; Figura 10.24: M´todo de ordena¸˜o por sele¸˜o. e ca ca A figura 10.24 mostra a vers˜o em Pascal deste algoritmo. a Este algoritmo tem algumas particularidades dignas de nota. A primeira ´ que, em ecada etapa i, a ordena¸ao dos primeiros i − 1 elementos ´ definitiva, isto ´, constitui c˜ e ea ordena¸ao final destes primeiros i elementos do vetor. c˜ A segunda ´ que a busca pelo menor elemento em cada etapa i exige percorrer eum vetor de N − i elementos. Como isto ´ feito N vezes, ent˜o o n´mero de com- e a upara¸oes feitas na parte mais interna do algoritmo ´ sempre N (N −1) , o que define um c˜ e 2comportamento quadr´tico para as compara¸oes. a c˜ A terceira ´ que trocas de posi¸˜es no vetor ocorrem no la¸o mais externo, por e co cisto o n´mero total de trocas feitas pelo algoritmo ´ sempre N − 1. u eOrdena¸˜o por inser¸˜o ca caA ordena¸ao por inser¸ao ´ provavelmente a mais eficiente, na pr´tica, que a ordena¸ao c˜ c˜ e a c˜por sele¸ao. Por´m, embora o algoritmo em s´ seja simples, sua implementa¸ao ´ c˜ e ı c˜ erepleta de detalhes. Vamos inicialmente entender o processo. O princ´ ıpio do algoritmo ´ percorrer o vetor e a cada etapa i, o elemento da eposi¸ao i ´ inserido (da´ o nome do m´todo) na sua posi¸ao correta relativamente c˜ e ı e c˜quando comparado aos primeiros i − 1 elementos. Para melhor compreens˜o, faremos a apresenta¸ao de um exemplo sem mostrarmos a c˜o vetor, usaremos sequˆncias de n´meros. Consideremos que a entrada ´ a mesma do e u eexemplo anterior, isto ´:e 15, 12, 27, 23, 7, 2, 0, 18, 19, 21. Na primeira etapa o algoritmo considera que o primeiro elemento, o 15, est´ na asua posi¸ao relativa correta, pois se considera apenas a primeira posi¸ao do vetor. c˜ c˜Usaremos os negritos para mostrar quais as etapas j´ foram feitas pelo algoritmo. a
    • 150 CAP´ ITULO 10. ESTRUTURAS DE DADOS Na segunda etapa deve-se inserir o segundo elemento em sua posi¸ao relativa cor- c˜reta considerando-se apenas o vetor de tamanho 2. Como o 12 ´ menor que que o 15, edeve-se trocar estes elementos de posi¸˜o, nos resultando na sequˆncia: ca e 12, 15, 27, 23, 7, 2, 0, 18, 19, 21. Neste ponto, os elementos 12 e 15 est˜o em suas posi¸˜es relativas corretas considerando- a cose um vetor de 2 posi¸oes. Agora, deve-se colocar o 27 no vetor de 3 elementos. Mas c˜o 27 j´ est´ em seu lugar relativo, ent˜o o algoritmo n˜o faz nada: a a a a 12, 15, 27, 23, 7, 2, 0, 18, 19, 21. Na quarta etapa deve-se inserir o 23 na sua posi¸ao relativa correta considerando-se c˜um vetor de 4 elementos. O 23 tem que estar entre o 15 e o 27: 12, 15, 23, 27, 7, 2, 0, 18, 19, 21. Na quinta etapa deve-se inserir o 7 na sua posi¸ao relativa a um vetor de 5 ele- c˜mentos. Ele deve ser inserido antes do 12, isto ´, na primeira posi¸˜o: e ca 7, 12, 15, 23, 27, 2, 0, 18, 19, 21. A situa¸˜o para o 2 ´ similar, deve ser inserido antes do 7, isto ´, no in´ ca e e ıcio: 2, 7, 12, 15, 23, 27, 0, 18, 19, 21. Idem para o zero: 0, 2, 7, 12, 15, 23, 27, 18, 19, 21. Agora ´ a vez de inserirmos o 18, entre o 15 e o 27: e 0, 2, 7, 12, 15, 18, 23, 27, 19, 21. Na pen´ltima etapa inserimos o 19 entre o 18 e o 23: u 0, 2, 7, 12, 15, 18, 19, 23, 27, 21. E por ultimo o 21 entre o 19 e o 23: ´ 0, 2, 7, 12, 15, 18, 19, 21, 23, 27. Esta sequˆncia de N passos ´ de f´cil compreens˜o. Se fˆssemos executar com e e a a oum conjunto de cartas na m˜o, por exemplo, com cartas de baralho, imaginando um ama¸o de cartas virado na mesa, basta pegar as cartas uma a uma e encaixar no lugar ccerto. As cartas de baralho s˜o facilmente manipuladas para permitir uma inser¸˜o a caem qualquer posi¸˜o. ca Infelizmente esta opera¸˜o executada em um vetor n˜o ´ t˜o simples. Vamos consi- ca a e aderar como exemplo a etapa 8 acima, isto ´, inser¸ao do 18 no lugar certo. Retomemos e c˜este caso agora considerando um vetor para melhor ilustra¸ao, com destaque para o c˜elemento 18 que deve nesta etapa ser inserido no lugar certo:
    • 10.1. VETORES 151 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 197 198 199 200 0 2 7 12 15 23 27 18 19 21 ? ? ? ? ? ... ? ? ? ? A posi¸˜o correta do 18, como vimos, ´ entre o 15 e o 23, isto ´, na sexta posi¸ao ca e e c˜do vetor. Significa que os elementos das posi¸oes 6 e 7 devem ser movidos um para c˜frente para abrir espa¸o no vetor para inser¸˜o do 18. Os elementos das posi¸oes 9 c ca c˜em diante n˜o v˜o mudar de lugar. Executando esta opera¸˜o, e salvando o 18 em a a caalguma vari´vel tempor´ria, obteremos o seguinte vetor: a a 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 197 198 199 200 0 2 7 12 15 23 23 27 19 21 ? ? ? ? ? ... ? ? ? ? Isto ´, o 27 foi copiado da posi¸ao 7 para a posi¸˜o 8 e o 23 foi copiado da posi¸ao e c˜ ca c˜6 para a posi¸ao 7. Na figura acima destacamos os elementos que foram movidos de c˜lugar. Observando que o 23 ficou repetido na posi¸ao 6, o que na pr´tica resultou na c˜ aposi¸ao 6 livre. Agora basta inserir o 18 a´ c˜ ı: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 197 198 199 200 0 2 7 12 15 18 23 27 19 21 ? ? ? ? ? ... ? ? ? ? Esta etapa constitui o n´cleo do algoritmo mostrado na figura 10.25. O la¸o u cexterno apenas garante que esta opera¸ao ser´ executada para todos os elementos das c˜ aposi¸oes de 1 at´ N . c˜ e O la¸o interno foi implementado de tal forma que, ao mesmo tempo em que se clocaliza o lugar certo do elemento da vez, j´ se abre espa¸o no vetor. O la¸o ´ a c c econtrolado por dois testes, um deles para garantir que o algoritmo n˜o extrapole o ain´ do vetor, o outro que compara dois elementos e troca de posi¸ao sempre que for ıcio c˜detectado que o elemento est´ na posi¸ao incorreta. a c˜procedure insercao (var v: vetor ; n: integer) ;var i , j : integer ; aux: real ;begin for i:= 1 to n do begin aux = v[ i ] ; (∗ abre espaco no vetor enquanto localiza a posicao certa ∗) j:= i − 1; while ( j >= 1) and (v[ j ] > aux) do begin v[ j+1] = v[ j ] ; j:= j − 1; end; v[ j+1] = aux; end;end; Figura 10.25: M´todo de ordena¸˜o por inser¸˜o. e ca ca
    • 152 CAP´ ITULO 10. ESTRUTURAS DE DADOS Analisar quantas compara¸˜es s˜o feitas ´ bem mais complicado neste algoritmo, co a epois isto depende da configura¸˜o do vetor de entrada. Neste nosso exemplo, vimos caque cada etapa teve um comportamento diferente das outras. Em uma vez o elementoj´ estava em seu lugar. Em duas outras vezes tivemos que percorrer todo o subvetor ainicial, pois os elementos deveriam ser o primeiro, em cada etapa. Aparentemente, no pior caso poss´ıvel, que ´ quando o vetor est´ na ordem inversa e ada ordena¸ao, haver´ o maior n´mero de compara¸oes, que ´ quadr´tico. Mas, na c˜ a u c˜ e apr´tica, este algoritmo aparenta ser mais r´pido que o m´todo da sele¸ao na maior a a e c˜parte dos casos, pois algumas vezes o elemento muda pouco de posi¸˜o.4ca10.1.5 Outros algoritmos com vetoresNesta se¸˜o vamos apresentar alguns problemas interessantes que podem ser resolvidos causando-se a estrutura de vetores.Permuta¸oes c˜Vamos apresentar um problema matem´tico conhecido como permuta¸˜o, propor uma a carepresenta¸˜o computacional em termos de vetores, e, em seguida, estudar alguns caproblemas interessantes do ponto de vista de computa¸˜o.5 ca Os matem´ticos definem uma permuta¸˜o de algum conjunto como uma fun¸ao a ca c˜bijetora de um conjunto nele mesmo. Em outras palavras, ´ uma maneira de reor- edenar os elementos do conjunto. Por exemplo, podemos definir uma permuta¸ao do c˜conjunto {1, 2, 3, 4, 5 } assim: P (1) = 4, P (2) = 1, P (3) = 5, P (4) = 2, P (5) = 3.Esquematicamente temos: 1 2 3 4 5 4 1 5 2 3 Outra maneira seria: P (1) = 2, P (2) = 5, P (3) = 1, P (4) = 3, P (5) = 2. Esque-maticamente: 1 2 3 4 5 2 5 1 3 2 De fato, existem n! maneiras de se reordenar os elementos e obter uma permuta¸ao c˜v´lida. Se n = 5 ent˜o existem 120 permuta¸oes. a a c˜ Modelando permuta¸˜es co O primeiro problema interessante do ponto de vista algoritmico ´ como representar e 4 O site http://cg.scs.carleton.ca/~morin/misc/sortalg permite visualizar o comporta-mento dos principais algoritmos de ordena¸˜o atrav´s de anima¸˜es. Os dois algoritmos aqui ex- ca e coplicados est˜o l´, entre outros. a a 5 Esta se¸˜o foi inspirada em uma preparat´ria para a maratona de programa¸˜o da ACM da ca o caUral State Universisy (Internal Contest October’2000 Junior Session) encontrada na seguinte URL:http://acm.timus.ru/problem.aspx?space=1&num=1024.
    • 10.1. VETORES 153uma permuta¸˜o. Para isto pode-se usar um vetor de n posi¸oes inteiras, onde cada ca c˜posi¸ao ´ um valor (sem repeti¸ao) entre 1 e n. Em todos os algoritmos desta se¸ao c˜ e c˜ c˜consideraremos que:const min i = 1; max i = 5; Assim os dois vetores que representam as permuta¸oes acima s˜o, respectivamente: c˜ a 1 2 3 4 5 4 1 5 2 3 1 2 3 4 5 2 5 1 3 2 Testando permuta¸˜es v´lidas co a Uma vez resolvido o problema da representa¸˜o, podemos estudar o pr´ximo de- ca osafio, que ´ como testar se um dado vetor (lido do teclado) ´ uma permuta¸˜o v´lida? e e ca a O algoritmo tem que testar se, para os ´ ındices de 1 a n, seus elementos s˜o cons- atitu´ ıdos por todos, e apenas, os elementos entre 1 e n, em qualquer ordem. A fun¸˜o cada figura 10.26 apresenta uma poss´ solu¸ao. ıvel c˜function testa permutacao (var v: vetor i ; n: integer) : boolean;var i , j : integer ; eh permutacao : boolean;begin eh permutacao:= true; i:= 1; while eh permutacao and ( i <= n) do begin j:= 1; (∗ procura se i esta no vetor ∗) while (v[ j ] < i ) and ( j <= n) do > j:= j + 1; i f v[ j ] < i then > (∗ se nao achou nao eh permutacao ∗) eh permutacao:= false ; i:= i +1; end; testa permutacao:= eh permutacao ;end; (∗ testa permutacao ∗) Figura 10.26: Verifica se um vetor define uma permuta¸ao. c˜ Este algoritmo testa para saber se cada ´ ındice entre i e n est´ presente no vetor. aPara isto executa no pior caso algo da ordem do quadrado do tamanho do vetor. No primeiro semestre de 2011 um estudante6 sugeriu que basta usar um vetor 6 Cr´ditos para o DESCOBRIR O NOME DO ALUNO e
    • 154 CAP´ ITULO 10. ESTRUTURAS DE DADOSauxiliar, inicialmente zerado, e percorrer o vetor candidato a permuta¸ao apenas uma c˜vez. Para cada ´ ındice, tentar inserir seu respectivo conte´do no vetor auxiliar: se esti- uver com um zero, inserir, sen˜o, n˜o ´ permuta¸˜o. Se o vetor auxiliar for totalmente a a e capreenchido ent˜o temos um vetor que representa uma permuta¸˜o. Este processo ´ a ca elinear e est´ ilustrado na figura 10.27. afunction testa permutacao (var v: vetor i ; n: integer) : boolean;var i , j : integer ; aux: vetor ; eh permutacao : boolean;begin zera vetor (aux,n) ; eh permutacao:= true; i:= 1; while eh permutacao and ( i <= n) do begin i f aux[v[ i ] ] = 0 then aux[v[ i ]]:= v[ i ] else eh permutacao:= false i:= i + 1; end; testa permutacao:= eh permutacao ;end; (∗ testa permutacao ∗) Figura 10.27: Verifica linearmente se um vetor define uma permuta¸ao. c˜ Outros estudantes sugeriram uma conjectura, n˜o provada em sala, de que, se atodos os elementos pertencem ao intervalo 1 ≤ v[i] ≤ n e n v[i] = n(n+1) e ao i=1 2mesmo tempo n v[i] = n!, ent˜o o vetor representa uma permuta¸ao. Tamb´m i=1 a c˜ en˜o encontramos contra-exemplo e o problema ficou em aberto. a Gerando permuta¸oes v´lidas c˜ a O pr´ximo problema ´ gerar aleatoriamente uma permuta¸ao. Para isto faremos o e c˜uso da fun¸˜o random da linguagem Pascal. ca O primeiro algoritmo gera um vetor de maneira aleat´ria e depois testa se o vetor oproduzido pode ser uma permuta¸˜o usando o c´digo da fun¸ao testa permutacao j´ ca o c˜ aimplementado. A tentativa ´ reaproveitar c´digo a qualquer custo. Este racioc´ e o ınioest´ implementado no c´digo da figura 10.28. a o Este algoritmo ´ absurdamente lento quando n cresce. Isto ocorre pois os vetores es˜o gerados e depois testados para ver se s˜o v´lidos, mas, conforme esperado, ´ a a a emuito prov´vel que n´meros repetidos sejam gerados em um vetor com grande n´mero a u ude elementos. Um dos autores deste material teve paciˆncia de esperar o c´digo e oterminar apenas at´ valores de n pr´ximos de 14. Para valores maiores o c´digo ficou e o oinfernalmente demorado, levando v´rias horas de processamento. a Numa tentativa de melhorar o desempenho, o que implica em abrir m˜o da como- a
    • 10.1. VETORES 155procedure gerar permutacao1 (var v: vetor i ; var n: integer) ;var i : integer ;begin read (n) ; randomize ; repeat (∗ repete ate conseguir construir uma permutacao valida ∗) for i:= 1 to n do v[ i ]:= random (n) + 1; (∗ sorteia numero entre 1 e n ∗) until testa permutacao (v, n) ;end; (∗ gera permutacao1 ∗) Figura 10.28: Gerando uma permuta¸˜o, vers˜o 1. ca adidade de se aproveitar fun¸oes j´ existentes, este mesmo autor pensou que poderia c˜ agerar o vetor de modo diferente: gerar um a um os elementos e testar se eles j´ n˜o a apertencem ao conjunto j´ gerado at´ a itera¸˜o anterior. Isto garante que o vetor final a e caproduzido ´ v´lido. A procedure da figura 10.29 apresenta a implementa¸˜o desta e a canova ideia.procedure gerar permutacao2 (var v: vetor i ; var n: integer) ;var i , j : integer ;begin read (n) ; randomize ; v[1]:= random (n) + 1; for i:= 2 to n do repeat v[ i ]:= random (n) + 1; (∗ gera um numero entre 1 e n ∗) j:= 1; (∗ procura se o elemento ja existe no vetor ∗) while ( j < i ) and (v[ i ] < v[ j ] ) do > j:= j + 1; until j = i ; (∗ descobre que o elemento eh novo ∗)end; (∗ gera permutacao2 ∗) Figura 10.29: Gerando uma permuta¸˜o, vers˜o 2. ca a Este algoritmo executa na casa de 2 segundos para vetores de tamanho pr´ximos ode 1000, mas demora cerca de 30 segundos para entradas de tamanho que beiram os30.000. Para se pensar em tamanhos maiores a chance do tempo ficar insuport´vel ´ a eenorme. Mas j´ ´ melhor do que o anterior. ae Queremos gerar um vetor que represente uma permuta¸˜o, provavelmente para cafins de testes. Uma maneira poss´ seria a seguinte: inicializa-se um vetor de forma ıvelordenada, depois faz-se altera¸˜es aleat´rias de seus elementos um n´mero tamb´m co o u ealeat´rio de vezes. Esta ideia foi implementada e ´ mostrada na figura 10.30. o e Este c´digo produz corretamente vetores que representam permuta¸˜es com bom o cograu de mistura dos n´meros em tempo praticamente constante para entradas da u
    • 156 CAP´ ITULO 10. ESTRUTURAS DE DADOSprocedure gerar permutacao3 (var v: vetor i ; var n: integer) ;var i , j , k, aux, max: integer ;begin read (n) ; randomize ; for i:= 1 to n do v[ i ] := i ; max:= random (1000) ; (∗ vai trocar dois elementos de 0 a 999 vezes ∗) for i:= 1 to max do begin j:= random (n) + 1; k:= random (n) + 1; aux:= v[ j ] ; v[ j ]:= v[k ] ; v[k]:= aux; end;end; (∗ gera permutacao3 ∗) Figura 10.30: Gerando uma permuta¸ao, vers˜o 3. c˜ aordem de um milh˜o de elementos (usando-se o tipo longint).7 a Em uma aula do segundo semestre de 2010 surgiu uma nova ideia para se gerarum vetor de permuta¸˜o.8 ca A sugest˜o ´ modificar o algoritmo 10.29, fazendo com que um vetor auxiliar a econtenha os n´meros ainda n˜o colocados no vetor permuta¸˜o. O sorteio deixa de u a caser sobre o elemento a ser inserido, mas agora sobre o ´ ındice do vetor auxiliar, cujotamanho decresce na medida em que os n´meros v˜o sendo sorteados. O c´digo da u a ofigura 10.31 ilustra estas ideias. Ele foi implementado durante a aula e possibilitougerar vetores de tamanhos incrivelmente grandes em tempo extremamente curto.9 Determinando a ordem de uma permuta¸˜o ca Antes de apresentarmos o pr´ximo problema do ponto de vista algoritmico a ser otratado precisamos introduzi-lo do ponto de vista matem´tico. a Observem que, uma vez que a fun¸ao que define a permuta¸ao ´ sobre o pr´prio c˜ c˜ e oconjunto, ocorre que, se P (n) ´ uma permuta¸˜o, ent˜o P (P (n)) tamb´m ´. Logo, e ca a e e´ poss´ calcular o valor de express˜es tais como P (P (1)). De fato, consideremose ıvel onovamente a permuta¸˜o: ca 1 2 3 4 5 4 1 5 2 3 7 Se algu´m souber de um modo mais eficiente de gerar uma permuta¸˜o, favor avisar. N˜o s´ e ca a odaremos os cr´ditos necess´rios como tamb´m mostraremos os resultados aqui neste material. e a e 8 Cr´ditos para o Felipe Z. do Nascimento. e 9 C´digo e testes feitos na aula por Renan Vedovato Traba, a partir da ideia do Felipe. o
    • 10.1. VETORES 157procedure gera aux(var aux: vetor i ; var tam : longint ) ;var i : longint ;begin for i := 0 to tam do aux[ i ] := i ;end;procedure gerar permutacao4 (var v: vetor ; var n: longint ) ;var i , j : longint ;begin read (n) ; randomize ; tam:= n; for i := 0 to n do begin j := random(tam+1); p[ i ] := aux[ j ] ; aux[ j ] := aux[tam] ; tam := tam−1; end;end; (∗ gera permutacao4 ∗) Figura 10.31: Gerando uma permuta¸˜o, vers˜o 4. ca a Ent˜o pode-se calcular: a • P (P (1)) = P (4) = 2. • P (P (2)) = P (1) = 4. • P (P (3)) = P (5) = 3. • P (P (4)) = P (2) = 1. • P (P (5)) = P (3) = 5. Desta maneira, definimos P 2 (n) = P (P (n)). Em termos gerais, podemos definir oseguinte: P 1 (n) = P (n); P k (n) = P (P k−1 (n)) k ≥ 2. Dentre todas as permuta¸oes, existe uma especial: c˜ 1 2 3 4 5 ID = 1 2 3 4 5 e c˜ ´ Isto ´, P (i) = i, ∀i. Esta permuta¸ao recebe um nome especial ID. E poss´ de- ıvel kmonstrar que, para quaisquer k e n, ID (n) = ID(n). Tamb´m ´ poss´ demonstrar e e ıvelque a senten¸a seguinte tamb´m ´ v´lida: c e e a
    • 158 CAP´ ITULO 10. ESTRUTURAS DE DADOS Seja P (n) uma permuta¸ao sobre um conjunto de n elementos. Ent˜o existe um c˜ a kn´mero natural k tal que P = ID. Este n´mero natural ´ chamado da ordem da u u epermuta¸ao. c˜ Vamos considerar como exemplo a permuta¸ao acima. Podemos calcular para c˜ kvalores pequenos de k como ´ P : e 1 2 3 4 5 P = 4 1 5 2 3 1 2 3 4 5 P2 = 2 4 3 1 5 1 2 3 4 5 P3 = 1 2 5 4 3 1 2 3 4 5 P4 = 4 1 3 2 5 1 2 3 4 5 P5 = 2 4 5 1 3 1 2 3 4 5 P6 = 1 2 3 4 5 Isto ´, a ordem da permuta¸ao P ´ 6. e c˜ e Chegamos no ponto de apresentarmos o pr´ximo problema10 . Dada uma per- omuta¸˜o, encontrar sua ordem. Simular a sequˆncia de opera¸˜es e testar quando ca e coa identidade for encontrada, contando quantas opera¸oes foram feitas ´ muito caro. c˜ eTem que haver uma maneira melhor. A fun¸ao da figura 10.32 implementa um algoritmo que recebe como entrada uma c˜permuta¸ao (v´lida) e retorna sua ordem. c˜ a Este algoritmo parte da ideia de que cada elemento P (i) = x do conjunto re-torna a posi¸ao i ciclicamente, de cont em cont permuta¸oes. Ou seja, P cont (i) = ` c˜ c˜x, P 2×cont (i) = x, . . .. O mesmo ocorre para todos elementos do conjunto, mas cadaum possui um ciclo (valor de cont) pr´prio. o Para exemplificar, tomemos a permuta¸˜o acima. Para o ´ ca ındice 1, temos que 3P (1) = 1. Isto quer dizer que para todo m´ltiplo de 3 (a cada 3 itera¸oes) ´ verdade u c˜ e 3kque P (1) = 1. Isto tamb´m ocorre para os ´ e ındices 2 e 4. Mas para os ´ındices 3 e 5, on´mero de itera¸oes para que ocorra uma repeti¸ao ´ de duas itera¸oes. Logo, pode- u c˜ c˜ e c˜se concluir que a permuta¸ao ID ocorrer´ exatamente na itera¸˜o que ´ o m´ c˜ a ca e ınimom´ltiplo comum (MMC) entre o n´mero que provoca repeti¸ao entre todos os ´ u u c˜ ındices.Observamos que: M M C(x1 , x2 , . . . , xn ) = M M C(x1 , M M C(x2 , . . . , xn ). Infelizmente, n˜o existe algoritmo eficiente para c´lculo do MMC. Mas existe para a ao c´lculo do MDC (m´ximo divisor comum). De fato, implementamos o algoritmo de a a 10 Este ´ o problema da Maratona da ACM. e
    • 10.1. VETORES 159function ordem permutacao (var v: vetor i ; n: integer) : int64 ;var mmc, cont : int64 ; p, i : integer ;begin mmc := 1; for i := 1 to n do begin cont := 1; p := i ; while (v[p] < i ) do > begin cont:= cont + 1; p := v[p ] ; end; writeln (cont) ; mmc := mmc ∗ cont div mdc(mmc, cont) ; end; ordem permutacao:= mmc;end. Figura 10.32: Calcula a ordem de uma permuta¸˜o. caEuclides (figura 6.16, se¸ao 6.4) e mostramos que ele ´ muito eficiente. Felizmente, a c˜ eseguinte propriedade ´ verdadeira: e a×b M DC(a, b) = M M C(a, b) O programa acima explora este fato e torna o c´digo muito eficiente para calcular oa ordem de permuta¸˜es para grandes valores de n. O estudante ´ encorajado aqui a co egerar uma permuta¸ao com os algoritmos estudados nesta se¸ao e rodar o programa c˜ c˜para valores de n compat´ ıveis com os tipos de dados definidos (integer).Polinˆmios oNesta se¸˜o vamos mostrar como representar e fazer c´lculos com polinˆmios repre- ca a osentados como vetores. Para uma sucess˜o de termos a0 , ..., an ∈ R, podemos para este curso definir um apolinˆmio de grau n como sendo uma fun¸ao que possui a seguinte forma: o c˜ P (x) = an xn + an−1 xn−1 + . . . + a1 x + a0 Vamos considerar ao longo desta se¸ao que ∀k > n, ent˜o ak = 0. Tamb´m c˜ a econsideramos que an = 0 para um polinˆmio de grau n. o Do ponto de vista computacional, uma poss´ representa¸˜o para um polinˆmio ıvel ca o´ um vetor de n + 1 elementos cujos conte´dos s˜o os coeficientes reais dos respectivose u amonˆmios. Consideremos ent˜o o tipo abaixo, podemos exemplificar alguns casos: o atype polinomio = array [ 0 . .max] of real ;
    • 160 CAP´ ITULO 10. ESTRUTURAS DE DADOS • P (x) = 5 − 2x + x2 : 0 1 2 5 -2 1 • P (x) = 7 − 2x2 + 8x3 − 2x7 0 1 2 3 4 5 6 7 7 0 -2 8 0 0 0 -2 No restante desta se¸ao iremos mostrar algoritmos que realizam opera¸˜es costu- c˜ comeiras sobre polinˆmios. A primeira ´ calcular o valor de um polinˆmio em um dado o e oponto x ∈ R. Por exemplo, se P (x) = 5 − 2x + x2 ent˜o, P (1) = 5 − 2 × 1 + 12 = 4. aA fun¸˜o em Pascal que implementa este c´lculo est´ apresentado na figura 10.33. ca a afunction valor no ponto (var p: polinomio ; n: integer ; x: real) : real ;var i : integer ; soma, pot x : real ;begin soma:= 0; pot x:= 1; for i:= 0 to n do (∗ basta usar a tecnica do acumulador ∗) begin soma:= soma + p[ i ] ∗ pot x ; pot x:= pot x ∗ x; (∗ controlando a potencia de x ∗) end; valor no ponto:= soma;end; Figura 10.33: Calcula o valor de P (x) para um dado x ∈ R. O pr´ximo algoritmo interessante ´ o c´lculo do polinˆmio derivada de um po- o e a olinˆmio P. Seja P (x) a derivada de P (x) assim definido: o P (x) = nan xn−1 + (n − 1)an−1 xn−2 + . . . + 2a2 x + a1 O programa que implementa este c´lculo est´ na figura 10.34. a a Por outro lado, para calcular o valor no ponto de uma derivada de um polinˆmio, on˜o ´ necess´rio que se calcule previamente um vetor auxiliar contendo a derivada. Isto a e apode ser feito diretamente usando-se o polinˆmio P , bastando trabalhar corretamente oos ´ ındices do vetor, conforme mostrado na figura 10.35. Os pr´ximos problemas v˜o nos permitir trabalhar um pouco com os ´ o a ındices dovetor. O primeiro problema ´ a soma de polinˆmios. O segundo ´ a multiplica¸˜o. e o e caAntes mostraremos a defini¸˜o matem´tica para estes conceitos. ca a Sejam dois polinˆmios P e Q assim definidos, supondo que n >= m: o
    • 10.1. VETORES 161procedure derivada (var p: polinomio ; n: integer var q: polinomio ; var m: integer) ;var i : integer ;begin for i:= 1 to n do q[ i −1]:= i ∗ p[ i ] ; (∗ diretamente da definicao de derivada ∗) m:= n − 1;end; Figura 10.34: Calcula o polinˆmio derivada de P (x). ofunction derivada no ponto (var p: polinomio ; n: integer ; x: real) : real ;var i : integer ; soma, pot x : real ;begin soma:= 0; pot x:= 1; for i:= 1 to n do begin soma:= soma + i ∗ p[ i ] ∗ pot x ; pot x:= pot x ∗ x; end; derivada no ponto:= soma;end; Figura 10.35: Calcula o valor de P (x) para um dado x ∈ R. P (x) = an xn + . . . + am xm + . . . + a1 x + a0 Q(x) = bn xm + bn−1 xm−1 + . . . + b1 x + b0 Ent˜o o polinˆmio soma de P e Q, denotado P + Q ´ assim definido: a o e (P + Q)(x) = an xn + . . . + am+1 xm+1 + (am + bm )xm + . . . + (a1 + b1 )x + (a0 + b0 ) Basicamente ´ a mesma opera¸ao de soma de vetores estudada neste cap´ e c˜ ıtulo,embora naquele caso exigimos que os tamanhos dos vetores fossem iguais. No casode polinˆmios os vetores podem ter tamanhos diferentes desde que se assuma que oos coeficientes que faltam no polinˆmio de maior graus s˜o nulos. A implementa¸ao o a c˜deste processo est´ na figura 10.36. a Considerando os mesmos polinˆmios P e Q acima definidos, o produto de P por oQ, denotado P Q ´ assim definida: e (P Q)(x) = (an+m b0 + . . . + an bm + . . . + a0 bn+m )xn+m + . . . + (ak b0 + ak−1 b1 + . . . + a0 bk )xk + . . . + (a1 b0 + a0 b1 )x + (a0 b0 )
    • 162 CAP´ ITULO 10. ESTRUTURAS DE DADOSprocedure soma (var p: polinomio ; n: integer ; var q: polinomio ; m: integer ; var r : polinomio ; var grau r : integer) ;var i , menor grau : integer ;begin i f n > m then (∗ primeiro copia a parte que sobra ∗) begin menor grau:= m grau r:= n; for i:= m do n do +1 r [ i ]:= p[ i ] ; end else begin menor grau:=n; grau r:= m; for i:= n+1 to m do r [ i ]:= q[ i ] ; end for i:= 0 to menor grau do (∗ este for eh o mesmo da soma de vetores ∗) r [ i ]:= p[ i ] + q[ i ] ;end; Figura 10.36: Calcula a soma de P (x) com Q(x). A opera¸˜o matem´tica exige que sejam feitas todas as multiplica¸oes e posterior ca a c˜agrupamento dos monˆmios de mesmo grau, somando-se os coeficientes, para cada omonˆmio. o O programa apresentado na figura 10.37 implementa os c´lculos para obten¸˜o do a capolinˆmio produto de P por Q. O programa realiza os c´lculos para cada monˆmio o a oa medida em que os ´` ındices dos dois comandos for variam, o que ´ um uso especial eda t´cnica dos acumuladores, embora os ac´mulos n˜o sejam simultˆneos para cada e u a amonˆmio do resultado final da opera¸ao, eles s˜o feitos aos poucos. Para isto ´ preciso o c˜ a ezerar o vetor antes de come¸ar. cprocedure produto (var p: polinomio ; n: integer ; var q: polinomio ; m: integer ; var r : polinomio ; var grau r : integer) ;var i , j : integer ;begin for i:= 0 to n+ do m r [ i ]:= 0; for i:= 0 to n do for j:= 0 to m do r [ i+j ]:= r [ i+j ] + p[ i ]∗q[ j ] ; grau r:= n+ m;end; Figura 10.37: Calcula o produto de P (x) com Q(x).
    • 10.1. VETORES 16310.1.6 Exerc´ ıcios 1. Fa¸a um programa que leia e armazene em um vetor uma sequˆncia de inteiros. c e Em seguida o programa deve ler uma sequˆncia de inteiros informados pelo e usu´rio e, para cada um deles, dizer se ele pertence ou n˜o ao vetor armazenado a a previamente. 2. Fa¸a um programa que leia duas sequˆncias de n inteiros em dois vetores dis- c e tintos, digamos, v e w e verifique se os dois vetores s˜o idˆnticos. a e 3. Fa¸a um programa em que leia dois vetores de n´meros reais e descubra se um c u deles ´ permuta¸˜o do outro, isto ´, se eles tem os mesmos elementos, ainda e ca e que em ordem diferente. A quantidade de elementos lidos em cada vetor ´ noe m´ximo 100, e cada sequˆncia termina quando o valor 0 ´ digitado. Por exemplo: a e e [2, 2, 0, 3, 4] e [2, 2, 0, 3, 4]: sim. [2, 2, 0, 3, 4] e [4, 3, 2, 0, 2]: sim. [2, 2, 0, 3, 4] e [4, 3, 4, 0, 2]: n˜o. a [3, 0, 5] e [3, 0, 5, 3]: n˜o. a Implemente trˆs vers˜es deste problema: e o • ordenando os vetores para em seguida compar´-los; a • sem ordenar os vetores; • crie uma fun¸˜o que retorna 0 se x n˜o pertence a v e caso contr´rio retorna ca a a o´ındice do vetor onde x se encontra. Use esta fun¸ao para resolver este c˜ problema. 4. Fa¸a um programa que leia duas sequˆncias de inteiros, n˜o necessariamente c e a contendo a mesma quantidade de n´meros. Seu programa dever´: u a • dizer se a segunda sequˆncia est´ contida na primeira. Exemplo: e a v1: 7 3 2 3 2 6 4 7 v2: 3 2 6 Sa´da: sim ı • constrir um terceiro vetor, sem destruir os originais, que ´ a concatena¸ao e c˜ do primeiro com o segundo; v1: 7 3 2 6 v2: 5 1 8 4 9 Sa´da: 1 2 3 4 5 6 7 8 9 ı • orden´-los, e em seguida imprimir todos os n´meros ordenados em ordem a u crescente. Exemplo: v1: 7 3 2 6 v2: 5 1 8 4 9 Sa´da: 1 2 3 4 5 6 7 8 9 ı
    • 164 CAP´ ITULO 10. ESTRUTURAS DE DADOS 5. Crie uma fun¸ao em que receba um vetor de inteiros de tamanho n e devolva o c˜ valor true se o vetor estiver ordenado e false em caso contr´rio. a 6. Aproveitando as solu¸oes dos problemas anteriores, escreva um programa em c˜ que leia dois vetores de inteiros v e w, de dimens˜es m e n respectivamente, o verifique se eles est˜o ordenados, ordene-os em caso contr´rio e, em seguida, a a imprima a intercala¸ao dos dois. c˜ Exemplo de intercala¸ao: v: 1 4 6 9; w: 2, 3, 5, 7. c˜ Sa´ ıda: 1, 2, 3, 4, 5, 6, 7, 9. 7. Dados dois n´meros naturais m e n, uma frase com m letras e uma palavra u com n letras, escreva um procedimento que determine o n´mero de vezes que a u palavra ocorre na frase e a posi¸ao em que cada ocorrˆncia inicia. c˜ e Exemplo: Para M = 30, N = 3, a palavra ANA e a frase: ANA E MARIANA GOSTAM DE BANANA A palavra ANA ocorre 4 vezes, nas posi¸oes 1, 11, 26, 28. c~ 8. Dada uma sequˆncia de N n´meros, determinar quantos n´meros dintintos e u u comp˜e a sequˆncia e o n´mero de vezes que cada um deles ocorre na mesma. o e u Exemplo: N=5 1 2 3 2 3 a sequˆncia tem trˆs n´meros distintos, 1, 2 e 3. Ocorrˆncias: 1 e e u e ocorre 1 vez 2 ocorre 2 vezes 3 ocorre 2 vezes 9. Dadas duas sequˆncias com n n´meros inteiros entre 0 e 1, interpretados como e u n´meros bin´rios: u a (a) imprimir o valor decimal dos n´meros; u (b) calcular a soma de ambos (em bin´rio), usando o “vai-um”; a (c) imprimir o valor decimal da soma. 10. Escreva um programa em que leia os seguintes valores: um inteiro B, um inteiro N (1 ≤ N ≤ 10), e N valores inteiros. A ideia ´ que estes valores sejam e entendidos como a representa¸ao de um n´mero n˜o negativo na base B. Estes c˜ u a valores dever˜o ser inseridos em um vetor de tamanho N + 1, onde a primeira a posi¸ao armazena a base B e as outras N posi¸oes o restante dos n´meros lidos. c˜ c˜ u Note que o intervalo de valores poss´ ıveis para cada d´ıgito na base B ´ [0, B − 1]. e Seu programa deve retornar o valor em decimal do n´mero representado no u vetor. Se o n´mero representado no vetor n˜o for v´lido na base B ent˜o dever´ u a a a a ser retornado o c´digo de erro “-1”. Por exemplo, se B = 3 o n´mero 2102 na o u base 3 equivale ao valor decimal 65; se B = 4 o n´mero 35 ´ inv´lido na base 4. u e a
    • 10.1. VETORES 165 11. Fa¸a um programa em que, dadas duas sequˆncias com N n´meros inteiros en- c e u tre 0 e 9, interpretadas como dois n´meros inteiros de N algarismos, calcular a u sequˆncia de n´meros que representa a soma dos dois inteiros, usando o “vai- e u um”. Por exemplo: N=6, 4 3 4 2 5 1 + 7 5 2 3 3 7 1 1 8 6 5 8 8 12. Dada uma sequˆncia x1 , x2 , . . . , xn de n´meros inteiros, determinar um seg- e u mento de soma m´xima. Exemplo: na sequˆncia 5, 2, -2, -7, 3, 14, 10, -3, 9, -6, a e 4, 1, a soma do maior segmento ´ 33, obtida pela soma dos n´meros de 3 at´ 9. e u e 13. Implemente um programa que leia um vetor de 1 milh˜o de inteiros em um vetor a de inteiros. Gere um n´mero aleat´rio e o procure neste vetor de duas maneiras u o diferentes: uma usando busca com sentinela e outra usando busca bin´ria. Seu a programa deve imprimir uma tabela com o n´mero de compara¸˜es feitas em u co cada um dos casos acima (busca com sentinela e busca bin´ria). Desconsidere a o tempo gasto com ordena¸ao no caso da busca bin´ria. A busca com sentinela c˜ a deve ser feita em um vetor n˜o ordenado. Gere 200 n´meros aleat´rios e imprima a u o a m´dia de compara¸oes para cada um dos dois algoritmos sendo testados. e c˜ 14. Suponha que um ex´rcito tenha 20 regimentos e que eles est˜o em processo de e a forma¸ao. Inicialmente o primeiro tem 1000 homens, o segundo 950, o terceiro c˜ 900, e assim por diante, at´ o vig´simo que tem 50. Suponhamos que a cada e e semana 100 homens s˜o enviados para cada regimento, e no final da semana o a maior regimento ´ enviado para o front. Imaginemos que o general do quinto e regimento ´ companheiro de xadrez do comandante supremo, e que eles est˜o e a no meio de uma partida. O comandante supremo ent˜o envia apenas 30 homens a para o quinto regimento a cada semana, esperando com isto poder acabar o jogo com seu colega. Escreva um programa em que diga, a cada semana, qual ´ o e regimento enviado ao front e mostre o status dos outros regimentos. O programa deve tamb´m determinar exatamente quantas semanas levar´ o quinto regimento e a para ser deslocado ao front. 15. Suponha que vocˆ esteja usando o m´todo da ordena¸ao por sele¸˜o. Qual e e c˜ ca das sequˆncias abaixo requerir´ o menor n´mero de trocas? Quantas? Qual e a u requerir´ o maior n´mero de trocas? Quantas? Explique. a u (a) 10, 9, 8, 7, 6, 5, 4, 3, 2, 1. (b) 5, 4, 3, 2, 1, 10, 9, 8, 7, 6. (c) 10, 1, 9, 2, 8, 3, 7, 4, 6, 5. (d) 2, 3, 4, 5, 6, 7, 8, 9, 10, 1. (e) 1, 10, 2, 9, 3, 8, 4, 7, 5, 6.
    • 166 CAP´ ITULO 10. ESTRUTURAS DE DADOS 16. Suponha que vocˆ tem uma vari´vel do tipo vetor declarada como: array [1..50] e a of real;. Fa¸a uma fun¸ao que inicialize o vetor de modo que os elementos c c˜ de ´ ındices ´ımpares recebam o valor inicial -2.0 e os elementos de ´ ındices pares recebam o valor inicial 7.0. Sua fun¸ao deve fazer uso de apenas um comando c˜ de repeti¸ao, que incrementa de um em um, e de nenhum comando de desvio c˜ condicional. 17. Qual dos seguintes problemas requer o uso de vetores para uma solu¸ao elegante? c˜ (a) Ler cerca de duzentos n´meros e imprimir os que est˜o em uma certa faixa; u a (b) Computar a soma de uma sequˆncia de n´meros; e u (c) Ler exatamente duzentos n´meros e orden´-los em ordem crescente; u a (d) Encontrar o segundo menor elemento de uma sequˆncia de entrada; e (e) Encontrar o menor inteiro de uma sequˆncia de inteiros. e 18. Considere um vetor declarado como: array [1..50] of integer que tem a par- ticularidade de todos os elementos estarem entre 1 e 30, sendo que nenhum ´e repetido. Fa¸a um programa que ordene o vetor de maneira eficiente explorando c esta caracter´ ıstica e fazendo o menor n´mero poss´ de trocas. u ıvel 19. Dada uma sequˆncia x1 , x2 , . . . , xk de n´meros reais, verifique se existem dois e u segmentos consecutivos iguais nesta sequˆncia, isto ´, se existem i e m tais que: e e xi , xi+1 , . . . , xi+m−1 = xi+m , xi+m+1 , . . . , xi+2m−1 . Imprima, caso existam, os valores de i e de m. Caso contr´rio, n˜o imprima a a nada. Exemplo: Na sequˆncia 7,9,5,4,5,4,8,6, existem i = 3 e m = 2. e 20. Um coeficiente binomial, geralmente denotado n , representa o n´mero de k u poss´ ıveis combina¸oes de n elementos tomados k a k. Um “Triˆngulo de Pascal”, c˜ a uma homenagem ao grande matem´tico Blaise Pascal, ´ uma tabela de valores a e de coeficientes combinatoriais para pequenos valores de n e k. Os n´meros que u n˜o s˜o mostrados na tabela tˆm valor zero. Este triˆngulo pode ser constru´ a a e a ıdo automaticamente usando-se uma propriedade conhecida dos coeficientes bino- miais, denominada “f´rmula da adi¸˜o”: k = r−1 + k−1 . Ou seja, cada o ca r k r−1 elemento do triˆngulo ´ a soma de dois elementos da linha anterior, um da a e mesma coluna e um da coluna anterior. Veja um exemplo de um triˆngulo de a Pascal com 7 linhas: 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1
    • 10.1. VETORES 167 Fa¸a um programa em que imprima na tela um triˆngulo de Pascal com 10 c a linhas. Seu programa deve obrigatoriamente fazer uso de exatamente dois ve- tores durante o processo de constru¸ao. Um deles conter´ a ultima linha ´ c˜ a ´ ımpar gerada, enquanto que o outro conter´ a ultima linha par gerada. Lembre-se que a ´ os elementos que n˜o aparecem na tabela tem valor nulo. Vocˆ deve sempre ter a e o controle do tamanho da ultima linha impressa (o tamanho util dos vetores em ´ ´ cada passo). Vocˆ deve tamb´m usar um procedimento para imprimir o vetor. e e Observe que n˜o h´ entrada de dados, os dois vetores s˜o gerados, um a partir a a a do outro. O unico elemento da primeira linha tem o valor 1. Vocˆ deve obri- ´ e gatoriamente declarar um tipo vetor com tamanho m´ximo Tam max vetor, e a o seu programa dever´ tomar cuidado para manipular corretamente vetores de a tamanho menor do que o tamanho m´ximo, impedindo que haja uma atribui¸ao a c˜ em posi¸˜o ilegal de mem´ria. ca o 21. Resolva o problema do triˆngulo de Pascal usando apenas um vetor. a 22. Seja um polinˆmio p(x) = a0 + a1 x + a2 x2 + . . . + an xn de grau n ≥ 2. Uma o poss´ maneira de calcular uma raiz do polinˆmio ´ pelo “m´todo de Newton”. ıvel o e e Este m´todo consiste em se fornecer uma aproxima¸˜o inicial para a raiz, isto e ca ´, um valor que n˜o ´ a raiz exata, mas ´ um valor pr´ximo. Assim, se x0 ´ e a e e o e esta aproxima¸ao inicial, p(x0 ) n˜o ´ zero mas espera-se que seja pr´ximo de c˜ a e o zero. A obten¸˜o da raiz pelo m´todo de Newton ´ feita pelo refinamento desta ca e e solu¸ao inicial, isto ´, pela tentativa de minimizar o erro cometido. Isto ´ feito c˜ e e pela express˜o seguinte: a p(xn ) xn+1 = xn − , p (xn ) n = 0, 1, 2, . . ., e onde p (x) ´ a primeira derivada de p(x). Usualmente, repete-se e este refinamento at´ que |xn+1 − xn | < , > 0, ou at´ que m itera¸oes tenham e e c˜ sido executadas. Construa um programa em que receba como dados de entrada um polinˆmio o 2 n p(x) = a0 + a1 x + a2 x + . . . + an x e uma aproxima¸˜o inicial x0 da raiz de ca p(x), > 0 e o n´mero m´ximo de itera¸˜es, e calcule uma aproxima¸˜o da raiz u a co ca de p(x) pelo m´todo de Newton. Utilize obrigatoriamente um procedimento que e receba como parˆmetro um polinˆmio p(x) (incluindo a informa¸˜o sobre o grau a o ca do polinˆmio) e que calcule e retorne a fun¸˜o derivada p (x). Utilize tamb´m o ca e uma fun¸˜o que receba como parˆmetros um polinˆmio p(x) e um valor real x ca a o e retorne o valor do polinˆmio no ponto x, isto ´ p(x). Use esta fun¸˜o para o e ca calcular, a cada itera¸ao do m´todo de Newton, os valores de p(xn ) e de p (xn ). c˜ e 23. Fa¸a um programa em que leia uma sequˆncia de 10 letras (caracteres de A a c e Z), as armazene em um vetor de 10 posi¸˜es e imprima a lista de letras repetidas co no vetor. Sendo assim, para os dados: A J G A D F G A A, a sa´ deve ser: ıda A G. 24. Escreva o programa da busca bin´ria de um valor x num vetor de inteiros que, a ao inv´s de achar a primeira ocorrˆncia do valor na lista, identifique e imprima e e
    • 168 CAP´ ITULO 10. ESTRUTURAS DE DADOS o menor ´ ındice do vetor no qual o valor ocorra. 25. Escreva um programa em que leia uma sequˆncia de c´digo de opera¸˜o e valor, e o ca onde o c´digo de opera¸˜o ´ um inteiro com os seguintes valores: o ca e • 0 (zero): fim • 1 (um): inser¸˜o ca • 2 (dois): remo¸˜o ca O valor lido ´ um real que deve ser inserido em um vetor (caso a opera¸˜o seja 1), e ca ou removido do vetor (caso a opera¸˜o seja 2). As inser¸oes no vetor devem ser ca c˜ realizadas de forma que o vetor esteja sempre ordenado. No final do programa o vetor resultante deve ser impresso. Detalhamento: • a quantidade m´xima de valores que pode ser inserida ´ 100; a e • se a quantidade m´xima for ultrapassada o programa deve dar uma men- a sagem de erro; • se for requisitada a remo¸˜o de um n´mero n˜o existente o programa deve ca u a dar uma mensagem de erro; • se o c´digo de opera¸ao for inv´lido o programa deve continuar lendo um o c˜ a novo c´digo at´ que ele seja 0 (zero), 1 (um) ou 2 (dois). o e Exemplo de execu¸˜o: ca Entre com operacao (0=fim, 1=insercao, 2=remocao): 1 Valor: 45.3 Entre com operacao (0=fim, 1=insercao, 2=remocao): 1 Valor: 34.3 Entre com operacao (0=fim, 1=insercao, 2=remocao): 1 Valor: 40.8 Entre com operacao (0=fim, 1=insercao, 2=remocao): 2 Valor: 34.3 Entre com operacao (0=fim, 1=insercao, 2=remocao): 0 Vetor resultante 40.8 45.3 1 2 3 4 5 6 in´ ıcio 45.3 ap´s inser¸˜o de 45.3 o ca 34.3 45.3 ap´s inser¸˜o de 34.3 o ca 34.3 40.8 45.3 ap´s inser¸˜o de 40.8 o ca 40.8 45.3 ap´s remo¸˜o de 34.3 o ca
    • 10.1. VETORES 169 26. Escreva um programa que leia duas sequˆncias de caracteres e verifica se a e segunda sequˆncia ´ subpalavra da primeira. Por exemplo, todo ´ subpalavra e e e de metodo e ar ´ subpalavra de farmacia. Por´m, todo n˜o ´ subpalavra de e e a e todavia. A leitura das sequˆncias deve ser feita caracter por caracter e o final e de cada sequˆncia ´ sinalizada pelo caracter ’.’. Se a segunda sequˆncia ´ uma e e e e subpalavra, a sa´ do programa deve ser a posi¸˜o na qual ela come¸a. Caso ıda ca c contr´rio, escrever a mensagem “Nao eh subpalavra.”. Observa¸oes: a c˜ • cada sequˆncia tem no m´ximo 80 caracteres. e a • vocˆ n˜o pode utilizar fun¸oes de manipula¸ao de cadeias de caracteres e a c˜ c˜ existentes no compilador, mas somente as fun¸oes para o tipo char. c˜ Exemplo de execu¸˜o: ca Entre com duas palavras terminadas por ponto: metodo.todo. A segunda subpalavra comeca na posicao 3 da primeira. 27. Escreva um programa em que leia uma sequˆncia de n valores reais (n ≤ 100) e e os insira num vetor. A sequˆncia termina quando o valor lido for 0. O programa e deve escrever o valor da divis˜o da soma dos valores positivos pela soma dos valores a negativos que est˜o armazenados no vetor. Cuidado com divis˜es por zero. a o 28. Escreva uma fun¸˜o em que substitui em um texto a primeira ocorrˆncia de uma ca e palavra por outra. A fun¸˜o deve retornar true se a substitui¸˜o for bem sucedida ca ca e false caso a palavra n˜o seja encontrada no texto. O texto e as palavras s˜o a a representados por vetores do tipo char. Por exemplo: +---+---+---+---+---+---+---+---+---+---+ texto1 | e | x | e | m | p | r | o | | u | n | +---+---+---+---+---+---+---+---+---+---+ +---+---+---+---+---+ palavra1 | r | o | | u | n | +---+---+---+---+---+ +---+---+---+---+---+---+---+ palavra2 | l | o | | d | o | i | s | +---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+---+---+---+---+ texto2 | e | x | e | m | p | l | o | | d | o | i | s | +---+---+---+---+---+---+---+---+---+---+---+---+ A fun¸˜o recebe como parˆmetros o texto, a palavra a ser substitu´ e a nova palavra. ca a ıda No exemplo, texto1 mostra o estado inicial do texto e texto2 o estado do texto ap´s o a substitui¸˜o da palavra1 pela palavra2. ca Vocˆ pode usar, caso seja necess´rio, a fun¸˜o: e a ca buscachar(texto, pos, letra);
    • 170 CAP´ ITULO 10. ESTRUTURAS DE DADOS que busca um caractere (letra) a partir de uma determinada posi¸˜o (pos) em um ca vetor que cont´m o texto (texto). A fun¸˜o buscaletra retorna a posi¸˜o no vetor e ca ca texto da primeira ocorrˆncia de letra, se letra n˜o aparece no texto a fun¸˜o e a ca retorna -1. 29. Um algoritmo gen´tico ´ um procedimento computacional de busca, inspirado no pro- e e cesso biol´gico de evolu¸˜o, que otimiza a solu¸˜o de um problema. O problema ´ o ca ca e modelado por: uma popula¸˜o de indiv´ ca ıduos que representam poss´ ıveis solu¸˜es; uma co fun¸˜o que avalia a qualidade da solu¸˜o representada por cada indiv´ ca ca ıduo da popula¸˜oca e um conjunto de operadores gen´ticos. Os indiv´ e ıduos s˜o dados por sequˆncias de a e genes que representam caracter´ ısticas da solu¸˜o do problema. O procedimento con- ca siste em aplicar os operadores gen´ticos sobre a popula¸˜o, gerando novos indiv´ e ca ıduos e selecionar os mais aptos para constituirem uma nova popula¸˜o. Esse processo ´ ca e repetido at´ que uma solu¸˜o adequada seja obtida. Dentre os operadores gen´ticos, e ca e o mais importante ´ o de recombina¸˜o gen´tica (crossover ) de dois indiv´ e ca e ıduos. Esse operador corta em duas partes as sequˆncias de genes de dois indiv´ e ıduos pais (pai1 e pai2) e gera dois novos indiv´ ıduos filhos (filho1 e filho2). filho1 ´ dado pela e contatena¸˜o da primeira parte dos genes de pai1 com a segunda parte de pai2 e ca filho2 pela concatena¸˜o da primeira parte de pai2 com a segunda parte de pai1. ca O diagrama abaixo exemplifica a opera¸˜o em indiv´ ca ıduos representados por vetores de n´meros inteiros onde a primeira posi¸˜o cont´m o tamanho do vetor: u ca e corte1 +----+---+---+---#---+---+---+---+---+---+---+---+ pai1 | 11 | 1 | 1 | 1 # 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | +----+---+---+---#---+---+---+---+---+---+---+---+ corte2 +----+---+---+---+---+---#---+---+---+---+---+ pai2 | 10 | 3 | 3 | 3 | 3 | 3 # 4 | 4 | 4 | 4 | 4 | +----+---+---+---+---+---#---+---+---+---+---+ +----+---+---+---+---+---+---+---+---+ filho1 | 8 | 1 | 1 | 1 | 4 | 4 | 4 | 4 | 4 | +----+---+---+---+---+---+---+---+---+ +----+---+---+---+---+---+---+---+---+---+---+---+---+---+ filho2 | 13 | 3 | 3 | 3 | 3 | 3 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | +----+---+---+---+---+---+---+---+---+---+---+---+---+---+ Escreva um procedimento em que execute a opera¸˜o de recombina¸˜o descrita acima, ca ca usando a estrutura de dados vetor. O procedimento deve receber seis parˆmetros, um a vetor representando o primeiro pai, a posi¸˜o de corte no primeiro pai, um vetor ca representando o segundo pai, a posi¸˜o do corte no segundo pai, e dois vetores que ca receber˜o os novos indiv´ a ıduos. No exemplo apresentado a chamada do procedimento seria: corte1 := 4; corte2 := 6; crossover(pai1, corte1, pai2, corte2, filho1, filho2);
    • 10.1. VETORES 171 Note que os vetores devem iniciar na posi¸˜o zero e essa posi¸˜o ´ usada para ar- ca ca e mazenar o tamanho do vetor. No caso do exemplo, pai1[0]=11, pai2[0]=10, filho1[0]=8 e filho2[0]=13. Os pontos de corte devem estar dentro dos vetores: 1 < corte1 <= pai1[0] e 1 < corte2 <= pai2[0]. 30. Escreva um procedimento em que implemente a subtra¸˜o de n´meros bin´rios. Con- ca u a sidere que os n´meros bin´rios tˆm N bits e que os bits s˜o armazenados em vetores u a e a de inteiros de N posi¸˜es indexadas de 1 a N . O primeiro bit do vetor representa o co sinal do n´mero, sendo zero (0) para o n´meros positivos e um (1) para negativos. u u Os demais bits representam o valor absoluto do n´mero. Por exemplo, para N = 11, u os n´meros decimais −13, 12 e 1010 s˜o representados pelos seguintes vetores: u a +---+---+---+---+---+---+---+---+---+---+---+ -13: | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | +---+---+---+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+---+---+---+ 12: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | +---+---+---+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+---+---+---+ 1010: | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | +---+---+---+---+---+---+---+---+---+---+---+ O procedimento recebe dois vetores do mesmo tamanho como parˆmetros e deve gerar a como resultado um vetor que contenha a subtra¸˜o do primeiro pelo segundo. Por ca exemplo −12 − 1010 = −1022: +---+---+---+---+---+---+---+---+---+---+---+ -998: | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | +---+---+---+---+---+---+---+---+---+---+---+ Caso o resultado tenha mais bits que o espa¸o dispon´ c ıvel no vetor o procedimento deve descartar os bits excedentes. 31. Escreva um programa em que leia uma sequˆncia de N valores reais n˜o nulos (N ≤ e a 100) e os insira em um vetor. A sequˆncia termina quando o valor lido for 0. O e elemento zero n˜o faz parte do vetor. Leia do teclado um inteiro p (p ≤ N ) e considere a que o elemento V [p] como o pivˆ na opera¸˜o de rearranjar o vetor de tal maneira o ca que todos os elementos ` esquerda de V [p] sejam menores que ele e todos os da direta a sejam maiores ou iguais a ele. Por exemplo, considere o seguinte vetor dado como entrada: +------+------+------+------+------+------+------+ | 99.7 | 32.6 | 2.45 | 13.4 | 26.7 | 12.2 | 0.51 | +------+------+------+------+------+------+------+ e P valendo 3, o programa deve gerar como resultado um vetor onde todos os elementos que est˜o ` esquerda do valor 2.45 no vetor sˆo menores que ele, enquanto que os da a a a direita s˜o maiores do que ele. a
    • 172 CAP´ ITULO 10. ESTRUTURAS DE DADOS 32. Escreva uma fun¸˜o em que procura uma palavra dentro de um texto. A fun¸˜o deve ca ca receber como parˆmetros: a • um vetor do tipo texto que cont´m um texto; e • o tamanho do vetor que cont´m o texto; e • a posi¸˜o inicial da busca dentro do vetor que cont´m o texto; ca e • um vetor do tipo texto que cont´m uma palavra; e • o tamanho do vetor que cont´m a palavra. e A fun¸˜o deve retornar um n´mero inteiro indicando a posi¸˜o no texto onde a palavra ca u ca foi encontrada pela primeira vez. Caso a palavra n˜o seja encontrada ou algum erro ocorra o valor retornado deve ser a zero. A busca pela palavra no texto deve iniciar na posi¸˜o passada como parˆmetro ca a para a fun¸˜o. ca O tipo texto ´ dado por: e const TAMMAX = 10000; type texto = array [1..TAMMAX] of char; 33. Escreva um programa em que gere e imprima um vetor de n´meros reais de tamanho u N , 1 ≤ N ≤ M AX. A cria¸˜o do vetor deve ser feita da seguinte maneira: ca • O tamanho N do vetor deve ser lido do teclado; • Os N n´meros reais s˜o gerados aleatoriamente no intervalo [Rmin , Rmax [, com u a Rmin e Rmax lidos do teclado; • A posi¸˜o em que cada elemento real ´ inserida no vetor tamb´m ´ gerada ca e e e aleatoriamente; • Se uma posi¸ao i sorteada j´ estiver ocupada, seu algoritmo deve encontrar a c˜ a primeira posi¸˜o j n˜o ocupada, iniciando a partir de i+1 at´ o final do vetor. Se ca a e todas as posi¸˜o entre i + 1 e o final do vetor estiverem ocupadas, seu algoritmo ca deve pegar a primeira posi¸˜o livre a partir do in´ do vetor. ca ıcio Dica: a fun¸˜o random sem parˆmetros retorna um n´mero real no intervalo [0, 1[, e ca a u a fun¸˜o random(n) retorna um n´mero inteiro no intervalo [0, n[. ca u 34. Escreva um procedimento em que remove um elemento de uma determinada posi¸˜o ca p de um vetor v de n n´meros reais. O vetor n˜o est´ ordenado. Use a seguinte u a a assinatura para o procedimento: procedure remove(var v: vetor; var n: integer; p: integer);
    • 10.1. VETORES 173 35. Escreva um procedimento em que altere um vetor de N n´meros reais da seguinte u forma: todos os elementos repetidos do vetor devem ir para o final do vetor, mas de maneira que estes ultimos fiquem em ordem crescente. Exemplos: ´ ENTRADA: 5 3 8 2 3 9 8 9 7 5 3 ENTRADA: 4 4 3 3 2 2 SA´DA : 5 3 8 2 9 7 3 3 5 8 9 I SA´DA : 4 3 2 2 3 4 I 36. Em uma festa estiveram presentes 150 pessoas. Cada uma delas recebeu um crach´ a na entrada com um n´mero entre 1 e 150, n´mero que representa a ordem de entrada u u de cada convidado. Como em toda festa, cada um dos presentes cumprimentou outras pessoas com apertos de m˜o. Ao final da festa, cada convidado sabia exatamente quantas vezes tinha a apertado a m˜o de outras pessoas. a Na sa´ıda, ao entregar o crach´ ao recepcionista, cada convidado informou o n´mero a u do seu crach´ e quantas vezes trocou apertos de m˜o na festa. a a Muito curioso, o recepcionista queria saber quantos convidados eram muito populares no encontro, isto ´, queria saber o n´mero de pessoas que apertaram a m˜o de pelo e u a menos outros 120 convidados. Fa¸a um programa que modele o problema do recepcionista e que produza como sa´ c ıda o n´mero de celebridades (cumprimentadas pelo menos 120 vezes) presentes na festa. u 37. Um procedimento chamado nova geracao recebe como parˆmetros dois vetores (ori- a gem e destino) e o tamanho dos vetores. Este procedimento constr´i um novo vetor o de valores 0 ou 1 (destino) a partir do conte´do do primeiro vetor (origem). Seja O o u vetor origem e D o vetor destino, a regra para a constru¸˜o do novo vetor ´ dada por: ca e • se: O[i − 1] = 0, O[i] = 0, O[i + 1] = 0 ent˜o: D[i] = 0 a • se: O[i − 1] = 0, O[i] = 0, O[i + 1] = 1 ent˜o: D[i] = 1 a • se: O[i − 1] = 0, O[i] = 1, O[i + 1] = 0 ent˜o: D[i] = 1 a • se: O[i − 1] = 0, O[i] = 1, O[i + 1] = 1 ent˜o: D[i] = 1 a • se: O[i − 1] = 1, O[i] = 0, O[i + 1] = 0 ent˜o: D[i] = 1 a • se: O[i − 1] = 1, O[i] = 0, O[i + 1] = 1 ent˜o: D[i] = 0 a • se: O[i − 1] = 1, O[i] = 1, O[i + 1] = 0 ent˜o: D[i] = 0 a • se: O[i − 1] = 1, O[i] = 1, O[i + 1] = 1 ent˜o: D[i] = 0 a Onde i indica uma posi¸˜o do vetor D. Considere o valor 0 para as bordas externas ca do vetor origem O. Escreva o procedimento nova geracao e separe a regra descrita acima em uma fun¸˜o que dados os valores das 3 posi¸˜es consecutivas do vetor origem ca co (O[i − 1], O[i], O[i + 1]) calcula o valor correspondente no vetor destino (D[i]). 38. Fa¸a um programa em que simule o tr´fego em um trecho de uma rodovia de m˜o c a a unica, ou seja, uma rodovia na qual os ve´ ´ ıculos entram de um lado e saem do outro. • A rodovia ´ representada por um vetor com TAM_RODOVIA posi¸˜es; e co • A simula¸˜o ocorre durante MAX_TEMPO itera¸˜es; ca co
    • 174 CAP´ ITULO 10. ESTRUTURAS DE DADOS • Atrav´s da chamada do procedimento e detecta_entrada(VAR tipo, placa, velocidade:INTEGER), o programador ´ informado sobre a ocorrˆncia ou n˜o da entrada de um ve´ e e a ıculo na rodovia, bem como o tipo do ve´ ıculo, sua placa e sua respectiva velocidade, onde: – tipo: 0 - nenhuma nova entrada, 1 - entrou autom´vel, 2 - entrou caminh˜o; o a – placa: um n´mero inteiro; u – velocidade: a velocidade de deslocamento do ve´ıculo (em posi¸˜es/unidade co de tempo). • Ve´ ıculos do tipo autom´vel ocupam uma posi¸˜o da rodovia. Caminh˜es ocupam o ca o duas posi¸˜es. co • Quando ve´ıculos mais r´pidos alcan¸am ve´ a c ıculos mais lentos, os primeiros devem andar mais devagar, pois n˜o podem ultrapassar. a A cada unidade de tempo em que algum ve´ ıculo sair da rodovia, seu programa deve imprimir esta unidade de tempo e o n´mero da placa do ve´ u ıculo que saiu. Exemplo: (TAM_RODOVIA=7, MAX_TEMPO=10) • Entrada: – t=1: tipo = 2, placa = 35, velocidade = 1 – t=2: tipo = 0 – t=3: tipo = 1, placa = 27, velocidade = 4 – t=4: tipo = 0 – t=5: tipo = 0 – t=6: tipo = 1, placa = 16, velocidade = 2 – t=7: tipo = 0 – t=8: tipo = 0 – t=9: tipo = 0 – t=10: tipo = 0 • Representa¸˜o gr´fica: ca a – t=1: 351 351 – t=2: 351 351 – t=3: 274 351 351 – t=4: 274 351 351 – t=5: 274 351 351 – t=6: 162 274 351 351 – t=7: 162 274 351 – t=8: 162 274 – t=9: 162 – t=10: • Sa´ ıda:
    • 10.1. VETORES 175 – t=8: 35 – t=9: 27 – t=10: 16 39. Vocˆ deve incluir no enunciado da quest˜o anterior a existˆncia de uma pista de e a e ultrapassagem. Agora, ve´ ıculos mais r´pidos podem mover-se para a pista de ultra- a passagem ao alcan¸arem ve´ c ıculos mais lentos, desde que n˜o haja ningu´m ocupando a e aquele trecho de pista. Eles devem retornar ` pista original assim que tiverem com- a pletado a ultrapassagem, retomando a velocidade original. Vocˆ deve escrever apenas e os procedimentos modificados ou novos que levam em conta este novo fato. Exemplo da nova sa´ para a entrada original: ıda • Representa¸˜o gr´fica: ca a – t=1: 351 351 – t=2: 351 351 – t=3: 274 351 351 274 – t=4: 351 351 – t=5: 351 351 274 – t=6: 162 351 351 – t=7: 162 351 – t=8: 162 – t=9: 162 – t=10: • Sa´ ıda: – t=6: 27 – t=8: 35 – t=10: 16 40. Mateus, um engenheiro novato, est´ desenvolvendo uma nota¸˜o posicional original a ca para representa¸˜o de n´meros inteiros. Ele chamou esta nota¸˜o de UMC (Um ca u ca m´todo curioso). A nota¸˜o UMC usa os mesmos d´ e ca ıgitos da nota¸˜o decimal, isto ca ´, de 0 a 9. Para converter um n´mero A da nota¸˜o UMC para a nota¸˜o decimal e u ca ca deve-se adicionar K termos, onde K ´ o n´mero de d´ e u ıgitos de A (na nota¸˜o UMC). O ca
    • 176 CAP´ ITULO 10. ESTRUTURAS DE DADOS valor do i-´simo termo correspondente ao i-´simo d´ e e ıgito ai , contando da direita para a esquerda ´ ai × i!. e Por exemplo, 719U M C ´ equivalente a 5310 , pois 7 × 3! + 1 × 2! + 9 × 1! = 53. e Mateus est´ apenas come¸ando seus estudos em teoria dos n´meros e provavelmente a c u n˜o sabe quais as propriedades que um sistema de numera¸˜o deve ter, mas neste a ca momento ele est´ apenas interessado em converter os n´meros da nota¸˜o UCM para a u ca a nota¸˜o decimal. Vocˆ pode ajud´-lo? ca e a Entrada: cada caso de teste ´ fornecido em uma linha simples que cont´m um n´mero e e u n˜o vazio de no m´ximo 5 d´ a a ıgitos, representando um n´mero em nota¸˜o UMC. Este u ca n´mero n˜o cont´m zeros a esquerda. O ultimo teste ´ sequido por uma linha contendo u a e ´ e um zero. Sa´ıda: para cada caso de teste imprimir uma linha simples contendo a representa¸˜o ca em nota¸˜o decimal do correspondente n´mero em UMC seguido do c´lculo feito para ca u a a convers˜o. a O programa: seu programa deve, para cada n´mero da entrada, convertˆ-lo em um u e vetor de inteiros, sendo que cada d´ ıgito do n´mero ´ um elemento do vetor, e fazer os u e c´lculos usando este vetor. a Exemplos de entrada e sa´ ıda: ENTRADA ´ SAIDA 719 53 = 7 x 3! + 1 x 2! + 9 x 1! 1 1 = 1 x 1! 15 7 = 1 x 2! + 5 x 1! 110 8 = 1 x 3! + 1 x 2! + 0 x 1! 102 8 = 1 x 3! + 0 x 2! + 2 x 1! 0 41. Sabemos que nos compiladores mais recentes, nos quais existe o tipo string, podemos realizar de maneira simples opera¸˜es com palavras. Imagine, no entanto, que estamos co usando um compilador Pascal no qual n˜o existe este tipo. Neste caso o programa- a dor deve implementar por sua pr´pria conta os procedimentos com palavras. Neste o exerc´ iremos considerar a seguinte declara¸˜o alternativa para o tipo string: ıcio ca type palavra = array[1..MaxTam] of char; Implemente uma fun¸˜o em Pascal que receba como parˆmetros duas vari´veis do ca a a tipo MeuString e retorne -1 se a primeira palavra for lexicograficamente menor que a segunda, 0 se forem iguais, e +1 no caso que resta. 42. Fa¸a um programa que leia um certo n´mero indefinido de vetores e que imprima c u o vetor original (O) e um vetor gerado (G) ap´s um processo de compacta¸˜o que o ca consiste na elimina¸˜o de todos os elementos repetidos em cada vetor. Considere que ca a entrada de dados ´ feita em um vetor por linha, sendo que o primeiro elemento da e linha ´ o tamanho de cada vetor e os elementos restantes da linha s˜o os elementos e a do vetor. Quando o tamanho for zero significa que terminou a entrada de dados. Por exemplo, considere a seguinte entrada:
    • 10.1. VETORES 177 5 2 4 7 -1 2 3 1 1 1 7 3 4 5 3 4 5 1 0 Dever´ produzir como sa´ o seguinte: a ıda O: 2 4 7 -1 2 G: 2 4 7 -1 O: 1 1 1 G: 1 O: 3 4 5 3 4 5 1 G: 3 4 5 1 43. Considere uma sequˆncia de d´ e ıgitos bin´rios como: a 011100011 Uma maneira de criptografar essa sequˆncia de bits ´ adicionar ` cada d´ e e a ıgito a soma dos seus d´ ıgitos adjacentes. Por exemplo, a sequˆncia acima se tornaria: e 123210122 Se P ´ a sequˆncia original e Q ´ a sequˆncia criptografada, ent˜o Q[i] = P [i − 1] + e e e e a P [i] + P [i + 1] para todas as posi¸˜es i da sequˆncia. Considerando uma sequˆncia co e e de tamanho n e seus ´ ındices variando de 0 a n − 1, os d´ ıgitos P [−1] e P [n] n˜o fazem a parte da sequˆncia original e s˜o tratados como zeros na opera¸˜o de codifica¸˜o. e a ca ca Assumindo P [0] = 0 temos: • Q[0] = P [0] + P [1] = 0 + P [1] = 1, logo P [1] = 1. • Q[1] = P [0] + P [1] + P [2] = 0 + 1 + P [2] = 2, logo P [2] = 1. • Q[2] = P [1] + P [2] + P [3] = 1 + 1 + P [3] = 3, logo P [3] = 1. • Repetindo a opera¸˜o temos: P [4] = 0, P [5] = 0, P [6] = 0, P [7] = 1 e P [8] = 1. ca Agora repetindo o mesmo processo para P [0] = 1 temos: • Q[0] = P [0] + P [1] = 1 + P [1] = 1, logo P [1] = 0. • Q[1] = P [0] + P [1] + P [2] = 1 + 0 + P [2] = 2, logo P [2] = 1. • Q[2] = P [1] + P [2] + P [3] = 0 + 1 + P [3] = 3, o que nos leva a conclus˜oa que P [3] = 2. Entretanto isso viola o fato da sequˆncia original ser bin´ria. e a Portanto n˜o existe uma decodifica¸˜o poss´ considerando o primeiro d´ a ca ıvel ıgito da sequˆncia original valendo 1. e Note que este algoritmo pode gerar ou decodificar uma sequˆncia criptografada em e at´ duas poss´ e ıveis sequˆncias originais, uma iniciando com 0 e outra iniciando com 1. e Escreva um procedimento em que receba como parˆmetros um vetor de n´meros a u inteiros contendo a sequˆncia criptografada e a decodifica em dois outros vetores de e n´meros inteiros. Caso uma das decodifica¸˜es n˜o seja poss´ u co a ıvel, como no caso do
    • 178 CAP´ ITULO 10. ESTRUTURAS DE DADOS exemplo para P [0] = 1, o vetor correspondente deve ser preenchido com -1 na posi¸˜o ca inicial. Outros exemplos: • 123210122 = 011100011, −1 • 11 = 01, 10 • 22111 = −1, 11001 • 123210120 = −1, −1 • 3 = −1, −1 • 12221112222221112221111111112221111 = 01101001101101001101001001001101001, 10110010110110010110010010010110010 44. Escrever um programa para ler um texto e imprimir uma distribui¸˜o de frequˆncias ca e para palavras do texto (quantas palavras de uma letra, quantas de duas letras, etc.). 45. Escreva um programa em Pascal que leia do teclado o gabarito de uma prova de 20 quest˜es de m´ltipla escolha, onde as respostas s˜o inteiros de 1 a 5. Em seguida, o u a o programa deve ler o n´mero de alunos que prestaram a prova e, para cada aluno, u a sua matr´ ıcula (um inteiro) e as respectivas respostas. O programa deve calcular e escrever: • a rela¸˜o de alunos ordenados pela nota, supondo que cada quest˜o vale 5 pontos; ca a • para cada quest˜o: quantos alunos acertaram a quest˜o a a
    • 10.2. MATRIZES 17910.2 MatrizesAssim como os vetores, as matrizes s˜o arrays. Os vetores s˜o estruturas unidimen- a asionais enquanto que as matrizes s˜o bidimensionais. Isto ´, o acesso as posi¸oes de a e ` c˜mem´ria de um vetor s˜o feitas com base em duas informa¸˜es: o nome da vari´vel e o a co ao deslocamento. Para se acessar os elementos de uma matriz, precisa-se do nome davari´vel, do deslocamento lateral e do deslocamento vertical. Os elementos de uma amatriz tamb´m s˜o do mesmo tipo. e a10.2.1 Matrizes em PascalPara se declarar uma matriz de 200 posi¸˜es inteiras, sendo 20 na vertical e 10 na hori- cozontal, a linguagem Pascal usa a seguinte sintaxe (lembre-se que em outras linguagensa sintaxe pode ser diferente):var m: array [ 1 . . 2 0 , 1 . . 1 0 ] of integer ; A constru¸ao “1..20,1..10” indica que existem 20 posi¸˜es na horizontal (linhas) e c˜ co10 na vertical (colunas). O “of integer” indica que cada posi¸ao ´ para se guardar um c˜ en´mero inteiro, isto ´ 2 bytes (dependendo da implementa¸˜o). u e ca Todas as restri¸oes e variantes que usamos para os vetores valem tamb´m para as c˜ ematrizes. Isto ´, as declara¸˜es seguintes tamb´m s˜o v´lidas: e co e a avar m: array [ 0 . . 1 9 , 0 . . 9 ] of integer ;var m: array [21..40,−19..−10] of integer ;var m: array [ −19..0 ,51..60] of integer ;const maxLin=20, maxCol=10;var m: array [ 1 . .maxLin, 1 . .maxCol] of integer ; Agora, para escrever um valor qualquer, digamos 12345, na linha 15 e coluna 7 damatriz m, em Pascal, se usa um dos dois comandos seguintes:m[15 ,7]:= 12345;read(m[15 ,7]) ; (∗ e se digita 12345 no teclado ∗) Por exemplo, a matriz abaixo tem 5 linhas e 4 colunas e pode ser visualizada domodo padr˜o: a 1 2 3 4 1 4 6 2 1 2 9 0 0 2 3 8 7 3 9 4 1 2 3 4 5 0 1 0 1
    • 180 CAP´ ITULO 10. ESTRUTURAS DE DADOS A declara¸ao do tipo matriz em Pascal ´ assim: c˜ etype matriz= array [1..5,1..4] of integer; No exemplo acima, a primeira linha ´ constitu´ pelos elementos seguintes: 4, 6, e ıda2 e 1. A terceira coluna pelos elementos 2, 0, 3, 3 e 0. Podemos destacar a t´ ıtulo deexemplo alguns elementos da matriz. Consideremos uma vari´vel m do tipo matriz. aEnt˜o: m[3, 2] = 7, m[2, 3] = 0, m[3, 4] = 9, e assim por diante. a Notem que, isoladamente, cada linha ou coluna completa pode ser imaginada comosendo um vetor. De fato, uma outra maneira de se ver uma matriz ´ como sendo um evetor de vetores! Confira a declara¸ao seguinte: c˜type vetor= array [ 1 . . 4 ] of integer ; matriz= array [ 1 . . 5 ] of vetor ;var m: matriz ; Em Pascal, ´ correto dizer que, para o exemplo acima: m[3][2] = 7, m[2][3] = 0, em[3][4] = 9, e assim por diante. N´s usaremos a constru¸ao apresentada inicialmente. o c˜10.2.2 Exemplos elementaresDo mesmo modo como fizemos para os vetores, vamos iniciar o estudo das matrizesapresentando problemas simples.Lendo e imprimindo matrizesA leitura dos elementos de uma matriz ´ bastante parecida com a leitura de vetores. eImaginando que cada linha da matriz ´ um vetor, basta fixar uma linha e ler todos os eelementos das colunas. Agora ´ s´ repetir o procedimento para todas as linhas. Isto e oleva naturalmente a um c´digo com um la¸o duplo: um para variar as linhas o outro o cpara as colunas. A figura 10.38 permite visualizar o c´digo para a leitura de uma omatriz.program ler matriz ;var w: array [ 0 . . 5 0 , 1 . . 1 0 ] of real ; i , j : integer ;begin for i:= 0 to 50 do for j:= 1 to 10 do read (w[ i , j ] ) ;end. Figura 10.38: Lendo uma matrizes. Da forma como foi constru´ ıdo, este c´digo exige que se digite os elementos da oprimeira linha, depois os da segunda e assim por diante. No la¸o mais interno, con- ctrolado pelo j, observem que o i ´ fixo, apenas o j varia, desta forma, a leitura das e
    • 10.2. MATRIZES 181colunas de uma linha fixa ´ idˆntico a ler um vetor. O la¸o mais externo, controlado e e cpelo i, faz variar todas as linhas. Da mesma forma como apresentamos os vetores, vamos mostrar os c´digos ape- onas em termos de procedimentos e fun¸oes. Para isto vamos precisar considerar as c˜seguintes defini¸oes: c˜const maxLin = 50; maxCol = 40;type matriz= array [ 0 . .maxLin, 1 . .maxCol] of real ; Tamb´m vamos considerar que apenas uma parte da matriz ser´ usada, logo pre- e acisaremos sempre fazer a leitura das dimens˜es de uma matriz. Neste sentido, a ofigura 10.39 apresenta um procedimento que lˆ uma matriz de dimens˜es n × m. e oprocedure ler (var w: matriz ; var n, m: integer) ;var i , j : integer ;begin read (n) ; (∗ n deve estar no intervalo 1..maxLin ∗) read (m) ; (∗ m deve estar no intervalo 1..maxCol ∗) for i:= 1 to n do for j:= 1 to m do read (w[ i , j ] ) ;end; Figura 10.39: Procedimento para ler uma matriz. As mesmas observa¸˜es sobre passagem de parˆmetros que foram feitas sobre os ve- co atores se aplicam aqui, isto ´, pelo overhead, sempre passamos matrizes por referˆncia. e eA figura 10.40 apresenta um procedimento para impress˜o de uma matriz usando apassagem de parˆmetros por referˆncia, embora n˜o fosse estritamente necess´rio. O a e a aprocedimento foi constru´ para imprimir a matriz linha por linha. ıdoprocedure imprimir (var w: matriz ; n,m: integer) ;var i , j : integer ;begin for i:= 1 to n do begin for j:= 1 to m do write (w[ i , j ] ,’ ’) ; writeln ; (∗ muda de linha a cada fim de coluna ∗) end;end; Figura 10.40: Procedimento para imprimir uma matriz. Tomando como exemplo a matriz do in´ desta se¸ao, se forem digitados todos os ıcio c˜valores, linha por linha, para cada uma do in´ at´ o final de cada coluna, ter´ ıcio e ıamosem mem´ria algo como ilustrado na figura seguinte: o
    • 182 CAP´ ITULO 10. ESTRUTURAS DE DADOS 1 2 3 4 5 ... 40 1 4 6 2 1 ? ? 2 9 0 0 2 ? ? 3 8 7 3 9 ? ? 4 1 2 3 4 ? ? 5 0 1 0 1 ? ? . . . 50 ? ? ? ? ? ? A t´ ıtulo de exemplo, poder´ıamos construir um procedimento que imprime a matrizem sua forma transposta, isto ´, com as linhas e colunas invertidas. Isto ´ apresentado e ena figura 10.41. Basta inverter i e j no comando de impress˜o! Observem que a matriz an˜o mudou na mem´ria, apenas a impress˜o ´ diferente. a o a eprocedure imprimir transposta (var w: matriz ; n,m: integer) ;var i , j : integer ;begin for i:= 1 to n do begin for j:= 1 to m do write (w[ j , i ] ,’ ’) ; (∗ i e j invertidos imprime transposta ∗) writeln ; end;end; Figura 10.41: Procedimento para imprimir a transposta de uma matriz. Outros procedimentos interessantes s˜o os de impress˜o de apenas uma certa linha a a(figura 10.42) ou de apenas uma certa coluna (figura 10.43).procedure imprimir uma linha (var w: matriz ; n,m: integer ; K: integer) ;(∗ imprime a linha K da matriz ∗)var j : integer ;begin for j:= 1 to m do write (w[K, j ] ,’ ’) ; (∗ K fixo na primeira posicao ∗) writeln ;end; Figura 10.42: Procedimento para imprimir uma unica linha da matriz. Considerando o exemplo acima e fazendo K = 2 ter´ ıamos a seguinte sa´ ıda:9 0 0 2 Considerando o exemplo acima e fazendo K = 2 ter´ ıamos a seguinte sa´ ıda:
    • 10.2. MATRIZES 183procedure imprimir uma coluna(var w: matriz ; n,m: integer ; K: integer) ;(∗ imprime a coluna K da matriz ∗)var i : integer ;begin for i:= 1 to n do writeln (w[ i ,K] ,’ ’) ; (∗ K fixo na segunda posicao ∗) writeln ;end; Figura 10.43: Procedimento para imprimir uma unica coluna da matriz.60721 Outro exemplo interessante seria imprimir apenas os elementos da matriz que s˜o apares, conforme mostrado na figura 10.44.procedure imprimir os pares(var w: matriz ; n,m: integer) ;var i , j : integer ;begin for i:= 1 to n do begin for j:= 1 to m do i f eh par (w[ i , j ] ) then write (w[ i , j ] ,’ ’) ; end;end; Figura 10.44: Procedimento para imprimir os elementos pares matriz. Considerando novamente a nossa matriz exemplo, ter´ ıamos a seguinte sa´ ıda:4 6 2 0 0 2 8 2 4 0 0 Para finalizarmos esta se¸˜o inicial, apresentamos na figura 10.45 um c´digo que ca oimprime os elementos cujos ´ ındices das linhas e das colunas s˜o pares. Considerando anovamente a nossa matriz exemplo, ter´ ıamos a seguinte sa´ ıda:0 22 4
    • 184 CAP´ ITULO 10. ESTRUTURAS DE DADOSprocedure imprimir as linhas e colunas pares (var w: matriz ; n,m: integer) ;var i , j : integer ;begin for i:= 1 to n do begin for j:= 1 to m do i f eh par ( i ) and eh par( j ) then write (w[ i , j ] ,’ ’) ; writeln ; end;end; Figura 10.45: Procedimento para imprimir os elementos cujos indices s˜o pares. aEncontrando o menor elemento de uma matrizVamos retornar ao velho e conhecido problema de se determinar qual ´ o menor eelemento de um conjunto de n´meros em mem´ria, considerando que, desta vez, eles u oestar˜o armazenados em uma matriz. A figura 10.46 cont´m o c´digo que faz isto. a e oNote a semelhan¸a com os programas das se¸oes anteriores. A t´cnica ´ a mesma: o c c˜ e eprimeiro elemento ´ considerado o menor de todos e depois a matriz tem que ser toda epercorrida (todas as linhas e todas as colunas) para ver se tem outro elemento aindamenor.function achamenor (var w: matriz ; n,m: integer) : real ;var i , j : integer ; maior : real ;begin menor:= w[ 1 , 1 ] ; for i:= 1 to n do for j:= 1 to m do i f w[ i , j ] < menor then menor:= w[ i , j ] ; achamenor:= menor;end; Figura 10.46: Encontrando o menor elemento de uma matriz.Soma de matrizesNesta se¸˜o vamos implementar o algoritmo que soma duas matrizes. Para isto pre- cacisamos antes entender como funciona o processo. Sejam v e w duas matrizes. Para som´-las, ´ preciso que elas tenham o mesmo a etamanho. Isto posto, o algoritmo cria uma nova matriz v + w onde cada elemento i, jda nova matriz ´ a soma dos respectivos elementos v[i, j] e w[i, j]. O esquema ´ muito e eparecido com a soma de vetores, j´ estudada, apenas, novamente, trata-se tamb´m da a esegunda dimens˜o. a
    • 10.2. MATRIZES 185 Desta forma, o algoritmo que soma os dois vetores dever´, para cada par i, j fixo, asomar os respectivos elementos em v e w e guardar em v + w. Variando i de 1 at´ oen´mero de linhas e j de 1 at´ o n´mero de colunas resolve o problema. O programa u e uque implementa esta ideia ´ apresentado na figura 10.47. eprocedure soma matrizes (var v, w, soma v w: matriz ; n,m: integer) ;var i , j : integer ;begin (∗ n e m sao o numero de linhas e colunas , respectivamente ∗) for i:= 1 to n do for j:= 1 to m do soma v w[ i , j ]:= v[ i , j ] + w[ i , j ] ;end; Figura 10.47: Somando duas matrizes. ´ E interessante comparar com o procedimento que soma vetores, apresentado nafigura 10.13. Se considerarmos que, no la¸o interno controlado pelo j o i ´ fixo, ent˜o c e aos dois procedimentos fazem a mesma opera¸ao de somar dois vetores! c˜Multiplica¸˜o de matrizes caAgora vamos resolver o problema da multiplica¸ao de matrizes. Inicialmente vamos c˜recordar como isto ´ feito. e Do ponto de vista matem´tico cada elemento da matriz resultado da multiplica¸ao a c˜de duas matrizes pode ser encarado como sendo o produto escalar de dois vetoresformados por uma linha da primeira matriz e por uma coluna da segunda. Vamos considerar duas matrizes An×m e Bm×p . A multiplica¸ao s´ pode ocorrer c˜ ose o n´mero de colunas da matriz A for igual ao n´mero de linhas da matriz B. Isto u upor causa do produto escalar de vetores, que exige que os vetores tenham o mesmotamanho. O resultado ´ uma matriz n × p. O produto escalar de vetores, conforme ej´ estudado, ´ o resultado da seguinte somat´ria: a e o m V [k] × W [k]. k=1 Vamos considerar duas matrizes A e B, fixando uma linha I na matriz A e umacoluna J na matriz B. Conforme j´ mencionado, fixar linhas ou colunas em matrizes a´ o mesmo que trabalhar com vetores. Ent˜o, neste caso, o produto escalar da linhae aI da matriz A pela coluna J da matriz B ´ dado pela seguinte somat´ria: e o m A[I, k] × B[k, J]. k=1 O programa que realiza esta opera¸ao ´ uma adapta¸ao simples do c´digo exibido c˜ e c˜ ona figura 10.14, que para fins did´ticos ´ mostrado na figura 10.48. a e
    • 186 CAP´ ITULO 10. ESTRUTURAS DE DADOSbegin (∗ considerando I e J fixos ∗) soma:= 0; for i:= 1 to m do soma:= soma + A[ I ,k] ∗ B[ k, J ] ; prod escalar:= soma;end; Figura 10.48: Produto escalar de uma linha da matriz por uma coluna da outra. Vejamos isto de forma ilustrada considerando as duas matrizes seguintes: 4 6 2 1 2 3 4 9 0 0 2 5 0 0 A: 8 7 3 9 B: 0 7 7 1 2 3 4 1 0 9 0 1 0 1 O produto escalar da linha (terceira) pela coluna (segunda) em destaque ´ o re- esultado da seguinte opera¸ao: 8 × 3 + 7 × 0 + 3 × 7 + 9 × 0 = 45. Este resultado ´ o c˜ evalor da linha 3 coluna 2 da matriz produto, isto ´, ´ o elemento AB[3,2]. e e Para se obter a resultado completo do produto de A por B, basta variar I naslinhas de A e J nas colunas de B. Isto ´ apresentado na figura 10.49. eprocedure multiplicacao matrizes (var A: matriz ; lin A , col A : integer ; var B: matriz ; lin B , col B : integer ; var AB: matriz ; var lin AB , col AB : integer ;var i , j , k: integer ;begin lin AB:= lin A ; col AB:= col B ; for i:= 1 to lin A do for j:= 1 to col B do begin AB[ i , j ]:= 0; for i:= 1 to m do AB[ i , j ]:= AB[ i , j ] + A[ i ,k] ∗ B[ k, j ] ; end;end. Figura 10.49: Multiplica¸ao de duas matrizes. c˜10.2.3 Procurando elementos em matrizesNesta se¸˜o vamos apresentar alguns problemas de busca de elementos em matrizes. caBusca em uma matrizO problema de busca em matrizes ´ similar ao caso dos vetores. O procedimento agora e´ quadr´tico, pois no pior caso a matriz inteira deve ser percorrida (caso em que oe aelemento n˜o est´ na matriz). A figura 10.50 cont´m o c´digo para este problema. a a e o
    • 10.2. MATRIZES 187function busca (var w: matriz ; n,m: integer ; x: integer) : boolean;var i , j : integer ; achou : boolean;begin achou:= false ; i:= 1; while ( i <= n) and not achou do begin j:= 1; while ( j <= m) and not achou do begin i f w[ i , j ] = x then achou:= true; j:= j + 1; end; i:= i + 1; end; busca:= achou ;end; Figura 10.50: Busca em uma matriz. As vezes ´ preciso saber as coordenadas i e j do elemento. A figura 10.51 mostra ecomo adaptar a fun¸˜o anterior com duas modifica¸oes: a primeira ´ que deve-se usar ca c˜ eum procedimento que retorna as duas coordenadas usando parˆmetros por referˆncia, a epois fun¸˜es retornam apenas um unico valor. A outra diferen¸a ´ que, quando o co ´ c eelemento ´ encontrado deve-se lembrar da linha e coluna correspondente. eprocedure acha pos elemento (var w: matriz ; n,m,x: integer ; var l , c : integer) ;var i , j : integer ; achou : boolean;begin (∗ trecho inicial omitido ∗) i f w[ i , j ] = x then begin (∗ quando acha o elemento , armazena as coordenadas ∗) achou:= true; l:= i ; c:= j ; end; (∗ trecho final omitido ∗)end; Figura 10.51: Busca em uma matriz, retornando as coordenadas (l,c). Um problema interessante ´ saber se uma matriz cont´m elementos repetidos. e eBasta varrer a matriz e, para cada elemento, saber se ele existe na matriz em posi¸ao c˜diferente. Isto exige um aninhamento de quatro la¸os! c Um la¸o duplo ´ necess´rio para se percorrer a matriz por completo, e depois um c e aoutro la¸o duplo para cada elemento para se saber se ele se repete. Isto resulta em um calgoritmo de ordem de n4 para uma matriz quadrada de ordem n, para o pior caso.
    • 188 CAP´ ITULO 10. ESTRUTURAS DE DADOSPara completar o grau de dificuldade, queremos parar o processamento t˜o logo um aelemento repetido seja encontrado. O c´digo final est´ ilustrado na figura 10.52. o afunction tem repetidos (var w: matriz ; n,m: integer) : boolean;var i , j , cont , p, q: integer ; repetiu : boolean;begin repetiu:= false ; i:= 1; while ( i <= n) and not repetiu do begin j:= 1; while ( j <= m) and not repetiu do begin p:= 1; while (p <= n) and not repetiu do begin q:= 1; while (q <= m) and not repetiu do begin i f (w[p,q] = w[ i , j ] ) and ((p < i ) or (q < j ) ) then > > repetiu:= true; q:= q + 1; end; p:= p + 1; end; j:= j + 1; end; i:= i + 1; end; tem repetidos:= repetiu ;end; Figura 10.52: Verifica se uma matriz tem elementos repetidos.10.2.4 Inserindo uma coluna em uma matrizVamos considerar o problema de receber uma matriz de dimens˜es n × m e um vetor ode n elementos e inserir o vetor como uma coluna adicional na matriz, que ficar´ com adimens˜es n × m + 1. o Por exemplo, consideremos a nossa matriz exemplo e o seguinte vetor: 1 2 3 4 1 4 6 2 1 2 9 0 0 2 1 2 3 4 5 3 8 7 3 9 7 6 5 4 3 4 1 2 3 4 5 0 1 0 1
    • 10.2. MATRIZES 189 Inicialmente vamos apenas inserir o vetor ap´s a ultima coluna, isto ´, o vetor ser´ o ´ e aa ultima coluna da nova matriz, tal como na figura seguinte, de ordem 5 × 5 (vetor ´inserido est´ em negrito na figura): a 1 2 3 4 5 1 4 6 2 1 7 2 9 0 0 2 6 3 8 7 3 9 5 4 1 2 3 4 4 5 0 1 0 1 3 O procedimento mostrado na figura 10.53 faz esta opera¸ao. c˜procedure insere coluna no fim (var w: matriz ; v: vetor ; var n,m: integer) ;(∗ recebe uma matriz e um vetor e insere o vetor como ultima coluna da matriz ∗)var i : integer ;begin for i:= 1 to n do w[ i ,m+1] := v[ i ] ; (∗ m eh fixo , queremos sempre a ultima coluna ∗) +1 m:= m + 1; (∗ altera o numero de colunas ∗)end; Figura 10.53: Insere um vetor como ultima coluna de uma matriz. ´ Um problema mais dif´ seria se quis´ssemos inserir o vetor em alguma coluna ıcil eque n˜o fosse a ultima da matriz. O exemplo seguinte mostra nossa matriz de exemplo a ´com o vetor inserido na coluna 2. 1 2 3 4 5 1 4 7 6 2 1 2 9 6 0 0 2 3 8 5 7 3 9 4 1 4 2 3 4 5 0 3 1 0 1 Neste caso, tal como no caso dos vetores, ter´ıamos que abrir espa¸o na matriz cantes de inserir o vetor. Esta ´ uma opera¸˜o bastante custosa, pois temos que mover e cav´rias colunas para frente, cada uma delas move n elementos para frente. O algoritmo aapresentado na figura 10.54 mostra estes dois passos, um que abre espa¸o o outro que cinsere o vetor no espa¸o aberto. c Para inserir linhas em uma matriz o procedimento ´ an´logo. e a
    • 190 CAP´ ITULO 10. ESTRUTURAS DE DADOSprocedure insere coluna k (var w: matriz ; v: vetor ; var n,m: integer , K: integer) ;(∗ recebe uma matriz e um vetor e insere o vetor na coluna K da matriz ∗)var i : integer ;begin (∗ primeiro abre espaco ∗) for j:= m downto K do (∗ para cada coluna , iniciando na ultima ∗) for i:= 1 to n do (∗ move elementos uma coluna para frente ∗) w[ i , j+1]:= w[ i , j ] ; (∗ depois insere na coluna K ∗) for i:= 1 to n do w[ i ,K] := v[ i ] ; (∗ K eh fixo , queremos sempre a K−esima coluna ∗) m:= m + 1; (∗ altera o numero de colunas ∗)end; Figura 10.54: Insere um vetor como K-´sima coluna de uma matriz. e10.2.5 Aplica¸˜es de matrizes em imagens coNosso objetivo nesta se¸ao ´ mostrar como podemos fazer modifica¸˜es em imagens c˜ e codigitais no formato PGM. Antes vamos resolver dois problemas que ser˜o uteis no a ´decorrer deste cap´ ıtulo.Primeiro desafioO primeiro desafio ´, dada uma matriz de dimens˜es n × n, vamos gerar uma segunda e omatriz a partir da primeira onde cada elemento ´ a m´dia da soma dele com trˆs e e ede seus vizinhos na matriz original. Para exemplificar o que queremos, vejamos aseguinte ilustra¸ao de uma matriz 4 × 4: c˜ 4 6 2 1 9 0 0 2 8 7 3 9 1 2 3 4 Queremos que a matriz nova tenha como elemento da primeira linha, primeiracoluna, a m´dia do quadrado constitu´ pelos elementos das duas primeiras linhas e ıdoconsiderando-se apenas as duas primeiras colunas, isto ´, a sub-matriz: e 4 6 9 0 A m´dia destes elementos ´ (4+6+9+0) = 4.75. e e 4 O elemento gerado para a primeira linha, segunda coluna ´ a m´dia da seguinte e esub-matriz: 2 1 0 2
    • 10.2. MATRIZES 191 Isto ´, (2+1+0+2) = 1.25. E assim por diante. No final, queremos produzir a e 4seguinte matriz, de ordem 2 × 2: 4.75 1.25 4.50 4.75 O procedimento que realiza este c´lculo ´ ilustrado na figura 10.55. Como estamos a eno in´ do estudo, vamos considerar sempre que a matriz as dimens˜es n e m s˜o ıcio o asempre pares.procedure media dos 4 vizinhos (var v, lin v , col v : integer var w, var lin w , col w : integer) ;(∗ produz a matriz w a partir da media dos vizinhos de v ∗)(∗ lin v , col v definem linhas e colunas da matriz v ∗)(∗ lin w , col w definem linhas e colunas da matriz w ∗)var i , j : integer ;begin lin w:= lin m div 2; col w:= col m div 2; for i:= 1 to lin w do for j:= 1 to col w do w[ i , j ]:= (m[2∗ i −1,2∗j −1] + m[2∗ i ,2∗ j −1] + m[2∗ i −1,2∗j ] + m[2∗ i ,2∗ j ] ) /4;end; Figura 10.55: Gerando matriz pela m´dia dos vizinhos. eSegundo desafioAgora vamos trabalhar com gera¸˜o de “peda¸os” de uma matriz, isto ´, dada uma ca c ematriz n × m, queremos gerar uma nova matriz que consiste de uma submatriz daprimeira. Para isto, vamos considerar uma “janela” da matriz original definida pelo cantosuperior esquerdo e pelo canto inferior direito. Vejamos um exemplo do que queremos.Vamos considerar novamente a matriz exemplo seguinte, de ordem 5 × 4: 4 6 2 1 9 0 0 2 8 7 3 9 1 2 3 4 0 1 0 1 A janela exemplo tem seu canto superior esquerdo nas coordenadas (2, 3) e seucanto inferior direito em (4, 4). Isto define a submatriz seguinte (elementos em negritona figura anterior):
    • 192 CAP´ ITULO 10. ESTRUTURAS DE DADOS 0 2 3 9 3 4 O procedimento apresentado na figura 10.56 gera a submatriz desejada.procedure gerasubmatriz(var m: matriz ; lin m , col m : integer ; var w: matriz ; var lin w , col w : integer ; x1, y1, x2, y2 : integer) ;(∗ (x1 ,y1) eh o canto superior esquerdo , (x2 ,y2) eh o canto inferior esquerdo ∗)var i , j : integer ;begin lin w:= x2 − x1 + 1; col w:= y2 − y1 + 1; for i:= 1 to lin w do for j:= 1 to col w do w[ i , j ]:= m[ i+x1−1,j+y1−1];end; Figura 10.56: Gerando submatriz.Matrizes que representam imagensUm dos formatos reconhecidos pelos computadores atuais para imagens ´ o padr˜o e aPGM. Este formato consiste de um arquivo ASCII que tem o seguinte formato: • a primeira linha cont´m um identificador “P2”; e • a segunda linha cont´m a largura e a altura de uma matriz, isto ´, o n´mero de e e u colunas e de linhas; • a terceira linha cont´m o valor do maior valor da matriz que cont´m a imagem e e propriamente dita; • o restante do arquivo cont´m uma matriz de elementos (bytes) que representam e um pixel da imagem em tons de cinza. A figura 10.57 mostra um exemplo de um arquivo que ´ uma imagem em PGM: ea primeira linha tem “P2”; a segunda linha cont´m a dimens˜o da matriz (10 × 11, e aobserve que por defini¸˜o o n´mero de colunas vem antes); a terceira linha cont´m o ca u emaior elemento (40) da matriz que constitui o restante do arquivo. Vamos mostrar uma maneira de se fazer um zoom na imagem. Existem v´rias at´cnicas, a nossa ser´ da seguinte forma: o zoom ser´ obtido pela m´dia de cada e a a equatro vizinhos, isto ´, o procedimento da figura 10.55. e A matriz que cont´m o zoom ser´ ent˜o impressa na sa´ padr˜o, mas no formato e a a ıda acorreto para poder ser visualizada com qualquer aplicativo padr˜o para imagens. Por a
    • 10.2. MATRIZES 193 P2 11 10 40 40 5 5 5 5 5 5 5 5 40 0 5 20 20 5 5 5 5 5 5 5 5 5 5 20 5 5 5 0 0 0 0 0 5 5 20 20 5 5 20 20 0 0 5 5 5 5 5 5 5 0 20 0 0 0 5 5 5 5 5 5 0 20 20 0 5 5 5 5 5 11 11 11 0 0 0 0 5 5 5 5 20 20 11 5 5 5 5 5 5 5 5 11 20 11 5 5 5 0 40 5 5 5 11 20 20 5 5 40 5 Figura 10.57: Exemplo de imagem no formato PGM.isto n˜o podemos esquecer de, na sa´ padr˜o, acrescentar o cabe¸alho do formato a ıda a cPGM, isto ´, uma linha contendo “P2”, outra contendo n´mero de colunas e de linhas e ue o valor do maior pixel. Notem que o procedimento para se achar o maior pode ser facilmente adaptadodo programa da figura 10.46, inclusive para se retornar um valor do tipo byte e n˜oado tipo real. Interessante observar que este zoom pode ser de v´rios n´ a ıveis, bastando para istoadaptar-se o procedimento da m´dia no que gera as submatrizes. Mas isto fica como eexerc´ ıcio. O programa para o zoom est´ mostrado na figura 10.58. aprogram faz zoom ;var imagem, zoom: matriz ; lin , col , lin z , col z : integer ;begin ler (imagem, lin , col ) ; media dos 4 vizinhos (imagem, lin , col , zoom, lin z , col z ) ; writeln (’P2’) ; writeln ( col z ,’ ’ , lin z ) ; writeln (achamaior (zoom, lin z , col z ) ) ; imprimir (zomm, lin z , col z ) ;end; Figura 10.58: Programa que le imagem PGM e gera imagem com zoom.
    • 194 CAP´ ITULO 10. ESTRUTURAS DE DADOS10.2.6 Exerc´ ıcios 1. Dada uma matriz real A com m linhas e n colunas e um vetor real V com n elementos, determinar o produto de A por V . 2. Um vetor real X com n elementos ´ apresentado como resultado de um sistema e de equa¸oes lineares Ax = B cujos coeficientes s˜o representados em uma matriz c˜ a real A(m×n) e os lados direitos das equa¸˜es em um vetor real B de m elementos. co Verificar se o vetor X ´ realmente solu¸ao do sistema dado. e c˜ 3. Dizemos que uma matriz inteira A(n × n) ´ uma matriz de permuta¸ao se em e c˜ cada linha e em cada coluna houver n − 1 elementos nulos e um unico elemento ´ igual a 1. Dada uma matriz inteira A(n × n) verificar se A ´ de permuta¸ao. e c˜ Exemplos: 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 1 ´ de permuta¸ao, enquanto que esta outra n˜o ´: e c˜ a e 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 2 4. Dada uma matriz A(n × m) imprimir o n´mero de linhas e o n´mero de colunas u u nulas da matriz. Exemplo: a matriz abaixo tem duas linhas e uma coluna nulas. 0 0 0 0 1 0 2 2 4 0 5 6 0 0 0 0 5. Dizemos que uma matriz quadrada inteira ´ um quadrado m´gico se a soma dos e a elementos de cada linha, a soma dos elementos de cada coluna e a soma dos elementos das diagonais principal e secund´ria s˜o todos iguais. Exemplo: a a 8 0 7 4 5 6 3 10 2 ´ um quadrado m´gico pois 8+0+7 = 4+5+6 = 3+10+2 = 8+4+3 = 0+5+10 e a = 7+6+2 = 8+5+2 = 3+5+7 = 15.
    • 10.2. MATRIZES 195 (a) Dada uma matriz quadrada A(n×m), verificar se A ´ um quadrado m´gico. e a (b) Informe quantas s˜o e quais s˜o as submatrizes n˜o triviais (isto ´, n˜o a a a e a pode ser a matriz constitu´ por apenas um elemento, uma linha e uma ıda coluna) que definem quadrados m´gicos. Por exemplo, a matriz do exemplo a acima tem 4 submatrizes de tamanho 2 × 2, duas submatrizes de tamanho 2 × 3, etc, e uma unica submatriz de dimens˜o 3 × 3; ´ a • Armazene de alguma maneira as informa¸˜es necess´rias sobre a loca- co a liza¸ao precisa de cada uma das submatrizes n˜o triviais que definem c˜ a quadrados m´gicos; a • Imprima a qualquer tempo algum quadrado m´gico armazenado; a • Dado uma dimens˜o qualquer, digamos N , imprima todas os quadra- a dos m´gicos de dimens˜o N contidos na matriz original. a a 6. Implemente o quadrado “quase magico”. Um quadrado quase magico ´ aquele e em que as somas das linhas e a somas das colunas resultam em um mesmo valor, mas a soma dos elementos das diagonais n˜o. O programa deve pedir a a dimens˜o do quadrado a ser impresso, que deve ser um n´mero ´ a u ımpar entre 1 e 99. 7. Um jogo de palavras cruzadas pode ser representado por uma matriz A(n × m) onde cada posi¸ao da matriz corresonde a um quadrado do jogo, sendo c˜ que 0 indica um quadrado em branco e -1 indica um quadrado preto. Colocar as numera¸˜es de in´ co ıcio de palavras horizontais e/ou verticais nos quadrados correspondentes (substituindo os zeros), considerando que uma palavra deve ter pelo menos duas letras. Exemplo: Dada a matriz: 0 -1 0 -1 -1 0 -1 0 0 0 0 0 -1 0 0 0 0 0 -1 -1 0 0 -1 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 -1 -1 A sa´ deveria ser: ıda 1 -1 2 -1 -1 3 -1 4 5 6 0 0 -1 7 0 0 8 0 -1 -1 9 0 -1 0 -1 10 0 11 0 -1 12 0 13 0 -1 14 0 0 -1 -1 8. Uma matriz D(8 × 8) pode representar a posi¸˜o atual de um jogo de damas, ca sendo que 0 indica uma casa vazia, 1 indica uma casa ocupada por uma pe¸a c branca e -1 indica uma casa ocupada por uma pe¸a preta. Supondo que as pe¸as c c pretas est˜o se movendo no sentido crescente das linhas da matriz D, determinar a as posi¸˜es das pe¸as pretas que: co c
    • 196 CAP´ ITULO 10. ESTRUTURAS DE DADOS • podem tomar pe¸as brancas; c • podem mover-se sem tomar pe¸as brancas; c • n˜o podem se mover. a e a ´ 9. Deseja-se atualizar as contas correntes dos clientes de uma agˆncia banc´ria. E dado o cadastro de N clientes contendo para cada cliente o n´mero de sua conta u e seu saldo. O cadastro est´ ordenado pelo n´mero da conta. Em seguida ´ a u e dado o n´mero de opera¸˜es realizadas no dia, e, para cada opera¸ao, o n´mero u co c˜ u da conta, uma letra C ou D indicando se a opera¸ao ´ de cr´dito ou d´bido, e o c˜ e e e valor da opera¸ao. Emitir o cadastro de clientes atualizado. Pode ser modelado c˜ como uma matriz N × 2. 10. Reordenar a matriz do exerc´ anterior por ordem de saldo, do maior para o ıcio menor. 11. Os elementos M [i, j] de uma matriz M (n × n) representam os custos de trans- porte da cidade i para a cidade j. Dados n itiner´rios lidos do teclado, cada um a com k cidades, calcular o custo total para cada itiner´rio. Exemplo: a 4 1 2 3 5 2 1 400 2 1 3 8 7 1 2 5 O custo do itiner´rio 1 4 2 4 4 3 2 1 ´: M[1,4] + M[4,2] + M[2,4] + M[4,4] + a e M[4,3] + M[3,2] + M[2,1] = 3 + 1 + 400 + 5 + 2 + 1 + 5 = 417. 12. Considere n cidades numeradas de 1 a n que est˜o interligadas por uma s´rie a e de estradas de m˜o unica. As liga¸˜es entre as cidades s˜o representadas pelos a ´ co a elementos de uma matriz quadrada L(n × n) cujos elementos L[i, j] assumem o valor 0 ou 1 conforme exista ou n˜o estrada direta que saia da cidade i e chegue a na cidade j. Assim, os elementos da i-´sima linha indicam as estradas que saem e da cidade i e os elementos da j-´sima coluna indicam as estradas que chegam a e ` cidade j. Por conven¸˜o, L[i, i] = 1. A figura abaixo ilustra um exemplo para ca n = 4. A B C D A 1 1 1 0 B 0 1 1 0 C 1 0 1 1 D 0 0 1 1 Por exemplo, existe um caminho direto de A para B mas n˜o de A para D. a (a) Dado k, determinar quantas estradas saem e quantas chegam a cidade k. `
    • 10.2. MATRIZES 197 (b) A qual das cidades chega o maior n´mero de estradas? u (c) Dado k, verificar se todas as liga¸˜es diretas entre a cidade k e outras s˜o co a de m˜o dupla; a (d) Relacionar as cidades que possuem sa´ ıdas diretas para a cidade k; (e) Relacionar, se existirem: • As cidades isoladas, isto ´, as que n˜o tˆm liga¸ao com nenhuma outra; e a e c˜ • As cidades das quais n˜o h´ sa´ a a ıda, apesar de haver entrada; • As cidades das quais h´ sa´ sem haver entrada; a ıda (f) Dada uma sequˆncia de m inteiros cujos valores est˜o entre 1 e n, verificar e a se ´ poss´ realizar o roteiro correspondente. No exemplo dado, o roteiro e ıvel representado pela sequˆncia (m = 5) 3 4 3 2 1 ´ imposs´ e e ıvel; (g) Dados k e p, determinar se ´ poss´ ir da cidade k at´ a cidade p pelas e ıvel e estradas existentes. Vocˆ consegue encontrar o menor caminho entre as e duas cidades? (h) Dado k, dterminar se ´ poss´ e ıvel, partindo de k, passar por todas as outras cidades apenas uma vez e retornar a k. 13. Uma matriz transposta M T ´ o resultado da troca de linhas por colunas em e uma determinad a matriz M . Escreva um programa que leia duas matrizes (A e B), e testa se B = A + AT . 14. Fazer procedimentos que recebam trˆs parˆmetros: uma matriz e dois inteiros e a representando as dimens˜es da matriz. Retornar: o (a) a transposta de matriz; (b) a soma das duas matrizes; (c) a multiplica¸˜o das duas matrizes. ca 15. Fa¸a um programa que leia duas matrizes A e B quaisquer e imprima a trans- c posta de B se a transposta de A for igual a B. 16. Fazer uma fun¸˜o que receba como parˆmetros: dois vetores de reais e dois ca a inteiros representando as dimens˜es dos vetores. Retornar o produto escalar o dos dois vetores (real). Refazer a multiplica¸ao de matrizes usando esta fun¸ao. c˜ c˜ 17. Fa¸a um programa que, dadas N datas em uma matriz DATASN ×3 , onde a c primeira coluna corresponde ao dia, a segunda ao mˆs e a terceira ao ano, e coloque essas datas em ordem cronol´gica crescente. Por exemplo: o     5 1 1996 16 3 1951   25 6 1965     25 6 1965   DAT AS =   16 3 1951  DAT AS =    5 11 1965    15 1 1996   5 1 1996  5 11 1965 15 1 1996
    • 198 CAP´ ITULO 10. ESTRUTURAS DE DADOS 18. Verifique se a matriz A ´ sim´trica, isto ´, se A[i, j] = A[j, i], ∀i, j ≤ M . Fa¸a e e e c uma fun¸ao que retorne 1 em caso afirmativo, 0 caso contr´rio. c˜ a 19. Uma matriz B ´ dita inversa da matriz A quando A × B = I, onde I ´ a matriz e e identidade e × ´ a opera¸˜o de multiplica¸ao de matrizes. A matriz identidade e ca c˜ ´ a matriz quadrada onde os elementos da diagonal principal s˜o 1 e os demais e a 0 (I[i, j] = 1 se i = j e I[i, j] = 0 se i = j). Escreva um programa em Pascal que leia duas matrizes e testa se a segunda ´ a inversa da primeira. e 20. Considere uma matriz M de tamanho N × M utilizada para representar gotas de agua (caractere G) em uma janela. A cada unidade de tempo T , as gotas ´ descem uma posi¸˜o na matriz, at´ que atinjam a base da janela e desapare¸am. ca e c Considere que a chuva parou no momento em que seu programa iniciou. Exemplo: Passo T=0 Passo T=1 Passo T=4 ----------------- ----------------- ----------------- | G G | | | | | | G | | G G | | | | | | G | | | | G G | | | ... | | ... | | | G G | | G G | | | | | | G | | | | | | | +++++++++++++++++ +++++++++++++++++ +++++++++++++++++ Fa¸a um programa em que: c (a) Leia as coordenadas iniciais das gotas de agua na matriz. O canto superior ´ esquerdo da matriz (desconsiderando as bordas) possui coordenada (1, 1). A coordenada (0, 0) indica o t´rmino da leitura. Coordenadas inv´lidas e a devem ser desconsideradas. Exemplo de entrada para a matriz acima (em T = 0): 1 4 1 13 4 6 2 8 100 98 4 10 0 0 Note que a entrada (100, 98) deve ser descartada pois ´ inv´lida para a e a matriz do exemplo. (b) Imprima, a cada unidade de tempo T , o conte´do da matriz M , atualizando u a posi¸˜o das gotas G at´ que n˜o reste nenhuma gota na janela. ca e a
    • 10.2. MATRIZES 199 21. Modifique seu programa da quest˜o anterior de modo que as gotas que est˜o a a inicialmente na primeira linha da janela des¸am com o dobro da velocidade das c outras gotas. Ou seja, as gotas que iniciam na primeira linha descem duas linhas na matriz a cada instante T . As gotas mais r´pidas podem encontrar gotas mais a lentas pelo caminho, neste caso a gota mais lenta desaparece ficando somente a mais r´pida. a 22. Modifique novamente o programa da quest˜o anterior considerando que, desta a vez, a cada unidade de tempo T , N G novas gotas s˜o inseridas na matriz. Al´m a e disso, as gotas descem na matriz at´ que atinjam a base da janela e desapare¸am. e c Inicialmente n˜o h´ gotas na janela, pois a chuva come¸a quando T = 1. a a c Exemplo: Passo T=1 Passo T=2 Passo T=1000 ----------------- ----------------- ----------------- | G G | | G | | | | G | | G G | | G | | | | G | | | | G G | | | ... | G | | | | G G | | G G | | | | | | G | | | | G | | | +++++++++++++++++ +++++++++++++++++ +++++++++++++++++ Fa¸a um programa em que: c (a) Leia o n´mero de linhas (L) e o n´mero de colunas (C) da matriz M , u u a quantidade de novas gotas a serem criadas a cada itera¸ao (N G), e o c˜ n´mero de itera¸oes (T M AX) do programa. u c˜ Exemplo de entrada para a matriz acima: 7 15 5 1000 (b) A cada unidade de tempo T , insira N G novas gotas na matriz. A posi¸ao c˜ de uma nova gota ´ dada por um procedimento cujo prot´tipo ´: e o e Procedure coordenada_nova_gota(L,C:integer; VAR x,y:integer); Este procedimento recebe quatro parˆmetros: os dois primeiros indicam o a n´mero de linhas e colunas da matriz M (L, C). Os dois ultimos retornam u ´ as coordenadas (x, y) da nova gota na matriz. (c) A cada unidade de tempo T , imprima o conte´do da matriz M , atualizando u a posi¸˜o das gotas G seguindo os seguintes crit´rios: ca e i. Quando uma gota cai sobre outra, forme-se uma gota “dupla”, ou seja, ela desce duas posi¸˜es a cada instante T . Caso uma nova gota co caia sobre uma gota “dupla”, surge uma gota “tripla”, que desce trˆs e posi¸oes a cada instante T , e assim por diante. c˜
    • 200 CAP´ ITULO 10. ESTRUTURAS DE DADOS ii. As gotas mais r´pidas podem encontrar gotas mais lentas pelo cami- a nho, neste caso a velocidade delas ´ somada. e 23. Considere o tipo PGM para imagens como definido na se¸ao 10.2.5. Fa¸a um c˜ c programa que leia da entrada padr˜o (teclado) duas imagens no formato PGM: a imagem original (imgO) e a imagem do padr˜o (imgP ). a Em seguida, o programa deve procurar se a imagem imgP est´ contida na ima- a gem imgO e imprimir na tela as coordenadas (coluna, linha) do canto superior esquerdo de cada ocorrˆncia da imagem imgP encontrada na imagem imgO. e Observa¸˜es: co • A imagem imgP pode aparecer mais de uma vez na imagem imgO; • Na imagem imgP , pontos com o valor −1 devem ser ignorados, isto ´, e represent am pontos transparentes da imagem e n˜o devem ser comparados a com a imagem imgO. • Estruture seu c´digo. A solu¸ao parcial ou a indica¸ao de chamadas a o c˜ c˜ fun¸oes n˜o implementadas ser˜o consideradas. c˜ a a Exemplo: • Imagem original: P2 11 10 40 40 5 5 5 5 5 5 5 5 40 0 5 20 20 5 5 5 5 5 5 5 5 5 5 20 5 5 5 0 0 0 0 0 5 5 20 20 5 5 20 20 0 0 5 5 5 5 5 5 5 0 20 0 0 0 5 5 5 5 5 5 0 20 20 0 5 5 5 5 5 11 11 11 0 0 0 0 5 5 5 5 20 20 11 5 5 5 5 5 5 5 5 11 20 11 5 5 5 0 40 5 5 5 11 20 20 5 5 40 5 • Imagem do padr˜o: a P2 3 3 20 20 20 -1 -1 20 -1 -1 20 20 • Resultado do Programa:
    • 10.2. MATRIZES 201 2 2 7 4 5 8 24. Modifique o programa anterior de forma que, ao inv´s de imprimir as coorde- e nadas, seja impressa uma nova imagem, que consiste de uma c´pia da imagem o original imgO na qual as ocorrˆncias da imagem imgP estejam circunscritas e por uma borda de um ponto de largura, com o valor m´ximo da imagem imgO a a (3 linha do arquivo PGM). Vocˆ n˜o precisa se preocupar com poss´ e a ıveis sobre- posi¸oes das bordas. c˜ Exemplo da nova sa´ para a entrada original: ıda • Imagem resultante: P2 11 10 40 40 40 40 40 40 5 5 5 5 40 0 40 20 20 5 40 5 5 5 5 5 5 40 5 20 5 40 40 40 40 40 40 0 40 5 20 20 40 40 20 20 0 40 5 40 40 40 40 40 40 0 20 0 40 0 5 5 5 5 5 40 0 20 20 40 5 5 5 5 40 40 40 40 40 40 40 0 5 5 5 40 20 20 11 40 5 5 5 5 5 5 40 11 20 11 40 5 5 0 40 5 5 40 11 20 20 40 5 40 5 25. Uma matriz ´ chamada de esparsa quando possui uma grande quantidade de e elementos que valem zero. Por exemplo, a matriz de ordem 5 × 4 seguinte ´ e esparsa, pois cont´m apenas 4 elementos n˜o nulos. e a 1 2 3 4 1 0 17 0 0 2 0 0 0 0 3 13 0 -12 0 4 0 0 25 0 5 0 0 0 0 Obviamente, a representa¸ao computacional padr˜o para matrizes ´ ineficiente c˜ a e em termos de mem´ria, pois gasta-se um espa¸o in´til para se representar muitos o c u elementos nulos. Nesta quest˜o, vamos usar uma representa¸ao alternativa que vai permitir uma a c˜ boa economia de mem´ria. o
    • 202 CAP´ ITULO 10. ESTRUTURAS DE DADOS A proposta ´ representar apenas os elementos n˜o nulos. Para isto usaremos trˆs e a e vetores, dois deles (L e C) para guardar as coordenadas dos elementos n˜o nulos a e o terceiro (D) para guardar os valores dos elementos daquelas coordenadas. Tamb´m usaremos trˆs vari´veis para representar o n´mero de linhas e colunas e e a u da matriz completa e o n´mero de elementos n˜o nulos da matriz. u a Considere as seguintes defini¸˜es de tipos: co C NT OS M X = 6; A (∗ um valor bem menor que 5 x 4, dimensao da matriz ∗) TP YE vetor coordenadas = array [ 1 . .M X] of integer ; (∗ coordenadas A ∗) vetor elementos = array [ 1 . .M X] of real ; A (∗ dados ∗) VR A L, C: vetor coordenadas ; (∗ L: linhas , C: colunas ∗) D: vetor elementos ; (∗ D: dados ∗) N lin , N col : integer ; (∗ para armazenar as dimensoes da matriz ∗) N elementos : integer (∗ numero de elementos nao nulos ∗) Defini¸˜o 1 Um elemento M[i,j] da matriz completa pode ser obtido da repre- ca senta¸˜o compactada: ca • se existe um k tal que L[k] = i e C[k] = j, ent˜o M[i,j] = D[k]; a • caso contr´rio, M[i,j] = 0. a A matriz do exemplo anterior pode ent˜o ser assim representada: a N_elementos:= 4; N_lin:= 5; N_col:= 4; 1 2 3 4 5 6 L 1 3 3 4 C 2 1 3 3 D 17 13 -12 25 (a) Fazer um procedimento que leia da entrada padr˜o: a • dois inteiros, representando as dimens˜es da matriz (linha, coluna); o • trincas de elementos l, c, d, onde l e c s˜o inteiros e d ´ real, represen- a e tando respectivamente a linha, a coluna e o valor de um elemento n˜o a nulo da matriz. A leitura termina quando for lido uma trinca 0, 0, 0. Para cada trinca, devem ser criados os trˆs vetores que representam a e matriz conforme descrito acima. Veja o exemplo de entrada de dados, abaixo. Exemplo para a entrada de dados:
    • 10.2. MATRIZES 203 5 4 1 2 17 3 1 13 3 3 -12 4 3 25 0 0 0 (b) Fazer uma fun¸ao que, dada uma coordenada (l, c), respectivamente para c˜ uma linha e coluna, retorne o valor de elemento M[l,c], conforme a defini¸ao c˜ 1. (c) Fazer um procedimento que, dadas duas matrizes no formato compactado descrito acima, obtenha uma terceira matriz compactada que ´ a soma das e duas primeiras. (d) Fazer um procedimento que, dada uma matriz no formato compactado, imprima na tela uma matriz no formato padr˜o, contendo os zeros. a 26. Declare uma matriz M × N de caracteres do tipo char. Implemente quatro fun¸oes que, dados como parˆmetros a matriz, uma palavra do tipo string e um c˜ a par de coordenadas na matriz, isto ´, dois inteiros representando uma linha e e uma coluna, descubram se, na matriz, a palavra ocorre iniciando na posi¸˜oca indicada pelas coordenadas. A primeira fun¸˜o procura na horizontal, da es- ca querda para direita; a segunda fun¸ao procura na horizontal, da direita para c˜ esquerda; a terceira fun¸˜o procura na vertical, da cima para baixo; a quarta ca fun¸ao procura na vertical, da baixo para cima. c˜ 27. Os incas construiam pirˆmides de base quadrada em que a unica forma de se a ´ atingir o topo era seguir em espiral pela borda, que acabava formando uma es- cada em espiral. Escreva um programa que leia do teclado uma matriz quadrada N × N de n´meros inteiros e verifica se a matriz ´ inca; ou seja, se partindo u e do canto superior esquerdo da matriz, no sentido hor´rio, em espiral, a posi¸ao a c˜ seguinte na ordem ´ o inteiro consecutivo da posi¸ao anterior. Por exemplo, as e c˜ matrizes abaixo s˜o incas: a 1 2 3 4 1 2 3 4 5 12 13 14 5 16 17 18 19 6 11 16 15 6 15 24 25 20 7 10 9 8 7 14 23 22 21 8 13 12 11 10 9 O programa deve ler do teclado a dimens˜o da matriz (um inteiro N , 1 ≤ a N ≤ 100) e em cada uma das pr´ximas N linhas, os inteiros correspondentes `s o a entradas da matriz naquela linha. A sa´ do programa deve ser “A matriz eh ıda inca” ou “A matriz nao eh inca”.
    • 204 CAP´ ITULO 10. ESTRUTURAS DE DADOS 28. Escreva um programa em Pascal que leia do teclado uma matriz A (N × M ) de inteiros e imprima uma segunda matriz B de mesma dimens˜es em que cada o elemento B[i, j] seja constitu´ pela soma de todos os 8 elementos vizinhos do ıdo elemento A[i, j], excetuando-se o pr´prio A[i, j]. o 29. Nesta quest˜o vocˆ ter´ que providenciar liga¸˜es par-a-par entre diversos pontos a e a co distribu´ ıdos ao longo de uma rota qualquer. A entrada de dados consiste de um conjunto de pares (x, y), 1 ≤ x, y ≤ M AX, sendo que o ultimo par a ser lido ´ o ´ e (0,0), que n˜o deve ser processado, apenas indicando final da entrada de dados. a Para cada par (x, y) dado como entrada, vocˆ deve providenciar uma conex˜o e a f´ ısica entre eles. As linhas de uma matriz podem representar a “altura” das linhas de conex˜o, enquanto que as colunas da matriz podem representar os a pontos (x, y) sendo conectados. Um s´ ımbolo de “+” pode ser usado para se representar altera¸˜o na dire¸˜o de uma conex˜o. O s´ ca ca a ımbolo “|” pode ser usado para representar um trecho de conex˜o na vertical. Finalmente o s´ a ımbolo “-” pode ser usado para se representar um trecho de conex˜o na dire¸ao horizontal. a c˜ Quando um cruzamento de linhas for inevit´vel, deve-se usar o s´ a ımbolo “x” para represent´-lo. Considere que n˜o existem trechos de conex˜es na diagonal. a a o Por exemplo, suponha que a entrada ´ dada pelos seguintes pares: e 3 5 2 9 0 0 Uma poss´ sa´ para seu programa seria a impress˜o da seguinte matriz: ıvel ıda a 4 3 2 +-------------+ 1 | +---+ | 1 2 3 4 5 6 7 8 9 Outra poss´ matriz solu¸ao para este problema seria esta: ıvel c˜ 4 3 2 +---+ 1 +-x---x-------+ 1 2 3 4 5 6 7 8 9 Note que nesta ultima vers˜o foi preciso inserir dois cruzamentos. ´ a Ainda como exemplo, se o par (6,8) tamb´m fosse dado como entrada no exemplo e anterior, a sa´ do programa poderia ser assim exibida: ıda
    • 10.2. MATRIZES 205 4 3 +---+ 2 +-------x---x-+ 1 | +---+ | | | 1 2 3 4 5 6 7 8 9 Vocˆ deve implementar um programa em Pascal que seja capaz de ler uma e sequˆncia de pares terminada em (0, 0) (como no exemplo acima) e que imprima e o desenho das conex˜es como sa´ o ıda, tamb´m conforme o diagrama acima. e 30. Modifique o programa anterior com o objetivo de minizar o n´mero de cruza- u mentos da matriz gerada como solu¸ao do problema anterior. Assim, a matriz c˜ ideal para ser dada como resposta do ultimo exemplo seria a seguinte: ´ 4 3 2 +-------------+ 1 | +---+ +---+ | 1 2 3 4 5 6 7 8 9 31. Considere o seguinte programa: program prova final ; C N TM X O S A =100; T P matriz = array [ 1 . .MAX 1 . .M X] of integer ; YE , A V R n lin , n col : integer ; (∗ dimensoes da matriz ∗) A m: matriz ; (∗ matriz ∗) (∗ espaco reservado para os procedimentos ∗) begin read ( n lin , n col ) ; le matriz (m, n lin , n col ) ; acha maior sequencia (m, n lin , n col , l i n i , c ini , l fim , c fim ) ; writeln (’A maior sequencia de numeros repetidos na matriz ’) ; writeln (’inicia na coordenada ’ , l i n i , c ini ) ; writeln (’ e termina na coordenada ’ , l fim , c fim ) ; end. Implemente os procedimentos indicados para que o programa leia uma matriz de inteiros e imprima as coordenadas de in´ ıcio e t´rmino da maior sequˆncia e e de n´meros repetidos da matriz. Esta sequˆncia pode estar tanto nas linhas u e quanto nas colunas. No caso de existir mais de uma sequˆncia repetida de e mesmo tamanho, vocˆ pode imprimir as coordenadas de qualquer uma delas, e desde que imprima as de uma s´. o
    • 206 CAP´ ITULO 10. ESTRUTURAS DE DADOS Exemplo 2: Exemplo 1: Entrada: Sa´da ı Entrada: Sa´da ı 4 5 2 2 4 3 1 2 1 2 3 1 2 2 4 1 2 3 3 2 1 2 2 2 3 2 2 1 2 3 4 5 6 3 2 5 8 7 6 4 2 32. Fa¸a um programa para: c • ler uma sequˆncia de polinˆmios Pi (x) = ai0 + ai1 x + ai2 x2 + ... + ain xn , i = e o 1, 2, ..., k; • A leitura deve considerar que cada linha de entrada cont´m um polinˆmio e o Pi . A primeira informa¸ao ´ o seu respectivo grau (ni ). As outras in- c˜ e forma¸oes s˜o os ni coeficientes (ai0 , ai1 , ..., ain ); c˜ a Exemplo: P (x) = 8.1 − 3.4x + x2 =⇒ 2 8.1 -3.4 1.0 • A sequˆncia de polinˆmios se encerra quando for fornecido um polinˆmio e o o de grau zero; • Ap´s a leitura de todos os polinˆmios, o programa deve ler uma sequˆncia o o e de n´meros reais x. Para cada n´mero real lido, o programa deve imprimir u u o resultado de Pi (x), para todos os polinˆmios lidos anteriormente (i = o 1, 2, ..., k); • A sequˆncia de n´meros reais se encerra quando for lido o n´mero 0.0, para e u u o qual n˜o se deve calcular os valores de Pi (x). a Exemplo: Entrada: 2 -1.0 0.0 1.0 3 1.0 2.0 0.0 -1.0 0 4.5 1.0 0.0 Sa´da: ı P_1(2.0) = 3.0 P_2(2.0) = -3.0 P_1(1.0) = 0.0 P_2(1.0) = 2.0 33. Fa¸a um programa para: c • ler um inteiro N e uma matriz quadrada de ordem N contendo apenas 0’s e 1’s.
    • 10.2. MATRIZES 207 • encontrar a maior submatriz quadrada da matriz de entrada que cont´m e apenas 1’s. • imprimir as coordenadas dos cantos superior esquerdo e inferior direito da submatriz encontrada no item anterior. Havendo mais de uma submatriz m´xima, imprimir as coordenadas de qualquer uma delas. a Exemplo: Considere a seguinte matriz quadrada de ordem 6: 1 2 3 4 5 6 1 0 1 0 1 1 1 2 0 1 1 1 1 0 3 0 1 1 1 0 1 4 1 1 1 1 0 1 5 0 0 1 0 1 0 6 0 1 0 1 0 1 A t´ ıtulo de ilustra¸ao, esta matriz tem: c˜ • 22 submatrizes quadradas de ordem 1 que cont´m apenas 1’s; e • 5 submatrizes quadradas de ordem 2 que cont´m apenas 1’s. Por exemplo, e para duas delas: uma ´ dada pelas coordenadas (1,4) e (2,5) e outra pelas e coordenadas (2,2) e (3,3); • 1 submatriz quadrada de ordem 3 que cont´m apenas 1’s, as coordenadas e s˜o (2,2) e (4,4). a Como a maior submatriz quadrada que cont´m apenas 1’s ´ a de ordem 3, ent˜o e e a a sa´ do programa deve imprimir, para este exemplo, as coordenadas (2,2) e ıda (4,4). 34. Escreva um programa que, dado um tabuleiro e uma lista de sub-partes retangu- lares do tabuleiro, retorna o n´mero de posi¸˜es que n˜o pertencem a nenhuma u co a sub-parte. Quando uma posi¸ao n˜o pertence a nenhuma sub-parte dizemos que c˜ a ela est´ perdida. a Entrada A entrada consiste de uma s´rie de conjuntos de teste. e Um conjunto de teste come¸a com uma linha com trˆs n´meros W , H e N , c e u indicando, respectivamente, a largura e a altura do tabuleiro e o n´mero de sub- u partes deste. Estes valores satisfazem as seguintes restri¸˜es: 1 ≤ W , H ≤ 500 co e 0 ≤ N ≤ 99.
    • 208 CAP´ ITULO 10. ESTRUTURAS DE DADOS Seguem N linhas, compostas de quatro inteiros X1 , Y1 , X2 e Y2 , tais que (X1 , Y1 ) e (X2 , Y2 ) s˜o as posi¸˜es de dois cantos opostos de uma sub-parte. Estes valores a co satisfazem as seguintes restri¸˜es: 1 ≤ X1 , X2 ≤ W e 1 ≤ Y1 , Y2 ≤ H. co O fim da entrada acontece quando W = H = N = 0. Esta ultima entrada n˜o ´ a deve ser considerada como um conjunto de teste. Sa´ ıda O programa deve imprimir um resultado por linha, seguindo o formato descrito no exemplo de sa´ ıda. Exemplo Entrada: 1 1 1 1 1 1 1 {fim do primeiro conjunto de testes} 2 2 2 1 1 1 2 1 1 2 1 {fim do segundo conjunto de testes } 493 182 3 349 148 363 146 241 123 443 147 303 124 293 17 {fim do terceiro conjunto de testes} 0 0 0 {fim do conjunto de testes} Sa´da ı N~o h´ posi¸~es perdidas. a a co Existe uma posi¸~o perdida. ca Existem 83470 posi¸~es perdidas. co
    • 10.3. REGISTROS 20910.3 RegistrosAt´ agora vimos, como estruturas de dados, apenas vetores e matrizes. Estas estru- eturas s˜o ditas homogˆneas, no sentido que as diversas posi¸˜es de mem´ria alocadas a e co os˜o sempre do mesmo tipo. a Para completarmos nosso estudo b´sico de algoritmos, resta ainda introduzir a ano¸ao de registros, que s˜o estruturas heterogˆnas, isto ´, pode-se alocar v´rias posi¸oes c˜ a e e a c˜de mem´ria cada uma delas de um tipo potencialmente diferente. o10.3.1 Introdu¸˜o aos registros caAssim como em um vetor ou em uma matriz, pode-se acessar diversas posi¸oes de c˜mem´ria com um unico nome da vari´vel, o que ´ diferente ´ que com um registro o ´ a e epodemos misturar diversos tipos diferentes. Por exemplo, suponhamos que seja necess´rio implementar um cadastro de um acliente em um banco. Normalmente, este cadastro cont´m: nome do cliente, telefone, eendere¸o, sexo, idade, RG e CPF. Usando-se um registro, podemos agrupar todos os cdados diferentes em uma s´ vari´vel. Por exemplo, em Pascal podemos declarar tal o avari´vel assim: avar r : record nome: string [ 5 0 ] ; fone : longint ; endereco : string ; sexo : char; idade , rg , cpf : integer ; end; Cada linguagem de programa¸˜o tem sua sintaxe pr´pria para a declara¸˜o e acesso ca o caaos dados. Nos vetores e matrizes, o acesso ´ feito usando-se o nome da vari´vel e um e a´ındice (ou um par no caso das matrizes). Para os registros, em Pascal, usa-se o nomeda vari´vel, um ponto, e o nome do campo, que ´ escolhido pelo programador. a e Por exemplo, ´ v´lido em Pascal a seguinte sequˆncia de comandos: e a er .nome:= ’Fulano de Tal’ ;r . fone:= 32145678;r . endereco:= ’Rua dos bobos, no 0’ ;r . sexo:= ’M’ ;r . idade:= 75;r . rg:= 92346539;r . cpf:= 11122233344; Tamb´m seria v´lido ler a partir do teclado da seguinte maneira: e aread ( r .nome) ;read ( r . fone) ;read ( r . endereco) ;read ( r . sexo) ;read ( r . idade) ;read ( r . rg) ;read ( r . cpf ) ;
    • 210 CAP´ ITULO 10. ESTRUTURAS DE DADOS Contudo, assim como se d´ para o tipo array, para se passar um parˆmetro de a aprocedimento ou fun¸ao em Pascal ´ necess´rio antes a declara¸˜o de um novo tipo, c˜ e a caque poderia ser assim:type cliente = record nome: string [ 5 0 ] ; fone : longint ; endereco : string ; sexo : char; idade : integer ; rg : longint ; cpf : qword; end;var r : cliente ; Na verdade a linguagem Pascal permite uma facilidade para se economizar algumadigita¸ao atrav´s do comando with. A figura 10.59 ilustra uma forma de se imprimir c˜ etodo o conte´do de um registro usando-se um procedimento. O comando with pode user usado para leitura ou atribui¸˜o tamb´m. ca eprocedure imprime reg ( r : cliente ) ;begin with r do begin writeln (nome) ; writeln (fone) ; writeln (endereco) ; writeln (sexo) ; writeln (idade) ; writeln (rg) ; writeln ( cpf ) ; end;end; Figura 10.59: Imprimindo registros.10.3.2 Vetores de registrosO leitor pode ter observado ou pensado: um registro n˜o faz um arquiv˜o. . . a a De fato, normalmente ´ mais comum ver os registros integrados a outras estrututas, etais como vetores, matrizes ou arquivos em disco11 Considerando ainda o exemplo do cliente do banco, ´ natural imaginar que o banco etem muitos clientes. Claro, se tiver um s´, melhor fechar as portas. Uma maneira oainda um pouco prec´ria de se manipular muitos clientes ´ usando a estrutura de a evetores em combina¸ao com a de registros. c˜ A t´ ıtulo de exemplo, consideremos ent˜o as seguintes defini¸˜es: a co 11 O tipo file est´ fora do escopo desta disciplina no primeiro semestre de 2009. a
    • 10.3. REGISTROS 211const M X 10000; A=type cliente = record nome: string [ 5 0 ] ; fone : longint ; endereco : string ; sexo : char; idade : integer ; rg : longint ; cpf : qword; end; bd = array [ 1 . .M X] of cliente ; Avar r : cliente ; v: bd; tam v: integer ; Isto ´, temos um vetor de tam v clientes! e Vamos imaginar que o banco ´ novo na pra¸a e que ´ preciso criar o banco de dados e c econtendo os clientes. Podemos usar o procedimento que ´ mostrado na figura 10.60. eprocedure le r cl ie nte (var r : cliente ) ;begin with r do begin readln (nome) ; readln (fone) ; readln (endereco) ; readln (sexo) ; readln (idade) ; readln (rg) ; readln ( cpf ) ; end;end;procedure carregar todos clientes (var v: bd; var tam v: integer) ;begin readln (tam v) ; for i:= 1 to tam v do le r cl ie nte (v[ i ] ) ;end; Figura 10.60: Lendo os clientes do banco. Os algoritmos para busca, ordena¸˜o e outros tipos de manipula¸˜o desta nova ca caestrutura devem levar em conta agora qual ´ o campo do registro que deve ser utilizado. ePor exemplo, se quisermos imprimir o telefone do cliente do banco cujo CPF seja1234567899, ent˜o ´ no campo r.cpf que devemos centrar aten¸ao durante a busca, a e c˜mas na hora de imprimir, deve-se exibir o campo r.fone. Vejamos um exemplo nafigura 10.61.
    • 212 CAP´ ITULO 10. ESTRUTURAS DE DADOSprocedure busca telefone (var v: bd; tam v: integer ; nome procurado : string) ;var i : integer ;begin i:= 1; while ( i <= tam v) and (v[ i ] .nome < nome procurado) do > i:= i + 1; i f i <= tam v then writeln (’O telefone do cliente ’ ,v[ i ] .nome,’ eh o ’ ,v[ i ] . fone) else writeln (’Cliente nao localizado na base.’) ;end; Figura 10.61: Imprime o telefone do cliente que tem um certo CPF. O campo do registro de interesse para um algoritmo normalmente ´ denominado echave. Por exemplo, vamos tentar ordenar o banco de dados. Por qual chave devemosfazer isto, j´ que temos uma estrutura contendo 7 campos diferentes? Vamos conven- acionar que a ordena¸ao se dar´ pelo CPF do cliente. O algoritmo de ordena¸ao pode c˜ a c˜ser, por exemplo, o m´todo da sele¸ao. Mas deve-se observar que, durante as trocas, e c˜todo o registro deve ser trocado, sob pena de misturarmos os dados dos clientes! Afigura 10.62 ilustra tal situa¸ao. c˜ O ideal ´ que se implemente um procedimento para as trocas, assim o c´digo e ofica encapsulado e ´ mais f´cil dar manuten¸˜o. Observar tamb´m que se a chave e a ca eda ordena¸ao for outra, por exemplo, o nome do cliente, deve-se implementar outra c˜procedure, mudando-se o c´digo na linha da compara¸ao de v[i].cpf para v[i].nome. o c˜10.3.3 Registros com vetoresNa sess˜o anterior vimos como implementar um vetor cujos campos s˜o registros. a aNesta sess˜o vamos ver como implementar um registro que tem, com um dos campos, aum vetor. Para isto, vamos considerar as seguintes defini¸oes: c˜const M X 10000; A=type vetor = array [ 1 . .M X] of real ; A tipo vetor = record tam: integer ; dados : vetor ; end;var v: tipo vetor ; A ideia ´ encapsular o tamanho do vetor junto com o pr´prio vetor. Isto facilita na e ohora de passar parˆmetros, entre outras coisas. Em uma figura de linguagem, ´ como a ese o vetor “soubesse” seu tamanho, sem precisar passar um parˆmetro indicando isto. a O conceito ´ simples, vamos ver pode ser feita a leitura de um vetor nesta nova eestrutuda de dados. Isto ´ apresentado na figura 10.63. e ´ importante observar o correto uso dos s´ E ımbolos de ponto (.) e dos colchetes,eles tˆm que estar no lugar certo. Uma vez que, no exemplo acima, v ´ uma vari´vel e e a
    • 10.3. REGISTROS 213do tipo registro, ela deve receber inicialmente um ponto para se poder acessar umdos dois campos. Se quisermos acessar o tamanho, ent˜o a constru¸ao ´ v.tam. Se a c˜ equisermos acessar o vetor de reais, ent˜o a constru¸˜o correta ´ v.dados. Ocorre que a ca ev.dados ´ um vetor, logo, deve-se indexar com algum inteiro, por isto a constru¸ao e c˜final correta ´ v.dados[i]. e10.3.4 Observa¸˜es importantes coO estudante ´ encorajado a praticar v´rios exerc´ e a ıcios at´ compreender bem estas eno¸oes. Uma vez compreendido, n˜o haver´ dificuldades em prosseguir no estudo c˜ a ade algoritmos e estruturas de dados. A maior parte das estruturas sofisticadas queser˜o estudadas ao longo dos pr´ximos anos de estudo s˜o variantes das constru¸oes a o a c˜estudadas nesta se¸˜o. ca Nas ultimas aulas desta disciplina abordaremos problemas que podem ser resol- ´vidos de forma elegante usando-se uma combina¸˜o de vetores, registros, matrizes e catamb´m, obviamente, os tipos b´sicos. Afinal, como estamos querendo mostrar desde e ao in´ do nosso estudo, a arte de se programar um computador ´ simplesmente encon- ıcio etrar as melhores estruturas de dados que, bem exploradas pelos algoritmos corretos,levam a programas eficientes e elegantes.
    • 214 CAP´ ITULO 10. ESTRUTURAS DE DADOSprocedure ordena por cpf (var v: bd; n: integer) ;var i , j , pos menor : integer ; aux: cliente ;begin for i:= 1 to n−1 do begin (∗ acha o menor elemento a partir de i ∗) pos menor:= i ; for j:= i+1 to n do i f v[ j ] . cpf < v[ pos menor ] . cpf then pos menor:= j ; (∗ troca ∗) with aux do begin nome:= v[ pos menos ] .nome; fone:= v[ pos menor ] . fone ; endereco:= v[ pos menor ] . endereco ; sexo:= v[ pos menor ] . sexo ; idade:= v[ pos menor ] . idade ; rg:= v[ pos menor ] . rg ; cpf:= v[ pos menor ] . cpf ; end; with v[ pos menor ] do begin nome:= v[ i ] .nome; fone:= v[ i ] . fone ; endereco:= v[ i ] . endereco ; sexo:= v[ i ] . sexo ; idade:= v[ i ] . idade ; rg:= v[ i ] . rg ; cpf:= v[ i ] . cpf ; end; with v[ i ] do begin nome:= aux.nome; fone:= aux.nome; endereco:= aux.nome; sexo:= aux.nome; idade:= aux.nome; rg:= aux.nome; cpf:= aux. cpf ; end; Figura 10.62: Ordena pelo CPF.
    • 10.3. REGISTROS 215procedure ler vetor (var v: tipo vetor ) ;var i : integer ;begin readln (v.tam) ; for i:= 1 to v.tam do readln (v. dados [ i ] )end; Figura 10.63: Lendo vetores implementados em registros.
    • 216 CAP´ ITULO 10. ESTRUTURAS DE DADOS10.3.5 Exerc´ ıcios 1. Latitude e longitude s˜o especificados em graus, (o ), minutos (’), segundos (”), a e dire¸˜o (N, S, L, O). Por exemplo, a cidade A fica na latitude 22o 17’34”N e ca longitude 53o 41’9”O. Defina um tipo em Pascal cujo nome seja localizacao, e que seja constituido de longitude e latitude, ambas do tipo coordenadas. Para isto voce ter´ que a definir o tipo coordenadas como sendo constituido de grau, minutos, segundos e direcao. 2. Declare um vetor onde cada elemento ´ um registro com os campos: nome, e DDD, telefone, CPF, Idade. 3. Considerando o vetor n˜o ordenado, encontrar e imprimir o nome do cliente a mais jovem. Fa¸a um procedimento para isto c 4. Ordenar por ordem de nome. Fa¸a um procedimento para isto. c 5. Dado um CPF, localizar se o nome est´ no vetor e imprimir todos os dados. a Fa¸a um procedimento para isto. c 6. Fa¸a um procedimento que receba por valor parˆmetros para nome, DDD, tele- c a fone, CPF, Idade e o insira no vetor (que j´ est´ ordenado) em ordem alfab´tica. a a e N˜o vale usar um vetor auxiliar. Retornar por referˆncia o vetor alterado a e 7. Considere o arquivo de uma empresa (chamado de “func.dat” – um arquivo de registros) contendo para cada funcion´rio seu n´mero, seu n´ salarial e seu de- a u ıvel partamento. Como a administra¸˜o desta empresa ´ feita a n´ departamental ca e ıvel ´ importante que no arquivo os funcion´rios de cada um dos departamentos este- e a jam relacionados entre si e ordenados sequencialmente pelo seu n´mero. Como u s˜o frequentes as mudan¸as interdepartamentais no quadro de funcion´rios, n˜o a c a a ´ conveniente reestruturar o arquivo a cada uma destas mudan¸as. Desta ma- e c neira, o arquivo poderia ser organizado da seguinte forma: linha numFunc nivel departamento proximo 0 123 7 1 5 1 8765 12 1 -1 2 9210 4 2 -1 3 2628 4 3 6 4 5571 8 2 -1 5 652 1 1 9 6 7943 1 3 -1 7 671 5 3 12 8 1956 11 2 11 9 1398 6 1 10 10 3356 3 1 1 11 4050 2 2 4 12 2468 9 3 3
    • 10.3. REGISTROS 217 Em um segundo arquivo (chamado “depto.dat” – um arquivo de registros) temos as seguintes informa¸oes: c˜ codDepto nomeDepto inicio 1 vendas 0 2 contabilidade 8 3 estoque 7 4 entrega 2 Assim, o primeiro funcion´rio do departamento de vendas ´ o registro 0 do a e arquivo de funcion´rios e os demais funcion´rios do mesmo departamento s˜o a a a obtidos seguindo o campo proximo. Ou seja, os funcion´rios do departamento a de vendas s˜o os funcion´rios nos registros: 0, 5, 9, 10 e 1. Os funcion´rios do a a a departamento de contabilidade s˜o os funcion´rios nos registros: 8, 11 e 4. a a Escreva um programa em Pascal que realize as seguintes opera¸oes: c˜ • admiss˜o de novo funcion´rio a a • demiss˜o de funcion´rio a a • mudan¸a de departamento por um funcion´rio c a Para estas opera¸˜es devem ser lidas as informa¸oes: co c˜ • c´digo do tipo da opera¸ao: 0 para fim, 1 para admiss˜o, 2 para demiss˜o o c˜ a a e 3 para mudan¸a de departamento c • n´mero do funcion´rio u a • n´ salarial (somente no caso de admiss˜o) ıvel a • n´mero do departamento ao qual o funcion´rio passa a pertencer (no caso u a de admiss˜o e mudan¸a) a c • n´mero do departamento do qual o funcion´rio foi desligado (no caso de u a demiss˜o e mudan¸a) a c O programa deve escrever as seguintes informa¸oes: c˜ • os valores iniciais lidos dos arquivos • para cada opera¸˜o: o tipo da opera¸˜o realizada, os dados da opera¸ao e ca ca c˜ a forma final dos dados (de funcion´rios e departamentos) a No final do programa novos arquivos “func.dat” e “depto.dat” s˜o gerados com a os dados atualizados. Detalhamento: • a quantidade m´xima de funcion´rios ´ 1000 a a e • a quantidade m´xima de departamentos ´ 20 a e
    • 218 CAP´ ITULO 10. ESTRUTURAS DE DADOS • se a quantidade m´xima for ultrapassada o programa deve dar uma men- a sagem de erro • se for requisitada a remo¸˜o ou mudan¸a de um funcion´rio n˜o existente ca c a a no departamento especificado o programa deve dar uma mensagem de erro. • quando for requisitada a inser¸ao de um novo funcion´rio ´ preciso verificar c˜ a e se um funcion´rio com o mesmo n´mero j´ existe. a u a • se o c´digo de opera¸ao for inv´lido o programa deve continuar lendo um o c˜ a novo c´digo at´ que ele seja 0 (zero), 1 (um), 2 (dois) ou 3 (trˆs). o e e 8. Uma empreiteira tem contratos para construir diversos tipos de casa: moderno, fazenda, colonial, etc. A quantidade de material empregada para cada tipo de casa est´ armazenada em um arquivo chamado “material.dat”. Este ´ um a e arquivo de registros contendo: o tipo de casa e as respectivas quantidades de cada material necess´rias para sua constru¸˜o. Existem no m´ximo 50 tipos de a ca a casas e 100 tipos distintos de materiais. Cada tipo de casa ´ representado por um c´digo inteiro no intervalo [1,50]. Por e o exemplo: • 1: moderno • 2: fazenda • 3: colonial, ... Cada tipo de material ´ representado por um c´digo inteiro no intervalo [1,100]. e o Por exemplo: • 1: ferro • 2: madeira • 3: vidro • 4: tinta • 5: tijolo, ... Em um segundo arquivo, chamado “preco.dat”, encontram-se os pre¸os de cada c um dos materiais. Este tamb´m ´ um arquivo de registros contendo: o c´digo e e o do material e o seu respectivo pre¸o. O c´digo do material segue a mesma c o codifica¸ao utilizada pelo arquivo de materiais. c˜ Escreva um programa Pascal que leia os dados do arquivo “material.dat” em uma matriz e o dados do arquivo “preco.dat” em um vetor, como ilustrado abaixo. 9. Usando as estruturas de dados abaixo escreva um procedimento em Pascal que recebe como parˆmetro uma estrutura do tipo TAGENDA e ordena de forma cres- a cente o vetor pessoa dessa estrutura tomando como referˆncia para a ordena¸ao e c˜ o campo nome da estrutura TPESSOA. Ou seja, ordena uma agenda pessoal de
    • 10.3. REGISTROS 219 telefones e endere¸os em ordem crescente do nome das pessoas presentes na c agenda. Vocˆ deve usar a fun¸˜o compara(r, s), que recebe dois parˆmetros do e ca a tipo string e retorna 0 se r e s s˜o iguais, 1 se r ´ lexicograficamente maior que a e s e −1 se r ´ lexicograficamente menor que s. Um nome n1 ´ lexicograficamente e e maior que um nome n2 se n1 aparece depois de n2 numa ordena¸˜o alfab´tica ca e crescente desses nomes. Const MAX = 1000; Type TPESSOA = record nome: string; telefone: string; endereco: string end; TAGENDA = record pessoa: array [1..MAX] of TPESSOA; tamanho: integer end; 10. Uma matriz ´ dita esparsa quando a maioria dos seus elementos possui valor 0.0 e (zero). Neste caso, a representa¸˜o da matriz sob a forma tradicional (um array ca bidimensional) implica em uma utiliza¸ao ineficiente da mem´ria. Por isso, c˜ o matrizes esparsas s˜o freq¨entemente representadas como vetores de elementos a u n˜o nulos, sendo que cada elemento cont´m suas coordenadas e seu valor. a e Exemplo:   0 0 0 1.2  7.3 0 99 0  1 4 2 1 2 3 3 2 4 2 M=  0 2 0 0  ⇐⇒ Me =  1.2 7.3 99 2 17 0 17 0 0 Para representar estas matrizes em Pascal, podemos definir as seguintes estru- turas de dados: A∗ A Const M X = 1000; MAXESP = M X M X/10; A Type t matriz = record lin , col : integer ; dados : array [ 1 . .MAX 1 . .M X] of real ; , A end; elemento = record l , c : integer ; val : real ; end; t matrizesp = record tam : integer ; dados : array [ 1 . .MAXESP] of elemento ; end;
    • 220 CAP´ ITULO 10. ESTRUTURAS DE DADOS Utilizando as estruturas de dados definidas acima, fa¸a: c (a) Escreva uma fun¸ao que transforme uma matriz do tipo t_matriz em uma c˜ matriz do tipo t_matrizesp. (b) Escreva uma fun¸˜o que transforme uma matriz do tipo t_matrizesp em ca uma matriz do tipo t_matriz. (c) Escreva uma fun¸ao que receba duas matrizes do tipo t_matrizesp e im- c˜ prima o resultado da soma destas matrizes. O resultado deve ser im- presso na forma bidimensional, com os valores de cada linha separados por espa¸os. c 11. Verdadeiro ou falso: • um record deve ter pelo menos dois campos • os campos de um record tem que ter nomes diferentes • um record deve ter um nome diferente de qualquer um dos seus campos. 12. Suponha que a linguagem Pascal foi modificada para permitir que o s´ ımbolo ponto ”.”possa fazer parte de identificadores. Qual problema isto poderia cau- sar? Dˆ um exemplo. e 13. Esta defini¸ao ´ legal? Porque n˜o? c˜ e a TYPE Ponto = RECORD quantidade: integer; corte: Tamanho; END; Tamanho = (mini, medio, maxi); 14. Latitudes e longitudes s˜o especificadas em graus (o), minutos (’), segundos a (”) e dire¸˜o (norte, sul, leste, oeste). Suponha que uma cidade esteja na lati- ca tude 22o17’34” norte e longitude 53o41’9”oeste. Armazene esta localiza¸˜o na ca vari´vel Cidade, como declarada abaixo: a TYPE TipoDirecao = (norte, sul, leste, oeste); Coordenadas = RECORD graus: 0..180; minutos, segundos: 0..60; direcao: TipoDirecao; END; Localizacao = RECORD latitude, longitude: Coordenadas; END VAR Cidade: Localizacao;
    • 10.3. REGISTROS 221 15. Suponha que temos as seguintes defini¸oes e declara¸˜es abaixo: c˜ co TYPE NumTelefone = RECORD Area, Prefixo, Numero: integer; END; VAR Casa, Escritorio, Celular: NumTelefone; Escreva c´digo Pascal par testar se Escritorio e Celular est˜o sobre o mesmo o a c´digo de ´rea e para atribuir o mesmo n´mero do Celular como sendo o do o a u Escrit´rio. o 16. Criar registros para as seguintes configura¸˜es da vida real: co • Pessoas com nome, endere¸o, telefone, sexo, idade e sal´rio; c a • Planetas com massa, distˆncia m´dia do sol, n´mero de sat´lites, nome, a e u e diˆmetro. a • Cursos, com alunos e suas notas, per´ ıodos em que s˜o oferecidos, professor, a hor´rio. a 17. Uma matriz ´ dita esparsa se o n´mero de elementos n˜o nulos for bastante e u a pequeno com rela¸˜o ao n´mero total de elementos da matriz. Vocˆ deve fazer ca u e um programa que leia do teclado uma matriz qualquer de n´meros reais e crie u um vetor que armazene somente os elementos n˜o nulos da matriz. Cada posi¸ao a c˜ do vetor deve ser um registro contendo o valor do elemento, e a posi¸ao desse c˜ elemento na matriz (linha e coluna). Imprima o resultado. A maneira de definir o vetor faz parte da prova. Exemplo: Seja a matriz 4 × 5 abaixo: 0.0 0.0 3.0 0.0 1.7 -1.1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -2.1 0.0 0.0 0.0 2.5 0.0 0.0 Seu programa dever´ construir um vetor que permita imprimrir as seguintes a informa¸oes: c˜ • o elemento 3.0 est´ na posi¸ao (1,3) do vetor; a c˜ • o elemento 1.7 est´ na posi¸ao (1,5) do vetor; a c˜ • o elemento -1.1 est´ na posi¸ao (2,1) do vetor; a c˜ • o elemento -2.1 est´ na posi¸ao (3,4) do vetor; a c˜ • o elemento 2.5 est´ na posi¸ao (4,3) do vetor; a c˜
    • 222 CAP´ ITULO 10. ESTRUTURAS DE DADOS 18. Considere uma estrutura de vetores para representar uma matriz esparsa, tal como vocˆ definiu na quest˜o anterior. Fa¸a um procedimento para imprimir e a c a matriz completa, contendo todos os elementos nulos e n˜o nulos (n˜o precisa a a fazer o programa todo, basta o procedimento). Por exemplo, dado vetor com as informa¸oes descritas no exemplo da quest˜o anterior, a sa´ do seu programa c˜ a ıda deve ser exatamente a matriz apresentada no in´ do exemplo. ıcio 19. Considere o tipo PGM para imagens como definido na se¸˜o 10.2.5. Nas quest˜es ca o que seguem, considere as seguintes estruturas de dados e assinaturas de fun¸oes c˜ e procedimentos: const M X A =10000; type matriz = array [ 1 . .MAX 1 . .M X] of integer ; , A vetor = array [ 1 . .M X] of integer ; A imagem = record col , lin , maior : integer ; m: matriz ; end; imgcompactada = record tam: integer ; v: vetor ; end; function calcula valor medio (var I : imagem) : integer ; (∗ funcao que retorna o valor medio dos pixels da imagem, isto eh a soma de todos os elementos dividido pelo numero de elementos ∗) procedure ler (var I : imagem) ; (∗ procedimento que le uma imagem no formato P M ∗) G procedure imprime imagem (var I : imagem) ; (∗ procedimento que imprime uma imagem no formato P M ∗) G procedure binariza (var I : imagem; limiar : integer) ; (∗ procedimento que transforma a imagem de tons de cinza para preto e branco para isto , os pixels que forem maiores que o limiar devem se tornar brancos e os que forem menores ou iguais a este mesmo limiar devem se tornar pretos ∗) procedure compacta imagem (var I : imagem; var C: imgcompactada) ; (∗ procedimento que recebe uma imagem no formato P M e cria um vetor C G que eh uma representacao compactada desta ∗) procedure imprime img compactada (var C: imgcompactada) ; (∗ procedure que recebe uma imagem compactada e a imprime no formato P M ∗) G (a) Implemente estas fun¸˜es e procedimentos e fa¸a um programa que receba co c um certo n´mero N de imagens PGM em tons de cinza (onde 0 representa u preto e branco ´ representado pelo maior valor da imagem) e imprima a e
    • 10.3. REGISTROS 223 imagem binarizada, isto ´, em preto e branco (onde 0 representa preto e 1 e representa branco). Note que o limiar ´ obtido pelo valor m´dio dos pixels. e e (b) Implemente um procedimento que gere um vetor que representa a matriz binarizada de forma compacta. Para isto, use a seguinte ideia: como a matriz s´ tem zeros e uns, vamos substituir sequˆncias de uns pelo n´mero o e u de uns consecutivos. Os elementos v˜o sendo colocados no vetor, de ma- a neira linear, cada linha seguinte ´ concatenada ` anterior. Veja o exemplo: e a Exemplo: • Imagem binarizada: P2 11 10 1 1 1 1 1 0 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 • Imagem compactada: 36 4 0 5 0 2 0 8 0 0 1 0 0 0 3 0 0 11 0 0 0 5 0 0 0 0 0 0 11 0 14 0 12 0 0 0 Isto ´, a primeira linha da matriz possui 4 uns consecutivos seguido de um e zero e outros 5 uns consecutivos, por isto, o vetor cont´m seus primeiros e elementos “4, 0 e 5”. Preste aten¸ao antes de escrever o c´digo. Vocˆ c˜ o e pode definir, se precisar, fun¸˜es, procedimentos ou estruturas de dados co adicionais.
    • 224 CAP´ ITULO 10. ESTRUTURAS DE DADOS
    • Cap´ ıtulo 11Desenvolvendo programas de maiorporteNeste ponto do curso j´ temos todas as no¸˜es fundamentais de algoritmos e estruturas a code dados que s˜o necess´rias para a constru¸ao de programas complexos. O objetivo a a c˜daqui para frente ´ mostrar como se desenvolver programas de maior porte em rela¸˜o e caaos que vimos at´ agora. e11.0.1 Campo minadoO primeiro grande problema que vamos tentar resolver ´ o conhecido jogo do Campo eminado, costumeiramente dispon´ ıvel gratuitamente em diversos sistemas operacio-nais modernos. Uma descri¸˜o do funcionamento deste jogo pode ser encontrada na ca 1Wikipedia . Vamos tentar implementar a vers˜o ASCII do jogo, contudo com algumas simpli- afica¸oes: vamos ignorar as bandeiras que se podem colocar para marca¸˜o de prov´veis c˜ ca abombas e tamb´m vamos ignorar a contagem do tempo e registro dos recordes. Como ea interface ´ ASCII, naturalmente tamb´m n˜o vamos nos preocupar com a beleza da e e ainterface. A ideia ´ desenvolvermos um c´digo final usando-se a t´cnica de refinamentos e o esucessivos, isto ´, vamos partir de um c´digo geral, muitas vezes escritos em pseudo- e olinguagem, e a cada etapa detalharmos as estruturas de dados e algoritmos necess´rios apara a resolu¸ao do problema. Para isto vamos explorar ao m´ximo as no¸oes de c˜ a c˜fun¸oes e procedimentos da linguagem Pascal. c˜ Vamos partir da existˆncia de um tabuleiro de dimens˜es N × M que cont´m um e o ecerto n´mero B de bombas em algumas posi¸˜es. As outras posi¸˜es cont´m o n´mero u co co e utotal de bombas vizinhas. A cada jogada, o usu´rio entra com as coordenadas (i, j) aonde deseja abrir o tabuleiro, se for uma bomba, o jogo acaba, sen˜o ´ exibido o valor a eda c´lula. O jogo tamb´m termina quando o usu´rio abriu todas as posi¸oes que n˜o e e a c˜ atem bombas. O pseudoc´digo que resolve este problema est´ ilustrado na figura 11.1. Neste o aponto do desenvolvimento, optamos por postergar as defini¸˜es das estruturas de co 1 http://pt.wikipedia.org/wiki/Campo_minado 225
    • 226 CAP´ ITULO 11. DESENVOLVENDO PROGRAMAS DE MAIOR PORTEdados necess´rias. abegin (∗ programa principal ∗) ‘ ‘ Criar o campo minado de dimensoes NxM contendo B bombas’’ repeat ‘ ‘Imprimir o tabuleiro ocultando as celulas nao abertas’’ ‘ ‘Ler as coordenadas da celula a ser aberta’’ ‘ ‘ Abrir a celula indicada’’ ‘ ‘Se nao era bomba, entao atualiza bombas restantes’’ ‘ ‘Senao jogador perdeu’’ until ‘ ‘ jogador ganhou’’ or ‘ ‘ jogador perdeu’’ ; ‘ ‘Imprimir o tabuleiro final’’ ;end. Figura 11.1: Pseudoc´digo para campo minado. o Podemos imaginar algumas fun¸oes e procedimentos contendo alguns parˆmetros c˜ aparcialmente definidos, mas j´ com o comportamento desejado. Por exemplo, vamos asupor a existˆncia dos seguites: eCriaCampoMinado (campo): Procedimento que cria um campo minado contendo dimens˜es N × M com B bombas de maneira que cada elemento deste campo o minado, quando clicado, exibe uma bomba ou o n´mero de bombas ao redor da u posi¸ao. Inicialmente este campo ´ criado de maneira que nenhuma c´lula ainda c˜ e e foi aberta.ImprimeCampoMinado (campo): Procedimento que imprime o campo minado de maneira que as c´lulas ainda n˜o abertas n˜o s˜o exibidas ao usu´rio. Para e a a a a as que j´ foram abertas ´ exibido o n´mero de c´lulas vizinhas contendo bombas a e u e ou uma bomba.LerCoordenadas (i, j, acao): Procedimento que lˆ um par de coordenadas repre- e sentando respectivamente a linha i e a coluna j de uma c´lula para ser aberta. e O procedimento garante que as coordenadas s˜o v´lidas. A¸ao define o que fazer a a c˜ com a coordenada, se for zero ´ para abrir a c´lula, se for 1, ´ para marcar com e e e uma bandeira e se for 2 ´ para desmarcar a bandeira. eAbrirCelula (campo, i, j): Fun¸˜o que abre a c´lula (i, j) do campo minado e ca e retorna false caso a c´lula contenha uma bomba. Sen˜o, retorna true. No e a caso da c´lula conter uma bomba, tamb´m retorna o campo minado com a e e informa¸ao de que todas as c´lulas do campo s˜o agora consideradas abertas. c˜ e a No caso contr´rio, considera como abertas as c´lulas da seguinte maneira: se a a e c´lula cont´m um n´mero diferente de zero bombas, abre somente a coordenada e e u (i, j). Se for um valor de zero bombas, ent˜o considera como abertas todas as a
    • 227 c´lulas vizinhas de (i, j). Se uma destas tamb´m contiver zero bombas vizinhas, e e ent˜o tamb´m abre suas vizinhas, de maneira iterativa, at´ que n˜o hajam mais a e e a c´lulas alcan¸´veis cujo n´mero de bombas vizinhas seja zero. e ca u Com estes procedimentos, ´ poss´ refinar a vers˜o em pseudoc´digo acima para e ıvel a oa que est´ mostrada na figura 11.2. Notem que ainda n˜o especificamos as estruturas a ade dados que permitem a implementa¸ao destes procedimentos e fun¸˜es. c˜ cobegin CriaCampoMinado (campo) ; repeat ImprimeCampoMinado (campo) ; LerCoordenadas ( i , j , acao) ; i f AbrirCelula (campo, i , j ) then ‘ ‘ atualiza bombas restantes’’ else ‘ ‘ jogador perdeu’’ until ‘ ‘ jogador ganhou’’ or ‘ ‘ jogador perdeu’’ ; ImprimeCampoMinado (campo) ;end. Figura 11.2: Primeiro refinamento para campo minado. Para fecharmos o c´digo do programa principal, no pr´ximo refinamento temos que o odefinir como o jogo termina, isto ´, como determinarmos quando o jogador perdeu e equando ele ganhou. O primeiro caso ´ f´cil, o jogador perde quando clica em uma e abomba. Quanto ao outro caso, basta, por exemplo, determinar quantas foram as c´lulas eabertas com sucesso, isto ´, sem provocar explos˜o de bombas. O problema ´ que e a ea fun¸ao AbrirCelula abre, em potencial, mais c´lulas do que a que foi clicada. Isto c˜ eocorre quando se entra com uma coordenada de c´lula que cont´m zero bombas vizi- e enhas. Para resolver este problema, temos que modificar o comportamento da fun¸ao,c˜prevendo que ela cont´m um parˆmetro adicional que informa o n´mero de c´lulas e a u eque ela abriu, incluindo a da coordenada fornecida. Assim:AbrirCelula (campo, i, j, nCasasAbertas): Em adi¸˜o ` descri¸ao acima, o parˆmetro ca a c˜ a nCasasAbertas retorna o n´mero de c´lulas que foram abertas durante o pro- u e cedimento, incluindo a coordenada (i, j), em caso de sucesso. Este valor ´ zero e quando uma bomba foi encontrada. A rigor, podemos modificar a fun¸˜o para que ela retorne n˜o um valor booleano, ca amas simplesmente retorne o n´mero de casas que foram abertas. Se o valor for zero ´ u eporque se escolheu uma bomba. Ent˜o o procedimento fica assim: a
    • 228 CAP´ ITULO 11. DESENVOLVENDO PROGRAMAS DE MAIOR PORTEAbrirContarCelulasAbertas (campo, i, j): Fun¸˜o que abre a c´lula (i, j) do ca e campo minado e retorna zero caso a c´lula contenha uma bomba. Sen˜o, retorna e a o n´mero de c´lulas abertas. No caso da c´lula conter uma bomba, tamb´m re- u e e e torna o campo minado com a informa¸ao de que todas as c´lulas do campo c˜ e s˜o agora consideradas abertas. No caso contr´rio, considera como abertas as a a c´lulas da seguinte maneira: se a c´lula cont´m um n´mero diferente de zero e e e u bombas, abre somente a coordenada (i, j). Se for um valor de zero bombas, ent˜o considera como abertas todas as c´lulas vizinhas de (i, j). Se uma destas a e tamb´m contiver zero bombas vizinhas, ent˜o tamb´m abre suas vizinhas, de e a e maneira iterativa, at´ que n˜o hajam mais c´lulas alcan¸aveis cujo n´mero de e a e c´ u bombas vizinhas seja zero. Vamos precisar tamb´m saber o n´mero de bombas colocadas no campo minado e e uas dimens˜es deste, o que pode vir de uma fun¸ao que retorna o n´mero de c´lulas do o c˜ u ecampo (fun¸ao nCelulas (campo)). Assim o programa pode mais uma vez ser refinado, c˜ficando como ´ mostrado na figura 11.3. evar CelulasParaAbrir , nBombas: integer ; perdeu : boolean;begin CriaCampoMinado (campo, nBombas) ; CelulasParaAbrir:= nCelulas (campo) − nBombas; perdeu:= false ; repeat ImprimeCampoMinado (campo) ; LerCoordenadas ( i , j , acao) ; nAbertas:= AbrirContarCelulasAbertas (campo, i , j , acao) ; i f nAbertas = 0 then perdeu:= true; else CelulasParaAbrir:= CelulasParaAbrir − nAbertas ; until (CelulasParaAbrir = 0) or perdeu ; ImprimeCampoMinado (campo) ;end. Figura 11.3: Segundo refinamento para campo minado. Agora vamos precisar definir as estruturas de dados para podermos implementaros procedimentos acima e garantir que o jogo funcione. Mas o estudante deve notarque existem diversas maneiras de se definir estruturas de dados para este problema. Aque vamos mostrar ´ apenas uma dentre as possibilidades e foi escolhida pois tamb´m e evai servir para treinarmos o uso dos conceitos at´ aqui estudados. O aprendiz ´ e eencorajado a buscar alternativas e tentar um c´digo mais eficiente do que este que oser´ apresentado. a Com estas observa¸˜es em mente, vamos definir um campo minado como sendo couma matriz de inteiros. Cada valor representar´ o n´mero de bombas ao redor de a u
    • 229uma c´lula. Para n˜o complicarmos demais a estrutura, vamos considerar que uma e ac´lula contendo uma bomba ´ representado por um n´mero negativo, por exemplo, o e e u-1. Esta ´ uma boa escolha, pois o n´mero de bombas vizinhas ´ sempre maior ou e u eigual a zero e sempre menor do que nove. A rigor, poder´ ıamos usar qualquer valorfora deste intervalos, mas vamos manter o -1. Esta estrutura ´ insuficiente para se armazenar o fato das c´lulas j´ terem sido e e aabertas ou n˜o, uma vez que somente podem ser impressas as que j´ foram clicadas a aalguma vez. Por isto, vamos adotar um registro para ser o elemento da matriz: umcampo informa um n´mero inteiro e o outro informa se a c´lula deve ser mostrada ou u en˜o. a Finalmente, h´ a quest˜o das bandeiras que marcam posi¸˜es onde o jogador acre- a a codita conterem bombas. Vamos usar mais um campo booleano para representar isto.Desta maneira, nossa estrutura de dados para representar o tabuleiro ´ apresentada ea seguir. celula = record nbombas: integer ; aberto : boolean; marca: boolean; end; matriz = array [ 1 . .max, 1 . .max] of celula ; campominado = record nlin , ncol : integer ; m: matriz ; end; Assim o tabuleiro ´ um registro que cont´m uma matriz e as dimens˜es desta. Cada e e oelemento da matriz ´ um registro que armazena o n´mero de bombas (-1 representando e uuma bomba) e dois campos booleanos para se representar uma c´lula que j´ foi aberta e ae se tem uma bandeira ou n˜o.a Com isto podemos escrever c´digo para as fun¸oes e procedimentos. Vamos iniciar o c˜pelo primeiro que aparece no c´digo, isto ´, a inicializa¸ao da estrutura de dados: o e c˜CriaCampoMinado. Este c´digo ´ exibido na figura 11.4. o eprocedure CriaCampoMinado (var campo: campominado; var nbombas: integer) ;begin readln(campo. nlin , campo. ncol) ; (∗ le as dimensoes do campo ∗) readln(nbombas) ; (∗ le numero de bombas no campo ∗) zera campo (campo) ; (∗ inicializa o campo vazio ∗) gera bombas (campo, nbombas) ; (∗ coloca as bombas no campo ∗) conta vizinhos (campo) ; (∗ conta os vizinhos com bombas ∗)end; Figura 11.4: Criando campo minado. O leitor pode observar que optamos por ainda n˜o definir alguns c´digos de pro- a ocedimentos, mas j´ ´ necess´rio conhecer a estrutura do campo para que se possam ae aarmazenar no lugar certo os valores do n´mero de linhas e colunas. u
    • 230 CAP´ ITULO 11. DESENVOLVENDO PROGRAMAS DE MAIOR PORTE Os outro procedimentos s˜o apresentados a seguir. Zerar o campo ´ necess´rio pois a e ahaver´ uma distribui¸ao de bombas e a posterior contagem dos vizinhos que cont´m a c˜ ebombas, logo, o programador deve inicializar todas as estruturas para que o procedi-mento completo seja robusto. O procedimento para zerar o campo ´ apresentado na efigura 11.5.procedure zera campo (var campo: campominado) ;var i , j : integer ;begin for i:= 1 to campo. nlin do for j:= 1 to campo. ncol do begin campo.m[ i , j ] .nbombas:= 0; campo.m[ i , j ] . aberto:= false ; campo.m[ i , j ] . marca:= false ; end;end; Figura 11.5: Criando campo minado. Este procedimento percorre toda a matriz e zera o n´mero de bombas ao mesmo utempo em que informa que, inicialmente, nenhuma c´lula do campo pode ser exibida eainda. Tamb´m n˜o existem bandeiras a serem mostradas. e a O procedimento para gerar as bombas ser´ definido assim: tendo-se o n´mero de a ubombas que devem ser distribu´ ıdas, vamos gerar aleatoriamente as posi¸˜es (linha e cocoluna) onde elas ser˜o colocadas. Isto ´ apresentado na figura 11.6. a eprocedure gera bombas (var campo: campominado; nbombas: integer) ;var i , l , c : integer ;begin randomize ; for i:= 1 to nbombas do begin l:= random (campo. nlin ) + 1; c:= random (campo. ncol ) + 1; campo.m[ l , c ] .nbombas:= −1; (∗ −1 eh uma bomba ∗) end;end; Figura 11.6: Distribuindo as bombas. ´ E importante observar que este procedimento pode gerar coordenadas iguais parabombas diferentes, e isto pode ocasionar que o campo tem menos bombas do que oprevisto. O estudante ´ encorajado a modificar este procedimento para garantir que enunca uma bomba pode ser colocada em uma posi¸ao que j´ contenha outra. c˜ a Neste ponto temos uma matriz zerada a menos das posi¸oes que cont´m bombas. c˜ eN˜o foi alterada nenhuma informa¸ao sobre c´lulas abertas ou n˜o. a c˜ e a O procedimento para contar vizinhos ´, a princ´ e ıpio, simples. Basta varrer a matrize para cada c´lula diferente de -1 se percorrer todos os oito vizinhos e contar as bombas. e
    • 231O problema ´ que as c´lulas nas bordas da matriz v˜o fazer um c´digo muito extenso, e e a orepleto de if-then-else’s. Por isto vamos optar por modificar a estrutura de dados,prevendo uma borda para o programador que facilite o procedimento. Esta borda,desde que todos os elementos estejam zerados, ajuda bastante, mas o programador s´odeve us´-la neste caso, isto ´, no caso de contar as bombas. O c´digo ´ mostrado na a e o efigura 11.7.procedure conta vizinhos (var campo: campominado) ;var i , j , k, l , nbombas: integer ;begin for i:= 1 to campo. nlin do for j:= 1 to campo. ncol do begin i f campo.m[ i , j ] .nbombas < −1 then > begin nbombas:= 0; for k:= i−1 to i+1 do for l:= j−1 to j+1 do i f campo.m[ k, l ] .nbombas = −1 then nbombas:= nbombas + 1; campo.m[ i , j ] .nbombas:= nbombas; end; end;end; Figura 11.7: Contando vizinhos com bombas. Notem que agora a estrutura de dados passou por uma revis˜o, pois deve prever aa existˆncia da borda. Agora os ´ e ındices iniciam-se em zero e terminam em max+1. matriz = array [ 0 . .max+1,0..max+1] of celula ; O resto permanece igual, em termos de estrutura de dados, mas o algoritmo quezera o tabuleiro tem que ser revisto, pois as bordas tˆm que ser inicializadas tamb´m. e eA modifica¸˜o ´ simples, bastando se alterar os limites dos dois comandos for, con- ca eforme a figura 11.8:procedure zera campo (var campo: campominado) ;var i , j : integer ;begin for i:= 0 to campo. nlin + 1 do for j:= 0 to campo. ncol + 1 do (∗ o resto nao muda ∗)end; Figura 11.8: Criando campo minado. Neste ponto temos um campo minado pronto para ser jogado! Mas falta definirmos como ser´ feita a impress˜o do tabuleiro, como se entram a acom as coordenadas e, finalmente, como se abre uma c´lula. Os procedimentos para e
    • 232 CAP´ ITULO 11. DESENVOLVENDO PROGRAMAS DE MAIOR PORTEleitura das coordenadas e impress˜o da matriz n˜o ser´ exibido aqui por serem muito a a asimples. Mas tamb´m pode o estudante que souber usar o mouse implement´-los e acomo uma rotina gr´fica. Mostramos na figura 11.9 o procedimento que abre uma ac´lula. efunction AbrirContarCelulasAbertas (var campo: campominado; lin , col , acao : integer) : integer ;var r : coordenadas ; cont : integer ; abrir : conjunto ;begin i f acao = 0 then i f campo.m[ lin , col ] .nbombas = −1 then (∗ achou bomba . . . ∗) AbrirContarCelulasAbertas:= 0 else begin cont:= 1; campo.m[ lin , col ] . aberto:= true; campo.m[ lin , col ] . marca:= false ; i f campo.m[ lin , col ] .nbombas = 0 then begin r . lin:= lin ; r . col:= col ; insere no conjunto ( abrir , r ) ; end; ‘ ‘AbreTodosVizinhosSemBomba’’ ; AbrirContarCelulasAbertas:= cont ; end else i f acao = 1 then campo.m[ lin , col ] . marca:= true else i f acao = 2 then campo.m[ lin , col ] . marca:= false ;end; Figura 11.9: Criando campo minado. Este procedimento ´ o mais complexo de todos a implementar. De fato, quando se eabre uma c´lula que tem zero bombas vizinhas, toda sua vizinhan¸a deve ser aberta e ctamb´m. O problema ´ que um destes vizinhos (ou mais de um) pode tamb´m cont´m e e e eum valor zero. Por isto usamos um procedimento que abre todos os vizinhos que tˆm ezero bombas e os vizinhos destes e assim por diante, at´ n˜o sobrar mais nenhum e a(AbreTodosVizinhosSemBomba). A solu¸ao mais elegante para este problema envolve a no¸ao de recursividade que c˜ c˜est´ fora do escopo deste curso, normalmente ela ´ vista em Algoritmos e Estruturas a ede Dados II. A solu¸ao adotada foi, para cada coordenada que possui zero bombas vizinhas, c˜armazenar esta coordenada para ser aberta posteriormente em outro procedimento.
    • 233Por isto criamos um tipo de dados chamado conjunto, que cont´m as coordenadas da eposi¸ao em quest˜o. c˜ a A ideia ´ temos um procedimento que pega um elemento do conjunto, sabidamente euma c´lula que tem zero bombas vizinhas, e que abre todos os vizinhos, mas para os eque s˜o nulos, armazena no conjunto. Assim, enquanto o conjunto contiver elementos, aexistem c´lulas para serem abertas ainda. O c´digo pode ser visto na figura 11.10. e oprocedure AbreTodosVizinhosSemBomba (var campo: campominado; var abrir : conjunto ; var cont : integer) ;var r , q: coordenadas ; i , j : integer ;begin while not conjunto vazio ( abrir ) do begin remove do conjunto ( abrir , r ) ; for i:= r . lin−1 to r . lin+1 do for j:= r . col−1 to r . col+1 do begin i f DentroCampo (campo, i , j ) then begin i f (campo.m[ i , j ] .nbombas = 0) and not campo.m[ i , j ] . aberto then begin q. lin:= i ; q. col:= j ; insere no conjunto ( abrir , q) ; end; i f not campo.m[ i , j ] . aberto then begin campo.m[ i , j ] . aberto:= true; cont:= cont + 1; end; end; end; end;end; Figura 11.10: Criando campo minado. . O problema agora ´ definirmos a estrutura de dados para este novo tipo, ne- ecess´rio para o funcionamento do c´digo, chamado conjunto. Tamb´m criamos uma a o efun¸ao chamada DentroCampo para informar se uma coordenada est´ dentro do c˜ acampo minado, pois podemos estar pegando elementos da borda. A defini¸˜o do tipo conjunto ser´ feito na pr´xima se¸ao, mas podemos neste ca a o c˜momento imaginar que as fun¸oes e procedimentos que manipulam os dados deste c˜tipo funcionam corretamente e declarar que o c´digo que resolve o problema do campo ominado est´ conclu´ a ıdo. A t´ ıtulo de exemplo, colocamos o c´digo completo na p´gina web da disciplina: o ahttp://www.inf.ufpr.br/cursos/ci055/mines_v4.pas.
    • 234 CAP´ ITULO 11. DESENVOLVENDO PROGRAMAS DE MAIOR PORTE11.1 Exerc´ ıcios 1. Escreva um programa em Pascal que implemente o jogo “ca¸a palavras”. O seu c program deve ler da entrada padr˜o: a • o n´mero de linhas da matriz de letras u • o n´mero de colunas da matriz de letras u • a matriz de letras (seq¨ˆncia de letras) ue • o n´mero de palavras u • a lista de palavras, sendo cada palavra dada por: – o tamanho da palavra – a palavra (seq¨ˆncia de letras) ue O programa deve procurar cada palavra da lista nas linhas e nas colunas da matriz. Para cada palavra encontrada o programa deve informar as posi¸˜es co (linha, coluna) de inicio e fim da palavra na matriz. 2. Abaixo temos parte da implementa¸˜o de um jogo de ca¸a-palavras. Neste jogo ca c de ca¸a-palavras as palavras podem estar dispostas apenas na horizontal (da c esquerda para direita apenas) ou na vertical (de cima para baixo). A entrada da matriz de letras deve ser feita a partir de um arquivo e as palavras devem ser entradas a partir do teclado. Para cada palavra a ser procurada devem ser impressa as coordenadas da matriz onde a palavra se inicia e onde termina. Vocˆ e deve completar esta implementa¸˜o para que o programa funcione corretamente. ca Program Caca_palavras (input,output,arquivo); (* declare as constantes necess´rias *) a (* declare os tipos necess´rios *) a (* implemente os procedimentos e fun¸oes necess´rios *) c~ a (* declare as vari´veis necess´rias *) a a BEGIN ASSIGN (arquivo,’matriz.txt’); RESET (arquivo); Leia (tabuleiro, numLinhas, numColunas); CLOSE (arquivo); WRITELN (’entre com uma palavra qualquer’); READ (palavra); WHILE NaoVazia (palavra) DO BEGIN IF Achou (palavra,tabuleiro,linIni,colIni,linFim,colFim) THEN BEGIN WRITE (’A palavra ’,palavra,’ ocorre a partir da coorden
    • 11.1. EXERC´ ICIOS 235 WRITELN (linIni,colIni,’ terminando em ’,linFim,colFim); END; READ (palavra); END; END.
    • 236 CAP´ ITULO 11. DESENVOLVENDO PROGRAMAS DE MAIOR PORTE Quest˜o 2 a (60 pontos) Considere as seguintes defini¸˜es de tipos: co TYPE coordenada = RECORD linha, coluna: integer; END; vetor = ARRAY [1..MAXTAM] of coordenada; ocorrencias = RECORD numOcorre: integer; coord : vetor; END; tabela = ARRAY [’A’..’Z’] of ocorrencias; A id´ia consiste em tentar otimizar a busca de palavras armazenando as ocorrˆncias e e de cada letra da matriz de entrada em uma tabela de ocorrˆncias. Na tabela e podemos registrar n˜o apenas quantas vezes cada letra ocorre na matriz mas a tamb´m as coordenadas de todas estas ocorrˆncias. e e (a) Fa¸a um desenho da estrutura de dados “tabela” acima definida e explique c como ela pode ser usada para que possamos saber, para cada letra, as coordenadas de todas as ocorrˆncias desta letra na matriz do ca¸a-palavras; e c (b) Crie um procedimento que recebe como parˆmetros a matriz do jogo, suas a dimens˜es, e inicialize a estrura da tabela conforme vocˆ acaba de explicar o e no item anterior; (c) Implemente a fun¸˜o “Achou” do programa anterior de maneira a tirar ca onde ela ocorre, que podem ser armazenadas em um vetor. proveito da estrutura “tabela” aqui definida. 3. Um passatempo bastante comum s˜o os “ca¸a-palavras”. Neste tipo de pro- a c blema existe uma lista de palavras sobre algum tema e uma grade repleta de letras distribu´ ıdas de maneira aparentemente sem sentido. Por exemplo: • chave s c C e l r • mel U e H A y r • erva g E A i M c c A V R E A • cama c x E p L a • v´u e
    • 11.1. EXERC´ ICIOS 237 Resolver o problema consiste de encontrar na grade as palavras indicadas na lista. Neste exerc´ vocˆ deve projetar um programa que receba como entrada ıcio e um problema do tipo “ca¸a-palavras” e deve retornar as coordenadas de in´ c ıcio e t´rmino de cada palavra fornecida na lista de palavras. Valer˜o pontos: a e a correta escolha da estrutura de dados, o bom uso de fun¸˜es e procedimentos, co a modularidade, a possibilidade de generaliza¸ao do problema, por exemplo, se c˜ vocˆ tiver um dia que modificar o seu programa para um ca¸a-palavras tridi- e c mensional, seu programa deve ser facilmente adapt´vel. Note que as palavras a est˜o em qualquer dire¸ao, horizontal, vertical, nas diagonais e que podem ser a c˜ escritas normalmente ou de maneira inversa. Preocupe-se inicialmente em de- talhar a estrutura do programa, isto j´ valer´ pontos. Mas observe que valer´ a a a a totalidade dos pontos apenas as quest˜es que detalharem c´digo de maneira o o suficiente. 4. Considere um dos mais populares jogos de azar do momento, a Mega-Sena. Neste jogo, um certo n´mero de apostadores marcam em uma cartela um n´mero u u vari´vel entre 6 e 15 dezenas (n´meros inteiros) entre 1 e 60. Ap´s o encerra- a u o mento das apostas, a agˆncia que det´m o controle do jogo (doravante denomi- e e nada Agˆncia) promove um sorteio p´blico de exatamente seis dezenas. Estas e u dezenas sorteadas s˜o comparadas com cada uma das apostas feitas pelo p´blico. a u Todos as cartelas que contiverem as seis dezenas sorteadas s˜o consideradas ga- a nhadoras e dividem o prˆmio. e Neste exerc´ vocˆ deve imaginar que foi contratado pela Agˆncia para proje- ıcio e e tar e implementar um sistema computacional que seja capaz de ler um arquivo contendo o conjunto das apostas do p´blico e encontrar o conjunto de vence- u dores. Por quest˜es de tempo, e para facilitar a corre¸˜o, vocˆ deve seguir as o ca e seguintes instru¸oes: c˜ • Use a primeira metade do tempo da prova para projetar o sistema, iniciando pelo programa principal. Defina, na medida do necess´rio, as estruturas a de dados que vocˆ utilizar´. Pense em usar constantes, tipos e vari´veis e a a adequadas para o algoritmo que vocˆ est´ planejando. Pense em deixar e a partes importantes do programa a cargo de procedimentos ou fun¸˜es. co • Use e abuse de procedimentos e fun¸oes (doravante apenas procedimen- c˜ tos). Vocˆ n˜o ´ obrigado a implementar todos os procedimentos. Mas e a e vocˆ deve indicar claramente seus prot´tipos e fazer uma documenta¸ao e o c˜ adequada de cada um. Lembrando que um prot´tipo de procedimento ´ a o e linha que cont´m a palavra reservada PROCEDURE (ou FUNCTION), o e nome, os argumentos e o tipo de retorno (no caso das fun¸˜es), isto ´, ´ o co e e procedimento tirando o que vem entre o BEGIN e o END (inclusive). • Vocˆ receber´ pelo menos duas folhas de resposta. Organize-as para que as e a primeiras p´ginas contenham a declara¸˜o de tipos, constantes e vari´veis, a ca a os prot´tipos de fun¸oes que vocˆ n˜o vai implementar, etc. Procure reser- o c˜ e a var uma p´gina inteira tamb´m para o programa principal, que, a princ´ a e ıpio, n˜o ´ grande. a e
    • 238 CAP´ ITULO 11. DESENVOLVENDO PROGRAMAS DE MAIOR PORTE • Vocˆ ter´ uma certa liberdade para estruturar o sistema. Mas lembre-se e a que a escolha das estruturas de dados ´ decisiva! e Vocˆ dever´ implementar completamente o programa principal, as declara¸oes e a c˜ de constantes, tipos e vari´veis utilizadas e no m´ a ınimo procedimentos para fazer o seguinte: (a) Ler o conjunto de apostas, que dever´ estar armazenado em um arquivo a do tipo TEXT. Este arquivo conter´ uma linha para cada aposta e cada a aposta consiste de um identificador da aposta e dos n´meros apostados u (entre 6 e 15 dezenas); (b) Gerar aleatoriamente uma aposta v´lida; a (c) Verificar se uma dada aposta ´ vencedora, baseando-se evidentemente na e combina¸˜o sorteada; ca (d) Gerar uma cole¸ao de seis dezenas v´lidas que maximizam o n´mero de c˜ a u apostas ganhadoras. 5. Fazendo uso das boas t´cnicas de programa¸˜o vistas durante o curso, fa¸a um e ca c programa em Pascal que implemente um jogo da velha: • O jogo possui um tabuleiro composto de nove posi¸oes, na forma de uma c˜ matriz de tamanho 3 por 3; cada posi¸˜o pode estar vazia ou pode ser ca ocupada pelo s´ ımbolo de um dos jogadores. • Dois jogadores participam do jogo, sendo que a cada um destes ´ associado e um s´ımbolo distinto, por exemplo: “X” e “0”. • A primeira jogada ´ efetuada pelo jogador X; em cada jogada um dos e jogadores ocupa uma posi¸ao vazia do tabuleiro; os jogadores se alternam c˜ a cada jogada. • Um dos jogadores vence quando ocupa uma posi¸ao que completa uma c˜ seq¨ˆncia de trˆs s´ ue e ımbolos iguais em uma linha, coluna ou diagonal. • O jogo termina empatado quando todas as posi¸oes do tabuleiro foram c˜ ocupadas e n˜o houve vencedor. a 6. Considere o problema do “Jogo da Vida” estudado em sala de aula. Sem qual- quer sombra de d´vidas, a opera¸˜o mais cara computacionalmente falando em u ca qualquer algoritmo que implemente a solu¸˜o do jogo ´ a contagem do n´mero ca e u de vizinhos de cada c´lula. Considerando uma c´lula fora da borda do tabuleiro, e e escreva um trecho de c´digo Pascal que obtenha o n´mero de vizinhos de uma o u c´lula. Vocˆ n˜o pode fazer uso de nenhum comando repeat, while, if, ou case, e e a mas deve usar comandos for. Este trecho de c´digo dever´ conter apenas e t˜o o a a somente a defini¸ao do tipo de dados para o tabuleiro e os comandos para contar c˜ o n´mero de vizinhos. u
    • 11.1. EXERC´ ICIOS 239 7. Na quest˜o anterior foi solicitado para n˜o se considerar a borda do tabuleiro. a a Nesta quest˜o vocˆ deve indicar, segundo a estrutura de dados definida no item a e anterior, qual o comportamento do seu programa quando se tenta contar o n´mero de vizinhos de uma c´lula da borda. Se por acaso houver alguma pos- u e sibilidade de erros, indique como deve ser modificado o algoritmo, sem alterar a estrura de dados, para que o erro deixe de existir. 8. Considere um jogo de Batalha Naval em que cada participante dispor´ seus 5 a barcos de 1, 2, 3, 4 e 5 c´lulas, respectivamente, no espa¸o de uma matriz de e c N × N (N ≥ 100). Os barcos dever˜o estar ou na dire¸ao horizontal ou na vertical, dever˜o ser a c˜ a retos e n˜o poder˜o se tocar. N˜o poder´ haver barcos que passem pelas linhas a a a a e colunas marginais da matriz. Escreva o programa principal para montar um jogo e fazer uma disputa entre dois advers´rios, especificando as chamadas as diferentes fun¸oes e procedimen- a ` c˜ tos. Escrever as fun¸˜es e procedimentos necess´rios para o bom funcionamento do co a seu programa principal acima. Vocˆ deve documentar a l´gica da solu¸ao de forma precisa. Em particular, e o c˜ descreva as estruturas de dados que vocˆ utilizar e a forma como elas ser˜o e a usadas para resolver o problema. 9. Implementar o Jogo da vida. 10. implementar o Sudoku 11. implementar a TV da vov´ o 12. implementar a espiral. 13. implementar o minesweeper.
    • 240 CAP´ ITULO 11. DESENVOLVENDO PROGRAMAS DE MAIOR PORTE
    • Cap´ ıtulo 12Tipos abstratos de dadosNo cap´ ıtulo anterior deixamos em aberto a defini¸˜o de um tipo de dados do qual can˜o importava saber, naquele momento, quais os detalhes das estruturas de dados e aaloritmos, mas importava saber da existˆncia de fun¸oes e procedimentos com com- e c˜portamentos espec´ ıficos para garantir o funcionamento do jogo do campo minado. Esta ideia ser´ desenvolvida aqui neste cap´ a ıtulo, isto ´, vamos mostrar como de- efinir tipos abstratos de dados. Como no exemplo do tipo conjunto, a ideia e termosinterfaces bem definidas. A implementa¸ao pode ser feita de v´rias maneiras, mas na c˜ averdade, para quem usa, n˜o faz diferen¸a alguma, a n˜o ser o comportamento destas a c afun¸oes e procedimetnos. c˜ Vamos iniciar pelo tipo conjunto, apenas para concluir o exerc´ ıcio do cap´ ıtuloanterior. Depois mostraremos outros tipos, todos compat´ ıveis com o conte´do desta udisciplina.12.1 Tipo ConjuntoUm conjunto ´ um conceito matem´tico bem conhecido. Trata-se de uma cole¸˜o de e a caelementos, sem repeti¸˜o. Opera¸oes importantes sobre conjuntos incluem saber se o ca c˜conjunto ´ vazio, se um elemento pertence ou n˜o a um conjunto, inserir ou remover e aelementos ou realizar opera¸˜es de uni˜o e interse¸ao. co a c˜ Primeiramente, vamos definir as interfaces, deixando a implementa¸˜o para um casegundo momento. As principais opera¸oes sobre conjuntos s˜o as seguintes: c˜ aCriaConjunto (C): Inicializa a estrutura de dados;ConjuntoVazio (C): Fun¸˜o que rotorna true se o conjunto C ´ vazio e false caso ca e contr´rio; aCardinalidade (C): Fun¸ao que retorna a cardinalidade (o n´mero de elementos) c˜ u do conjunto C.Pertence (x,C): Fun¸˜o que retorna true se o elemento x pertence ao conjunto C ca e false caso contr´rio; a 241
    • 242 CAP´ ITULO 12. TIPOS ABSTRATOS DE DADOSInsere (x, C): Procedimento que insere o elemento x no conjunto C garantindo que n˜o haver´ repeti¸ao; a a c˜Remove (x,C): Procedimento que remove o elemento x do conjunto C;Uniao (C1, C2, C3): Procedimento que faz a uni˜o dos conjuntos C1 e C2 retor- a nando o resultado no conjunto C3;Interseccao (C1, C2, C3): Procedimento que faz a intersec¸˜o dos conjuntos C1 ca e C2 retornando o resultado no conjunto C3;Contido (C1, C2): Fun¸˜o que retorna true se o conjunto C1 est´ contido no ca a conjunto C2 e retorna false caso contr´rio. a Vamos para isto usar um conjunto de n´meros reais. As opera¸oes aqui definidas u c˜servir˜o para dar a base necess´ria para que se possa implementar o conjunto de a acoordenadas para o exerc´ do campo minado, bastando para isto que se adapte o ıciotipo real para o tipo coordenadas. O conjunto de reais ser´ implementado em um registro com dois campos: um vetor ade reais e o tamanho util desse. ´const max = 10000;type vetor = array [ 1 . .max] of real ; conjunto = record tam: integer ; v: vetor ; end; Figura 12.1: Estrutura de dados para tipo conjunto. As fun¸˜es e procedimentos ter˜o que lidar com o tamanho m´ximo deste vetor, co a aque ´ definido pela constante max. Vamos considerar a existˆncia de um procedimento e edenominado Erro (msg) que retorna erro em caso de qualquer problema apresentandoa mensagem msg. Evidentemente que isto pode ser feito de outra maneira, mas estaop¸ao ´ apenas para facilitar a reda¸˜o do texto. c˜ e ca Vamos implementar na ordem os procedimentos acima descritos. O primeiro deles´ o que inicializa a estrutura, que deve resultar na cria¸ao de um conjunto vazio.e c˜Para isto, basta definirmos que o tamanho do vetor ´ zero, conforme mostrado na efigura 12.2. Assim, ´ f´cil tamb´m definirmos o c´digo da fun¸˜o que testa se o conjunto ´ ou e a e o ca en˜o vazio, conforme mostrado na figura 12.3. a Tamb´m ´ trivial a fun¸ao que retorna a cardinalidade de um conjunto, o que ´ e e c˜ eapresentado na figura 12.4. A pr´xima tarefa ´ criar um procedimento que define se um elemento pertence ao o econjunto. Para isto, ´ necess´rio que se percorra o vetor em busca do elemento. Isto e aj´ foi feito nesta disciplina. Pode-se usar busca simples, busca com sentinela, busca a
    • 12.2. TIPO LISTA 243procedure CriaConjunto (var c : conjunto) ;begin c .tam:= 0;end; Figura 12.2: Procedimento para criar um conjunto vazio.function ConjuntoVazio (var c : conjunto) : boolean;begin i f c .tam = 0 then ConjuntoVazio:= true else ConjuntoVazio:= false ;end; Figura 12.3: Fun¸ao que testa se conjunto ´ vazio. c˜ ebin´ria ou outra que se venha a inventar. No momento, vamos implementar uma abusca simples, sem sentinela, conforme mostrado na figura 12.5. A pr´xima tarefa ´ garantir a inser¸ao de um elemento no conjunto, de modo a o e c˜n˜o gerar elementos repetidos. Isto ´ mostrado na figura 12.6. Optamos por inserir a esempre no final, para tornar a opera¸ao menos custosa. Mas poderiamos ter optado c˜por outra maneira de inserir, por exemplo, sempre no in´ ıcio, de maneira ordenada(por exemplo para viabilizar busca bin´ria) ou outras. Isto ´ importante para se a eimplementar outras fun¸oes ou procedimentos como os de remo¸ao, uni˜o, etc. . . . c˜ c˜ a Para remover um elemento do conjunto temos que inicialmente saber a posi¸˜o ca 1deste elemento . Este c´digo ´ mostrado na figura 12.7. o e A uni˜o de dois conjuntos consiste em se adicionar todos os elementos dos dois aconjuntos e garantir a n˜o repeti¸ao de elementos. Isto ´ meio chato de fazer e ´ a c˜ e emostrado na figura 12.8. A intersec¸ao consiste de construir um conjunto que cont´m apenas os elementos c˜ eque ocorrem nos dois vetores. O procedimento que faz esta opera¸˜o ´ apresentado ca ena figura 12.9. Finalmente, para sabermos se um conjunto est´ contido em outro, basta percorrer ao primeiro conjunto e verificar se todos os elementos est˜o no segundo, conforme aapresentado na figura 12.10. Observamos, mais uma vez, que estes algoritmos devem ser alterados e adaptadospara o programa do campo minado da se¸ao anterior funcionarem. Isto fica como c˜exerc´ ıcio.12.2 Tipo ListaUma lista pode ser usada em v´rias situa¸oes: lista de compras, lista de pagantes, a c˜lista de presentes ou de mebros de um clube. Trata-se de uma cole¸˜o de elementos, caeventualmente com repeti¸ao. Opera¸oes importantes sobre listas incluem saber se a c˜ c˜ 1 Note que o programa do campo minado precisa de um procedimento que remove um elementoqualquer do conjunto e isto vai ficar como exerc´ para o estudante. ıcio
    • 244 CAP´ ITULO 12. TIPOS ABSTRATOS DE DADOSfunction Cardinalidade (var c : conjunto) : integer ;begin Cardinalidade:= c .tam;end; Figura 12.4: Fun¸˜o que retorna a cardinalidade do conjunto. cafunction Pertence (x: real ; var c : conjunto) : boolean;var i : integer ;begin i:= 1; while ( i <= c .tam) and (c .v[ i ] < x) do > i:= i + 1; i f i <= c .tam then Pertence:= true else Pertence:= false ;end; Figura 12.5: Fun¸ao que define pertinˆncia no conjunto. c˜ elista ´ vazia, se um elemento pertence ou n˜o a uma lista, inserir ou remover elementos, e aconcatenar listas, e demais opera¸oes. c˜ Primeiramente, vamos definir as interfaces, deixando a implementa¸˜o para um casegundo momento. As principais opera¸oes sobre listas s˜o as seguintes: c˜ aCriaLista (L): Inicializa a estrutura de dados;ListaVazia (L): Fun¸ao que rotorna true se a lista L ´ vazia e false caso contr´rio; c˜ e aTamanho (L): Fun¸˜o que retorna o n´mero de elementos da lista L. ca uPertence (x,L): Fun¸˜o que retorna true se o elemento x pertence ` lista L e false ca a caso contr´rio; aInsere (x, L): Procedimento que insere o elemento x na lista L;Remove (x,L): Procedimento que remove o elemento x da lista L;Uniao (L1, L2, L3): Procedimento que faz a fus˜o das listas L1 e L2 retornando a o resultado na lista L3; Notem que, contrariamente aos conjuntos, uma lista pode ter repeti¸oes, e, por c˜vezes, pode importar a ordem dos elementos. Podemos implementar uma lista de n´meros reais usando um registro com dois ucampos: um vetor de reais e o tamanho util desse. ´ Neste caso, a implementa¸ao das fun¸oes e procedimentos recair´ nos exerc´ c˜ c˜ a ıciosque j´ fizemos no cap´ a ıtulo sobre vetores. Sabemos que as opera¸oes de remo¸ao e c˜ c˜inser¸ao custam algo proporcional ao tamanho do vetor e que, para piorar, exigem c˜tamb´m algo de ordem proporcional ao tamanho do vetor em n´mero de c´pias a e u o
    • 12.2. TIPO LISTA 245procedure InsereConjunto (x: real ; var c : conjunto) ;begin i f not Pertence (x, c) then i f Cardinalidade (c) < c .tam then begin c .tam:= c .tam + 1; c .v[ c .tam]:= x; end else Erro (’Conjunto cheio’) ;end; Figura 12.6: Procedimento para inserir elemento no conjunto.procedure RemoveConjunto (x: real ; var c : conjunto) ;var i : integer ;begin (∗ primeiro acha o elemento no conjunto ∗) i:= 1; while ( i <= c .tam) and (c .v[ i ] < x) do > i:= i + 1; i f i <= c .tam then begin (∗ se achou remove, senao nao faz nada ∗) for j:= i to c .tam−1 do c .v[ j ]:= c .v[ j +1]; c .tam:= c .tam − 1; end;end; Figura 12.7: Procedimento para remover elemento do conjunto.cada elemento removido ou inserido no “meio” do vetor, uma vez que os vetores n˜o apodem ter “buracos”. Notem que isto ocorre no tipo conjunto definido na se¸ao anterior quando se remove c˜um elemento do conjunto, mas n˜o na opera¸ao de inser¸ao, que ´ sempre no final. a c˜ c˜ e Em sua forma b´sica, um vetor ´ feito de tal maneira que para cada elemento o a eseu sucessor ´ sempre o que est´ no ´ e a ındice seguinte do vetor. Por exemplo, se umelemento est´ na posi¸ao i do vetor, o pr´ximo estar´ na posi¸˜o i + 1. a c˜ o a ca Vamos modificar este comportamento e introduzir uma nova maneira de se colocaras informa¸˜es no vetor. Agora, o elemento sucessor do que est´ na posi¸˜o i poder´ co a ca aficar em qualquer outra posi¸ao diferente de i, bastando para isto que se anote qual c˜´ esta posi¸˜o. Isto exigir´, no momento, o uso de um campo adicional para indicare ca aesta informa¸ao, tal como mostrado na figura 12.11. c˜ Para exemplificar, consideremos a lista de elementos como sendo: 5.2, -1.9, 4.8,3.3, -2.7 e 7.2, nesta ordem. O desenho abaixo mostra essa lista na estrutura proposta.
    • 246 CAP´ ITULO 12. TIPOS ABSTRATOS DE DADOSprocedure UniaoConjunto (var c1 , c2 , c3 : conjunto) ;var i , cont : integer ;begin CriaConjunto (c3) ; (∗ como o primeiro conjunto nao tem repeticao ∗) (∗ insere todos os elementos deste no conjunto resultante ∗) for i:= 1 to c1 .tam do c3 .v[ i}:= c1 .v[ i ] ; c3 .tam:= c1 .tam; (∗ para cada elemento do segundo conjunto , se ele nao ∗) (∗ estiver no primeiro , insere no final do segundo ∗) cont:= 0; for i:= 1 to c2 .tam do i f not Pertence (c2 .v[ i } , c1) then begin Insere (c2 .v[ i ] , c3) ; cont:= cont + 1; end; c3 .tam:= c3 .tam + cont ;end; Figura 12.8: Procedimento para unir dois conjuntos. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 3.3 7.2 5.2 4.8 -1.9 -2.7 18 0 13 4 11 6 Para recuperarmos a lista, basta saber a posi¸˜o do primeiro, isto ´, a posi¸ao ca e c˜9. De fato, o elemento 5.2 est´ na nona posi¸ao do vetor. O elemento seguinte est´ a c˜ aindicado logo abaixo, isto ´, na posi¸˜o 13. Novamente, conferimos que o segundo e caelemento da lista, -1.9, est´ na posi¸ao 13 do vetor. O pr´ximo, 4.8, est´ na posi¸ao a c˜ o a c˜4. Pode-se conferir que, de fato, o 3.3 est´ na quarta posi¸ao do vetor e seu sucessor a c˜est´ na posi¸˜o indicada, 18. O -2.7 est´ nesta posi¸ao e o ultimo, o 7.2 na posi¸ao a ca a c˜ ´ c˜indicada, a sexta. O fato deste elemento ser o ultimo ´ anotado com o ´ ´ e ındice zero. As fun¸˜es e procedimentos ter˜o que lidar com o tamanho m´ximo deste vetor, co a aque ´ definido pela constante max. Vamos considerar a existˆncia de um procedimento e edenominado Erro (msg) que retorna erro em caso de qualquer problema apresentandoa mensagem msg. Evidentemente que isto pode ser feito de outra maneira, mas estaop¸ao ´ apenas para facilitar a reda¸˜o do texto. c˜ e ca Vamos implementar na ordem os procedimentos acima descritos. O primeiro deles´ o que inicializa a estrutura, que deve resultar na cria¸ao de uma lista vazia. Para isto,e c˜basta definirmos que o tamanho do vetor ´ zero, conforme mostrado na figura 12.12. e Assim, ´ f´cil tamb´m definirmos o c´digo da fun¸˜o que testa se a lista ´ ou n˜o e a e o ca e avazia, conforme mostrado na figura 12.13. Tamb´m ´ trivial a fun¸˜o que retorna o n´mero de elementos da lista, o que ´ e e ca u eapresentado na figura 12.14. A pr´xima tarefa ´ criar um procedimento que define se um elemento faz parte o e
    • 12.2. TIPO LISTA 247procedure InterseccaoConjunto (var c1 , c2 , c3 : conjunto) ;var i , cont : integer ;begin CriaConjunto (c3) ; cont:= 0; for i:= 1 to c1 .tam do i f Pertence (c1 .v[ i ] , c2) then begin InsereConjunto (c1 .v[ i ] , c3) ; cont:= cont + 1; end: c3 .tam:= cont ;end; Figura 12.9: Procedimento para fazer a intersec¸ao de dois conjuntos. c˜function ContidoConjunto (var c1 , c2 : conjunto) : boolean;var i : integer ;begin ContidoConjunto:= false ; i:= 1; while ( i<= c1 .tam) and Pertence(c1 .v[ i ] , c2) then i:= i + 1; i f i = c1 .tam then ContidoConjunto:= true else ContidoConjunto:= false ;end; Figura 12.10: Procedimento para verificar se um conjunto est´ contido em outro. ada lista. Para isto, ´ necess´rio que se percorra o vetor em busca do elemento. Isto e aj´ foi feito nesta disciplina, para o caso de um vetor “tradicional” (ver se¸˜o 10.1.3. a caMas, desta vez, os elementos est˜o armazenados de um modo diferente, em primeiro alugar, sem ordena¸ao, o que impede a busca bin´ria. Em sugundo lugar, percorrer c˜ aa lista ´ um pouco diferente do que percorrer um vetor, pois o sucessor na lista de eum elemento pode estar em qualquer outra posi¸˜o, logo, o tradicional incremento cado apontador deve ser substitu´ levando-se em conta o campo “pr´ximo”. Isto ´ ıdo o emostrado na figura 12.15. A pr´xima tarefa ´ garantir a inser¸˜o de um elemento na lista. Isto ´ mostrado o e ca ena figura 12.16. Uma decis˜o que precisa ser tomada ´ onde inserir na lista, isto ´, a e eem qual posi¸ao. No caso do conjunto, inserimos sempre no final. No caso da lista, o c˜mais f´cil ´ inserir sempre no in´ a e ıcio, uma vez que temos o apontador para o primeiroelemento. Inserir no final custaria uma busca pelo ultimo elemento, a menos que se ´modifique a estrutura de dados para se armazenar tamb´m o ultimo, al´m do primeiro. e ´ e Assim, optamos por inserir sempre no in´ ıcio, para tornar a opera¸ao menos cus- c˜tosa. O estudante ´ encorajado a construir algoritmos que inserem em uma posi¸˜o e cadeterminada por um parˆmetro. a
    • 248 CAP´ ITULO 12. TIPOS ABSTRATOS DE DADOSconst max = 10000;type celula= record elemento : real ; proximo : integer ; end; vetor = array [ 1 . .max] of celula ; l i s t a = record tamamho, primeiro : integer ; v: vetor ; end; Figura 12.11: Estrutura de dados para tipo lista.procedure CriaLista (var l : l i s t a ) ;begin l .tamanho:= 0;end; Figura 12.12: Procedimento para criar uma lista vazia. Um detalhe adicional ´ que, nesta estrutura, precisamos saber quais s˜o as posi¸oes e a c˜do vetor que n˜o s˜o ocupadas por nenhum elemento da lista, pois uma inser¸˜o vai a a caocupar um espa¸o novo. Por exemplo, na ilustra¸ao acima, das 20 posi¸oes do vetor, c c˜ c˜apenas 6 est˜o ocupadas. Vamos supor que existe uma fun¸ao que retorne um ´ a c˜ ındicen˜o ocupado no vetor: aAlocaPosicao (v): Fun¸˜o que retorna um inteiro entre 1 e max indicando uma ca posi¸ao do vetor que n˜o ´ usada por nenhum elemento da lista. c˜ a e Para remover um elemento da lista temos que inicialmente saber a posi¸ao deste c˜elemento. Vamos precisar de um procedimento para informar que a posi¸ao no vetor c˜do elemento removido da lista agora est´ livre e pode ser usada futuramente em um aprocesso de inser¸ao. c˜DesalocaPosicao (p, v): Procedimento que informa que a posi¸ao p n˜o est´ mais c˜ a a em uso e pode ser alocada futuramente. O problema deste procedimento ´ que, para remover um elemento da lista, deve-se esimplesmente apontar o campo pr´ximo do elemento anterior do que ser´ removido o apara o sucessor deste. N˜o h´ a necessidade de se mover todos os que est˜o “na frente” a a apara tr´s, como faz´ a ıamos no caso do vetor tradicional. Localizar a posi¸ao do elemento a ser removido n˜o ´ suficiente, uma vez que temos c˜ a etamb´m que localizar a posi¸ao do anterior. Isto exige um c´digo mais elaborado, o e c˜ oqual ´ mostrado na figura 12.17. e
    • 12.2. TIPO LISTA 249function ListaVazia (var l : l i s t a ) : boolean;begin i f l .tamanho = 0 then ListaVazia:= true else ListaVazia:= false ;end; Figura 12.13: Fun¸˜o que testa se lista ´ vazia. ca efunction Tamanho (var l : l i s t a ) : integer ;begin Tamanho:= l .tamanho;end; Figura 12.14: Fun¸˜o que retorna o n´mero de elementos da lista. ca u A uni˜o de duas listas consiste em se adicionar todos os elementos das duas listas. aBasta varrer as duas listas e inserir na terceira, conforme apresentado na figura 12.18.
    • 250 CAP´ ITULO 12. TIPOS ABSTRATOS DE DADOSfunction Pertence (x: real ; var l : l i s t a ) : boolean;var i : integer ;begin i:= l . primeiro ; (∗ indice no vetor do primeiro elemento da l i s t a ∗) while ( i <= l .tamanho) and ( l .v[ i ] . elemento < x) do > i:= l .v[ i ] . proximo ; (∗ indice no vetor do proximo elemento na l i s t a ∗) i f i <= l .tamanho then Pertence:= true else Pertence:= false ;end; Figura 12.15: Fun¸˜o que define pertinˆncia na lista. ca eprocedure InsereLista (x: real ; var l : l i s t a ) ;var p: integer ;begin i f Tamanho ( l ) < l .tamanho then begin l .tamanho:= l .tamanho + 1; p:= AlocaPosicao (v) ; (∗ acha posicao liv re ∗) l .v[p ] . elemento:= x; l .v[p ] . proximo:= l . primeiro ; (∗ o que era primeiro agora eh o segundo ∗) l . primeiro:= p; (∗ o novo elemento agora eh o primeiro ∗) end else Erro (’Lista cheia’) ;end; Figura 12.16: Procedimento para inserir elemento na lista.
    • 12.2. TIPO LISTA 251procedure RemoveLista (x: real ; var l : l i s t a ) ;var i : integer ;begin i f ListaVazia ( l ) then Erro (’Lista vazia, nao eh possivel remover elemento’) else i f l .v[ l . primeiro ] . proximo = 0 then (∗ l i s t a tem um unico elemento ∗) i f l . [ l . primeiro ] . elemento = x then begin l . primeiro:= 0; . . tamanho:= 0; end; else (∗ l i s t a tem mais de um elemento , achar a posicao de x ∗) begin q:= l . inicio ; p:= l .v[q ] . proximo ; while (p < 0) and ( l .v[p ] . elemento < x) do > > begin q:= p; p:= l .v[p ] . proximo ; end; i f l .v[p ] . elemento = x then (∗ achou posicao de x ∗) begin l .v[q ] . proximo:= l .v[p ] . proximo ; l .tamanho:= l .tamanho − 1; DesalocaPosicao (p,v) ; end; end;end; Figura 12.17: Procedimento para remover elemento da lista.procedure UniaoListas (var l1 , l2 , l3 : l i s t a ) ;var i , cont : integer ;begin CriaLista ( l3 ) ; i:= l1 . primeiro ; while i < 0 do > begin Insere ( l1 .v[ i ] . elemento) , l3 ) ; i:= l1 .v[ i ] . proximo ; end; i:= l2 . primeiro ; while i < 0 do > begin Insere ( l2 .v[ i ] . elemento) , l3 ) ; i:= l2 .v[ i ] . proximo ; end;end; Figura 12.18: Procedimento para unir duas listas.
    • 252 CAP´ ITULO 12. TIPOS ABSTRATOS DE DADOS12.2.1 Exerc´ ıcios 1. Considere o tipo abstrato de dados lista assim definido: TYPE TipoIndice = 1..TAM_MAX_LISTA; TipoElemento = RECORD Num : Real; Prox: TipoIndice; END; Lista = RECORD Tam: integer; Primeiro: TipoIndice; Vet: ARRAY [1..TAM_MAX_LISTA] of TipoElemento; END; Vamos considerar que os elementos da lista s˜o inseridos em ordem crescente a considerando-se a estrutura de dados. Por exemplo, em algum momento a lista: 12, 15, 16, 20, 38, 47 Pode estar armazenada na estrutura da seguinte maneira: Tam 6 Primeiro 4 Vet 16 20 12 47 15 38 2 9 7 0 1 5 • Desenhe como estar´ a estrutura de dados lista ap´s a remo¸ao do elemento a o c˜ “20” da lista seguido da inser¸ao do elemento “11”. Note que remo¸oes ou c˜ c˜ inser¸oes devem manter a lista ordenada considerando-se a estrutura de c˜ dados. • Implemente uma fun¸˜o InsereOrdenado em Pascal que receba como parˆmetros ca a uma lista do tipo lista e um elemento real e insira este elemento no local correto na lista ordenada, considerando-se a estrutura de dados. 2. Preˆmbulo: Na aula n´s trabalhamos uma estrutura “Lista”, que foi assim a o definida: TYPE Registro = RECORD chave: string[20]; (* outros campos *) prox: integer; END; Lista = ARRAY [1..TAM_MAX_LISTA] of Registro;
    • 12.2. TIPO LISTA 253 VAR L: Lista; TamLista: integer; (* Ou seja, a lista nao sabe seu tamanho *) Primeiro: integer; (* Diz quem ´ o primeiro elemento da lista *) e Nesta estrutura, n´s trabalhamos uma s´rie de procedimentos que manipulavam o e esta lista. Por´m, nestes procedimentos, havia a necessidade de passar como e parˆmetros, al´m da lista em s´ o seu tamanho e quem ´ o primeiro. Isto a e ı, e causa a necessidade de definir as duas vari´veis globais, a saber, T amLista e a P rimeiro. Agora, vocˆ deve resolver as quest˜es seguintes: e o 3. Modifique a estrutura da Lista acima para que seja uma lista de (apenas e t˜o a somente) reais, de maneira que as informa¸oes sobre seu tamanho e quem ´ o c˜ e primeiro estajam definidas na pr´pria lista, isto ´, a unica vari´vel global relativa o e ´ a a lista ser´ L. ` a 4. Baseado na sua modifica¸˜o, fa¸a os seguintes procedimentos e/ou fun¸oes (a ca c c˜ escolha correta faz parte da prova): (a) criar a lista; (b) inserir o elemento X na posi¸˜o pos da lista L; ca (c) retornar o elemento X que est´ na posi¸˜o pos da lista L. a ca 5. Com base nos procedimentos e/ou fun¸˜es acima definidos, fa¸a um programa co c principal que, usando apenas os procedimentos acima, leia uma seq¨ˆncia de ue reais e, em seguida, ordene a lista usando para isto o algoritmos de ordena¸ao c˜ por sele¸ao. Observe que, a princ´ c˜ ıpio, neste ´ ıtem da prova, vocˆ n˜o conhece e a a estrutura interna da lista, vocˆ apenas sabe que ´ uma lista de reais, e tem e e acesso aos elementos pelas suas posi¸oes. c˜ 6. Considere o tipo abstrato de dados lista definido em aula: TYPE TipoIndice = 1..TAM_MAX_LISTA; TipoElemento = RECORD Num : Real; Prox: TipoIndice; END; Lista = RECORD Tam: integer; Primeiro: TipoIndice; Vet: ARRAY [1..TAM_MAX_LISTA] of TipoElemento; END;
    • 254 CAP´ ITULO 12. TIPOS ABSTRATOS DE DADOS Considerando que os elementos da lista est˜o ordenados em ordem crescente, im- a plemente uma fun¸ao RemoveOrdenado em Pascal que receba como parˆmetros c˜ a uma lista do tipo lista e um elemento do tipo Real e remova este elemento da lista, mantendo a lista ordenada. N˜o vale remover e ordenar a lista toda. a Considere as seguintes estruturas de dados: TYPE TipoIndice = 1..TAM_MAX_LISTA; TipoElemento = Real; Lista = RECORD Tam: integer; Vet: ARRAY [1..TAM_MAX_LISTA] of TipoElemento; END; Isto define um tipo abstrato de dados chamado ”Lista”. Listas s˜o comumente a usadas em diversos tipos de programas. Trata-se basicamente de uma estrutura qualquer que cont´m alguns n´meros de interesse, no caso, n´meros reais. e u u A id´ia ´ esconder detalhes da estrutura e trabalhar apenas com ”o que fazer”e e e n˜o ”como fazer”. Isto ´ feito pela defini¸˜o de um conjunto de fun¸oes e a e ca c˜ procedimentos que manipulam a real estrutura, escondendo detalhes in´teis do u usu´rio (no caso, este usu´rio ´ um programador tamb´m). a a e e As principais opera¸oes que manipulam listas s˜o as seguintes: c˜ a • criar uma lista (vazia) • inserir (no in´ ıcio, no fim, na posi¸˜o p) ca • remover (do in´ ıcio, do fim, da posi¸ao p) c˜ • verificar o tamanho da lista • saber se a lista est´ vazia/cheia a • imprimeir a lista em ordem • fundir duas listas • intercalar duas listas • pesquisar o elemento da posi¸˜o p na lista ca • copiar uma lista em outra • particionar uma lista em duas, segundo algum crit´rio e Por exemplo, uma fun¸ao que cria uma lista na estrutura acima definida poderia c˜ ser algo assim: • Convenciona-se que a lista com tamanho zero est´ vazia. a
    • 12.2. TIPO LISTA 255 • Define-se a seguinte fun¸˜o: ca procedure cria_lista (var L: Lista); begin L.tam :=0; end; {cria lista} Outro exemplo, para saber se a lista est´ vazia, pode-se fazer algo parecido com a isto: function lista_vazia (var L: Lista): boolean; begin lista_vazia := (L.tam = 0); end; {lista vazia} 7. Implemente os outros procedimentos e fun¸oes indicados acima, isto ´, crie um c˜ e conjunto de fun¸oes e procedimentos que ir˜o constituir uma biblioteca que c˜ a manipula o tipo abstrato de dados Lista. 8. Implemente um programa que encontra bilhetes premiados do jogo da mega- sena, usando o tipo lista acima definido: • Seu programa dever´ ter ler de um arquivo texto os bilhetes que concor- a rem ao premio da mega-sena. Neste arquivo, cada linha tem os n´meros u apostados. Note que cada linha pode ter um n´mero diferente de apostas, u sendo no m´ınimo 6 e no m´ximo 10. a • Invente uma maneira de indicar ao programa que as apostas terminaram. Considere que a primeira coluna do arquivo cont´m o identificador da e aposta, que ´ o n´mero do cart˜o (sen˜o vocˆ n˜o sabe quem ganhou). e u a a e a • Um outro programa dever´ gerar aleatoriamente o arquivo com as apostas. a • Gere uma lista contendo os n´meros sorteados. u • Use a estrutura de lista para ler o arquivo com as apostas e use apenas opera¸oes com a lista para saber quem ganhou prˆmios: quadra, quina, c˜ e sena, indicando separadamente os identificadores dos premiados. Isto ´, e imprima uma lista com os ganhadores da mega-sena, da quina e da quadra. • Implemente uma fun¸˜o (para fins did´ticos!!!) que calcule uma com- ca a bina¸ao de n´meros ”sorteados”que n˜o tenha nenhum ganhador. c˜ u a • Implemente uma fun¸˜o que calcule uma combina¸ao de n´meros que ma- ca c˜ u ximize o n´mero de ganhadores. Note que as apostas tem entre 6 e 10 u n´meros. u • Implemente uma fun¸˜o (para fins did´ticos!!!) que n˜o apenas fa¸a que ca a a c uma determinada aposta seja a vencedora, mas de maneira que ela minimize o n´mero de outros ganhadores. Note que as apostas tem entre 6 e 10 u n´meros. u
    • 256 CAP´ ITULO 12. TIPOS ABSTRATOS DE DADOS ´ • E proibido manipular diretamente a lista, imagine que vocˆ n˜o faz a menor e a id´ia de que se trata de uma record com um inteiro e um vetor. e 9. Em aula n´s trabalhamos uma estrutura “Lista”, que foi assim definida: o TYPE Registro = RECORD chave: string[20]; (* outros campos *) prox: integer; END; Lista = ARRAY [1..TAM_MAX_LISTA] of Registro; VAR L: Lista; TamLista: integer; (* Ou seja, a lista nao sabe seu tamanho *) Primeiro: integer; (* Diz quem ´ o primeiro elemento da lista * e N´s trabalhamos em aula uma s´rie de procedimentos que manipulavam esta o e estrutura de lista. Por´m, ´ poss´ e e ıvel implementar os mesmos procedimentos usando-se uma estrutura de vetor. Como em um vetor o primeiro elemento ´ e sempre o da primeira posi¸ao, a vari´vel global P rimeiro torna-se desnecess´ria, c˜ a a bastando apenas mantermos o controle da vari´vel T amLista. a Neste exerc´ ıcio, vocˆ deve resolver as quest˜es seguintes: e o (a) Modifique a estrutura da Lista acima para que seja uma vetor de reais. (b) Baseado na sua modifica¸˜o, fa¸a os seguintes procedimentos e/ou fun¸oes ca c c˜ (a escolha correta faz parte da prova): i. criar a lista (o que n˜o significa inserir elementos nela); a ii. inserir o elemento X na posi¸˜o pos da lista L; ca iii. retornar o elemento X que est´ na posi¸˜o pos da lista L. a ca (c) Fa¸a um programa principal que, sem usar informa¸˜es sobre a estrutura c co interna da lista a n˜o ser pelo uso de fun¸oes e procedimentos definidos por a c˜ vocˆ (se n˜o forem os do exerc´ anterior, vocˆ deve constru´ e a ıcio e ı-los), fa¸a o c seguinte: i. leia uma seq¨ˆncia de reais e os insira, um a um, na lista, em ordem ue num´rica crescente; e ii. insira um elemento no final da lista; iii. retire o primeiro elemento da lista; iv. ordene a lista pelo m´todo de ordena¸ao por sele¸ao; e c˜ c˜