• Nenhum resultado encontrado

Calculando ra´ızes de equa¸c˜ oes do segundo grau

No documento Algoritmos e Estruturas de Dados I (páginas 121-128)

9.3 Alguns exemplos

9.4.1 Calculando ra´ızes de equa¸c˜ oes do segundo grau

Para refor¸carmos os conceitos em estudo, consideremos aqui o problema de se ler os coeficientes a, b e c que definem uma equa¸c˜ao do segundo grau ax2 +bx+c = 0 e imprimir as ra´ızes calculadas pela f´ormula de B´askara. O programa deve imprimir mensagens corretas no caso de n˜ao haverem ra´ızes reais bem como n˜ao deve aceitar entradas cujo valor para o coeficienteasejam nulas. O programa da figura 9.11 cont´em o c´odigo que resolve este problema.

A figura 9.12 ilustra o programa principal modificado para se dar a ideia de que as fun¸c˜oes se comportam como express˜oes aritm´eticas, ao contr´ario dos procedimentos, que se comportam como comandos.

Na verdade, o programa principal poderia ser apenas o c´odigo da figura 9.13, sem preju´ıjo do funcinamento, mas com bem menos legilidade e ainda por cima sem tratamento do delta negativo. Apresentamos esta vers˜ao apenas para ilustrar o uso das fun¸c˜oes dentro de fun¸c˜oes, mas observamos que o c´alculo do delta ´e feito duas vezes.

program raizes eq 2o grau ;

var a , b, c , delta , x1 , x2 : real; procedure l e r (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∗b4∗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 ∗)

l e r (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´ızes de equa¸c˜ao do segundo grau.

9.4. C ´ALCULO DO MDC PELA DEFINIC¸ ˜AO 123

begin (∗ programa principal ∗)

l e r (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´ızes de equa¸c˜ao do segundo grau.

begin (∗ programa principal ∗)

l e r (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´ızes de equa¸c˜ao do segundo grau.

Terminamos aqui a primeira parte do curso, no qual as no¸c˜oes fundamentais sobre algoritmos est˜ao estabelecidas. Nos pr´oximos estudaremos as principais estruturas de dados b´asicas para um curso introdut´orio de algoritmos.

9.5 Exerc´ıcios

1. Fazer uma fun¸c˜ao em Pascal que receba como parˆametro dois n´umeros intei-ros n˜ao nulos e retorne TRUE se um for o contr´ario do outro e FALSE em caso contr´ario. Isto ´e, se os parˆametros forem 123 (cento e vinte e trˆes) e 321 (trezentos e vinte e um), deve-se retornar TRUE. Usar apenas opera¸c˜oes sobre inteiros.

2. Fazer uma fun¸c˜ao em Pascal que receba como parˆametro um n´umero inteiro representando um n´umero bin´ario e retorne seu valor equivalente em decimal.

Por exemplo, se a entrada for 10001, a sa´ıda deve ser 17.

3. Fazer uma fun¸c˜ao em Pascal que receba como parˆametro um n´umero inteiro e retorne TRUE se ele for primo e FALSE em caso contr´ario. Use esta fun¸c˜ao para imprimir todos os n´umeros primos entre 0 e 1000.

4. Implemente fun¸c˜oes para seno e cosseno conforme definidos em cap´ıtulos an-teriores e use-as em uma terceira fun¸c˜ao que calcule a tangente. O programa principal deve imprimir os valores de tg(x) para um certo valor fornecido pelo usu´ario.

5. Implemente um procedimento para gerar mais de um milh˜ao de n´umeros inteiros.

Os n´umeros gerados dever˜ao ser impressos em um arquivo texto.

6. Fa¸ca uma fun¸c˜ao em Pascal que some dois n´umeros representando horas. A entrada deve ser feita da seguinte maneira:

12 52 7 13

A sa´ıda deve ser assim:

12:52 + 7:13 = 20:05

7. Fa¸ca uma fun¸c˜ao que receba como parˆametros seis vari´aveis DIA1, MES1 e ANO1, DIA2, MES2 e ANO2, todas do tipo integer. Considerando que cada trinca de dia, mˆes e ano representa uma data, a fun¸c˜ao deve retornar true se a primeira data for anterior `a segunda e false caso contr´ario.

Cap´ıtulo 10

Estruturas de dados

At´e aqui apresentamos as t´ecnicas b´asicas para constru¸c˜ao de algoritmos, incluindo as no¸c˜oes de fun¸c˜oes e procedimentos. Podemos dizer que ´e poss´ıvel, com este conte´udo, programar uma vasta cole¸c˜ao de algoritmos, inclusive alguns com alta complexidade.

Contudo, o estudo geral da disciplina de “Algoritmos e Estrurutas de Dados”

envolve algoritmos que trabalham dados organizados em mem´oria de maneira mais sofisticada do que as simples vari´aveis b´asicas que foram estudadas at´e o momento.

E algo mais ou menos parecido como manter um guarda-roupas organizado no lugar´ de um monte de coisas atiradas no meio do quarto de qualquer jeito.

A organiza¸c˜ao de dados em mem´oria permite a constru¸c˜ao de algoritmos sofistica-dos e eficientes. Neste textp estudaremos trˆes estruturas de dados elementares. S˜ao elas:

• vetores (ou array unidimencional);

• matrizes (ou array multidimencional);

• registros.

Nas se¸c˜oes seguintes explicaremos cada uma delas, sempre motivados por proble-mas que exigem seu uso ou que facilitam a implementa¸c˜ao. Tamb´em veremos nos pr´oximos cap´ıtulos algumas estruturas que misturam estas trˆes.

10.1 Vetores

Para motivar, vamos considerar o problema seguinte: ler uma certa quantidade de valores inteiros e os imprimir na ordem inversa da leitura. Isto ´e, se os dados de entrada forem: 2, 5, 3, 4, 9, queremos imprimir na sa´ıda: 9, 4, 3, 5, 2.

Este tipo de problema ´e imposs´ıvel de ser resolvido com o uso de apenas uma vari´avel pois, quando se lˆe o segundo n´umero, j´a se perdeu o primeiro da mem´oria.

Exigiria o uso de tantas vari´aveis quantos fossem os dados de entrada, mas notem que isto deve ser conhecido em tempo de compila¸c˜ao! O que faz com que simplesmente n˜ao seja poss´ıvel resolver este problema para uma quantidade indefinida de valores.

125

De fato, quando se aloca, por exemplo, um n´umero inteiro em uma vari´avel de nomea, o que ocorre ´e que o computador reserva uma posi¸c˜ao de mem´oria em algum endere¸co da RAM (conforme sabemos pelo modelo Von Neumann). Um inteiro exige (dependendo da implementa¸c˜ao) 2 bytes.

Mas, digamos que ´e preciso alocar espa¸co para 100 n´umeros inteiros. Sabendo que cada um deles ocupa 2 bytes, precisar´ıamos encontrar uma maneira de reservar 100×2 = 200 bytes e fazer com que este espa¸co de mem´oria pudesse ser acessado tamb´em por um ´unico endere¸co, ou em outras palavras, por uma ´unica vari´avel.

Os vetores s˜ao estruturas de dados que permitem o acesso a uma grande quantidade de dados em mem´oria usando-se apenas um nome de vari´avel. Esta vari´avel especial

´e declarada de tal maneira que o programador passa a ter acesso `a muitas posi¸c˜oes de mem´oria, de maneira controlada.

Sem ainda entrar em detalhes da linguagemPascal, vamos tentar entender o pro-cesso.

Como funciona isto em mem´oria?

Seguindo no exemplo de se alocar 200 espa¸cos em mem´oria para n´umeros inteiros, suponhamos que o seguinte comando faz esta aloca¸c˜ao:

var V: array[ 1 . . 2 0 0 ] of integer;

EmPascal isto resulta na aloca¸c˜ao de 200 vezes 2 bytes. Pela vari´avel V temos o controle deste espa¸co.

O problema ´ecomo se faz para se escrever um valor qualquer neste espa¸co. Outro problema ´eonde se escreve, j´a que temos 200 possibilidades de escolha. O simples uso da vari´avel, como est´avamos acostumados, n˜ao serve. ´E preciso uma outra informa¸c˜ao adicional para se dizerem qual das 200 posi¸c˜oes se quer escrever.

Na verdade, a vari´avel V aponta para o in´ıcio do segmento reservado, da mesma maneira que se fazia para vari´aveis b´asicas j´a estudadas. Para se escrever em algum lugar deste segmento, ´e preciso informar, al´em do nome da vari´avel, uma segunda informa¸c˜ao: a posi¸c˜ao (ou o deslocamento) dentro do espa¸co reservado.

Ora, sabemos que foram reservadas 200 posi¸c˜oes, cada uma delas com espa¸co para conter um n´umero inteiro. Se quisermos escrever na quinta posi¸c˜ao, basta informar ao computador que o in´ıcio do segmento ´e dado pela vari´avel V e que, antes de se escrever, ´e preciso realizar um deslocamento de 5 posi¸c˜oes, cada uma delas para um inteiro. Isto d´a um deslocamento de 10 bytes. Ap´os esta informa¸c˜ao, o valor pode ser escrito. Se o desejo ´e escrever na d´ecima quarta posi¸c˜ao, o deslocamento deve ser de 14×2 bytes, isto ´e, 28 bytes.

Para se recuperar a informa¸c˜ao, por exemplo para se imprimir, ou para se fazer algum c´alculo com estes dados, basta usar o mesmo processo: os dados s˜ao acessados pelo nome da vari´avel e pelo deslocamento.

Este processo foi apresentado em muito baixo n´ıvel. Como de costume, precisamos de uma outra forma de representa¸c˜ao de mais alto n´ıvel. Isto ´e, cada linguagem de

10.1. VETORES 127 programa¸c˜ao que implementa a no¸c˜ao de vetores tem que encontrar uma maneira para se mascarar para o programador este processo que ´e baseado em deslocamentos (ou somas de endere¸cos).

Na pr´oxima se¸c˜ao veremos como a linguagem Pascal lida com isto.

Vetores em Pascal

Para se declarar um vetor de 200 posi¸c˜oes inteiras, a linguagem Pascal usa a seguinte sintaxe (lembre-se que em outras linguagens a sintaxe pode ser diferente):

var v : array [ 1 . . 2 0 0 ] of integer;

A constru¸c˜ao “1..200” indica que existem 200 posi¸c˜oes controladas pela vari´avel v. O “of integer” indica que cada posi¸c˜ao ´e para se guardar um n´umero inteiro, isto

´

e, 2 bytes (dependendo da implementa¸c˜ao).

A rigor, a linguagemPascal permite que se reserve 200 posi¸c˜oes de v´arias maneiras.

Basta que o intervalo “a..b” contenha 200 posi¸c˜oes. Apresentamos 6 variantes dentre as milhares poss´ıveis:

var v : array [ 0 . . 1 9 9 ] 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¸c˜oes. Em termos gerais, existe uma restri¸c˜ao forte. O intervalo deve ser definido em termos de n´umeros de algum tipo ordinal (em Pascal), isto ´e, integer, logint, . . . , at´e mesmo char. Tamb´em em Pascal, o limite inferior deve ser menor ou igual ao limite superior. Na sequˆencia desta se¸c˜ao, vamos considerar a vers˜ao que usa o intervalo de 1 a 200.

Agora, para guardar um valor qualquer, digamos 12345, na posi¸c˜ao 98 do vetor v, em Pascal, se usa um dos dois comandos seguintes:

v[98]:= 12345;

read(v[ 9 8 ] ) ; (∗ e se digita 12345 no teclado ∗)

Em termos gerais, vejamos os seguintes exemplos, para fixar o conceito:

read (v [ 1 ] ) ; (∗ l e 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 tel a ∗)

write (v [ v [ 1 3 ] ] ) ; (∗ imprime o valor de v[100] na t ela ∗) 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¸c˜ao (v[v[13]]) s´o ´e poss´ıvel pois o vetor v ´e do tipo integer. Se fosse um vetor de reais isto n˜ao seria poss´ıvel (em Pascal).

No documento Algoritmos e Estruturas de Dados I (páginas 121-128)