• Nenhum resultado encontrado

Cuidados na implementação da recursividade

No documento Linguagem c Completa e Descomp (páginas 191-200)

Tipos definidos pelo programador

RETORNO DA FUNÇÃO

9.3.3 Cuidados na implementação da recursividade

O exemplo da Figura 9.30 apresenta as funções com e sem recursão para o cálculo do fatorial.

Exemplo: fatorial

Com recursão Sem recursão

01 02 03 04 05 06 07 08 09 10

int fatorial (int n){

if(n == 0) return 1; else

return n*fatorial(n-1); }

int fatorial (int n){

if(n == 0) return 1; else {

int i, f = 1;

for (i=2; i <= n;i++) f = f * i; return f; }

}

F I G U R A 9 . 3 0

Em geral, as formas recursivas dos algoritmos são consideradas “mais enxutas” e “mais elegantes” do que suas formas iterativas. Isso facilita a interpretação do código. Porém, esses algoritmos apresentam maior dificuldade na detecção de erros e podem ser ineficientes.

Todo cuidado é pouco ao se fazerem funções recursivas, pois duas coisas devem ficar bem estabelecidas: o critério de parada e o parâmetro da chamada recursiva.

Durante a implementação de uma função recursiva temos de ter em mente duas coisas: o critério de parada e o parâmetro da chamada recursiva:

Critério de parada

• : determina quando a função deve parar de chamar a si mes- ma. Se ele não existir, a função continuará executando até esgotar a memória do computador. No cálculo de fatorial, o critério de parada ocorre quando tenta- mos calcular o fatorial de zero: 0! = 1.

Parâmetro da chamada recursiva

• : quando chamamos a função dentro dela mes-

ma, devemos sempre mudar o valor do parâmetro passado, de forma que a recur- são chegue a um término. Se o valor do parâmetro for sempre o mesmo, a função continuará executando até esgotar a memória do computador. No cálculo de fa- torial, a mudança no parâmetro da chamada recursiva ocorre quando definimos o fatorial de N em termos no fatorial de (N − 1): N! = N * (N − 1)!.

O exemplo da Figura 9.31 deixa bem claros o critério de parada e o parâmetro da chamada recursiva na função recursiva implementada em linguagem C.

Exemplo: fatorial 01 02 03 04 05 06

int fatorial (int n){

if(n == 0) //critério de parada

return 1;

else //parâmetro do fatorial sempre muda

return n*fatorial(n – 1);

}

F I G U R A 9 . 3 1

Note que a implementação da função recursiva do fatorial em linguagem C segue exatamente o que foi definido matematicamente.

Algoritmos recursivos tendem a necessitar de mais tempo e/ou espaço do que algoritmos iterativos.

Sempre que chamamos uma função, é necessário espaço de memória para armaze- nar os parâmetros, variáveis locais e endereço de retorno da função. Em uma função recursiva, essas informações são armazenadas para cada chamada da recursão, sendo, portanto, a memória necessária para armazená-las proporcional ao número de cha- madas da recursão. Por exemplo, para calcular o fatorial do número 4 são necessárias cinco chamadas da função fatorial.

Além disso, todas essas tarefas de alocar e liberar memória, copiar informações etc. envolvem tempo computacional, de modo que uma função recursiva gasta mais tempo que sua versão iterativa (sem recursão).

Outro exemplo clássico de recursão é a sequência de Fibonacci: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …

A sequência de Fibonacci é definida como uma função recursiva utilizando a fór- mula a seguir:

0, se n = 0

F(n) = 1, se n = 1

F(n – 1) + F(n – 2), outros casos

O exemplo da Figura 9.32 apresenta as funções com e sem recursão para o cálculo da sequência de Fibonacci.

Exemplo: sequência de Fibonacci

Com recursão Sem recursão

01 02 03 04 05 06 07 08 09 int fibo(int n){ if(n == 0 || n == 1) return n; else

return fibo(n-1) + fibo(n-2); } int fibo(int n){ int i,t,c,a=0, b=1; for(i=0;i<n;i++){ c = a + b; a = b; b = c; } return a; } F I G U R A 9 . 3 2

Funções 193

Como se nota, a solução recursiva para a sequência de Fibonacci é muito elegante. Infelizmente, ela contém duas chamadas para si mesma. Isso significa que ela contém duas chamadas recursivas. Logo, sua elegância não significa eficiência, como se verifica na Figura 9.33. fibo(4) fibo(3) fibo(2) fibo(2) 2 1 1 1 1 1 0 0 fibo(1) fibo(1) fibo(1) fibo(0) fibo(0) F I G U R A 9 . 3 3

Nessa figura, as setas inteiras indicam quando uma nova chamada da função é reali- zada, enquanto as setas tracejadas indicam o processo inverso, ou seja, quando a função passa a devolver para quem a chamou o valor do comando return. O maior problema dessa solução recursiva está nas caixas pontilhadas. Neles, fica claro que parte do cál- culo é realizada duas vezes pelas duas chamadas recursivas: um grande desperdício de tempo e espaço!

Se, em vez de calcularmos fibo(4), quisermos calcular fibo(5), teremos um desper- dício ainda maior de tempo e espaço, como mostra a Figura 9.34.

fibo(4) fibo(5) fibo(3) fibo(3) fibo(2) fibo(2) fibo(2) 2 3 2 1 1 1 1 1 1 1 0 1 0 0 fibo(1) fibo(1) fibo(1) fibo(1) fibo(1) fibo(0) fibo(0) fibo(0) F I G U R A 9 . 3 4

Por esse motivo, deve-se ter muito cuidado com o uso da recursão na programação.

Recursão é realmente um tópico difícil de entender em programação. Para compreender melhor, leia a Seção 9.3.

9.4 EXERCÍCIOS

9.4.1 Passagem por valor

1) Escreva uma função que receba por parâmetro dois números e retorne o maior deles.

2) Faça uma função que receba um número inteiro de 1 a 12 e imprima em tela o mês e a sua quantidade de dias de acordo com o número digitado pelo usuário. Exemplo: Entrada = 4. Saída = abril.

3) Escreva uma função que receba por parâmetro uma temperatura em graus Fahrenheit e a retorne convertida em graus Celsius. A fórmula de conversão é: C = (F – 32.0) * (5.0/9.0), sendo F a temperatura em Fahrenheit e C a temperatura em Celsius. 4) Escreva uma função que receba por parâmetro a altura e o raio de um cilindro

circular e retorne o volume desse cilindro. O volume de um cilindro circular é calculado por meio da seguinte fórmula:

V = π * raio2 * altura,

em que π = 3.1414592

5) Escreva uma função para o cálculo do volume de uma esfera V = 4/3π * r3,

em que π = 3.1414592 valor do raio r deve ser passado por parâmetro.

6) Escreva uma função que receba o peso (quilos) e a altura (metros) de uma pessoa. Calcule e retorne o IMC (índice de massa corporal) dessa pessoa:

IMC = peso/(altura * altura)

7) Elabore uma função que receba três números inteiros como parâmetro, represen- tando horas, minutos e segundos. A função deve retornar esse horário convertido em segundos.

8) Elabore uma função para verificar se um número é um quadrado perfeito. Um quadrado perfeito é um número inteiro não negativo que pode ser expresso como o quadrado de outro número inteiro. Exemplos: 1, 4, 9.

9) Elabore uma função que receba três notas de um aluno como parâmetros e uma letra. Se a letra for “A”, a função deverá calcular a média aritmética das notas do aluno; se for “P”, deverá calcular a média ponderada, com pesos 5, 3 e 2. Retorne a média calculada para o programa principal.

10) Escreva uma função que receba dois valores numéricos e um símbolo. Esse sím- bolo representará a operação que se deseja efetuar com os números. Assim, se o

Funções 195

símbolo for “+”, deverá ser realizada uma adição, se for “−”, uma subtração, se for “/”, uma divisão, e, se for “*”, será efetuada uma multiplicação. Retorne o resulta- do da operação para o programa principal.

11) Escreva uma função que receba por parâmetros dois valores inteiros x e y e calcule e retorne o resultado de x y para o programa principal. Não use nenhuma função pronta para isso.

12) Escreva uma função que receba um número inteiro positivo e retorne o maior fator primo desse número.

13) Escreva uma função que receba um número inteiro positivo n. Calcule e retorne o somatório de 1 até n: 1 + 2 + 3 + ... + n.

14) Escreva uma função que receba um número inteiro positivo n. Calcule e retorne o seu fatorial n!: n! = n * ( – 1) * (n – 2) * ... * 1.

15) Elabore uma função que receba como parâmetro um valor inteiro n e gere como saída n linhas com pontos de exclamação, conforme o exemplo a seguir, em que usamos n = 5: ! !! !!! !!!! !!!!!

16) Elabore uma função que receba como parâmetro um valor inteiro n e gere como saída um triângulo lateral formado por asteriscos conforme o exemplo a seguir, em que usamos n = 4: * ** *** **** *** ** *

17) Faça uma função que receba um inteiro N como parâmetro. Calcule e retorne o resultado da seguinte série S:

18) Faça uma função que receba como parâmetro o valor de um ângulo em graus e calcule o valor do seno desse ângulo usando a sua respectiva série de Taylor:

em que x é o valor do ângulo em radianos. Considere π = 3.1414592 e n variando de 0 até 5.

19) Faça uma função que receba como parâmetro o valor de um ângulo em graus e calcule o valor do cosseno desse ângulo usando a sua respectiva série de Taylor:

em que x é o valor do ângulo em radianos. Considerar π = 3.1414592 e n variando de 0 até 5.

20) Faça uma função que calcule e retorne o número neperiano e, e = 2,71828183, usando a série a seguir:

A função deve ter como parâmetro o número de termos que serão somados, N. Note que quanto maior esse número, mais próxima do valor e estará a resposta.

9.4.2 Passagem por referência

1) Escreva uma função que, dado um número real passado como parâmetro, retorne a parte inteira e a parte fracionária desse número por referência.

2) Escreva uma função para o cálculo do volume e área de uma esfera V = 4/3 π + r3,

A = 4 π * r2

em que π = 3.1414592. O valor do raio r deve ser passado por parâmetro, e os valores calculados devem ser retornados por referência.

3) Escreva uma função que receba um array de 10 elementos e retorne a sua soma. 4) Escreva uma função que receba um array contendo a nota de 10 alunos e retorne

Funções 197

5) Escreva uma função que calcule o desvio-padrão d de um vetor V contendo n números

em que m é a média desse vetor.

6) Crie uma função que receba uma matriz A contendo cinco linhas e cinco colunas. Calcule na própria matriz A a sua transposta (se B é a matriz transposta de A, então A[i][j] = B[j][i]).

7) Crie uma função que receba uma matriz A contendo 10 linhas e 10 colunas e retorne a soma dos seus elementos.

8) Faça uma função que receba, por parâmetro, uma matriz A contendo seis linhas e seis colunas. Essa função deve retornar, por referência, a soma dos elementos da sua diagonal principal e da sua diagonal secundária.

9) Crie uma estrutura representando um aluno de uma disciplina. Essa estrutura deve conter o número de matrícula do aluno, seu nome e as notas de três provas. Agora, escreva uma função que receba um vetor de tamanho N dessa estrutura. Essa função deve retornar o índice do aluno que possui a maior média geral entre todos os alunos.

10) Escreva uma função que receba uma string e retorne se ela é um palíndromo (1) ou não (0). Um palíndromo é uma palavra que tem a propriedade de poder ser lida tanto da direita para a esquerda como da esquerda para a direita. Exemplos: ovo, arara, rever, asa, osso etc.

11) Escreva uma função que receba uma string e converta todos os seus caracteres em maiúscula. Dica: subtraia 32 dos caracteres cujo código ASCII está entre 97 e 122.

12) Escreva uma função que receba como parâmetro um vetor contendo N valores in- teiros. Essa função deve retornar, por referência, dois valores: a soma dos números pares e ímpares.

13) Crie uma função que receba um vetor de tamanho N e ordene os seus valores. 14) Elabore uma função que receba por parâmetros os coeficientes de uma equação do

segundo grau. Em seguida, calcule e mostre as raízes dessa equação. Lembre-se de que as raízes são calculadas como

em que Δ = b2 – 4 * a * c e ax2 + bx + c = 0 representa uma equação do segun-

mensagem “Não é equação de segundo grau” e retorne o valor −1. Do contrário, retorne o número de raízes e as raízes (por referência) se elas existirem:

Se

• Δ < 0, não existe real. Número de raízes: 0. Se

• Δ = 0, existe uma raiz real. Número de raízes: 1. Se

• Δ > 0, existem duas raízes reais. Número de raízes: 2

15) Elabore uma função que receba um vetor contendo N valores e retorne por refe- rência o maior e o menor elemento desse vetor.

16) Elabore uma função que receba um vetor contendo N valores e retorne por refe- rência o maior elemento do vetor e o número de vezes que esse elemento ocorreu no vetor.

9.4.3 Recursão

1) Escreva uma função recursiva que calcule a soma dos primeiros n cubos: S = 13 + 23 + ... + n3

2) Crie uma função recursiva que receba um número inteiro N e retorne o somatório dos números de 1 a N.

3) Crie uma função recursiva que receba um número inteiro N e imprima todos os números naturais de 0 até N em ordem crescente.

4) Crie uma função recursiva que receba um número inteiro N e imprima todos os números naturais de 0 até N em ordem decrescente.

5) Crie uma função recursiva que retorne a soma dos elementos de um vetor de in- teiros.

6) Crie uma função recursiva que retorne a média dos elementos de um vetor de inteiros.

7) Escreva uma função recursiva que receba por parâmetro dois valores inteiros x e y e calcule e retorne o resultado de xy para o programa principal.

8) A multiplicação de dois números inteiros pode ser feita através de somas sucessivas (por exemplo, 2 * 3 = 2 + 2 + 2). Crie uma função recursiva que calcule a multi- plicação por somas sucessivas de dois inteiros.

9) Escreva uma função recursiva que receba um número inteiro positivo n. Calcule e retorne o seu fatorial n!:

n! = n * (n – 1) * (n – 2) * ... * 1

10) Escreva uma função recursiva que receba um número inteiro, maior ou igual a zero, e retorne o enésimo termo da sequência de Fibonacci. Essa sequência começa

Funções 199

no termo de ordem zero e, a partir do segundo termo, seu valor é dado pela soma dos dois termos anteriores. Alguns termos dessa sequência são: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34.

11) Escreva uma função recursiva que receba um valor inteiro e o retorne invertido. Exemplo:

Número lido = 123. Número retornado = 321.

12) Escreva uma função recursiva que receba um valor inteiro em base decimal e o imprima em base binária.

13) Faça uma função recursiva que calcule o valor da série S descrita a seguir para um valor n maior do que zero a ser fornecido como parâmetro para a mesma:

14) Crie uma função recursiva que retorne o menor elemento em um vetor.

15) Em matemática, o número harmônico designado por Hn define-se como o enési- mo termo da série harmônica. Ou seja:

Ponteiros

A

finalidade deste capítulo é apresentar o conceito de ponteiros dentro da lingua- gem C. Ao final, o leitor será capaz de:

Declarar um ponteiro. •

Diferenciar um ponteiro de uma variável comum. •

Associar o ponteiro a um endereço de memória. •

Associar o ponteiro a um endereço de memória inexistente. •

Acessar o conteúdo apontado por um ponteiro. •

Realizar operações com ponteiros. •

Utilizar ponteiros genéricos. •

Entender a relação dos ponteiros com os arrays. •

Utilizar o conceito de ponteiro para ponteiro. •

10.1 DEFINIÇÃO

Toda informação que manipulamos dentro de um programa (esteja ela guardada em uma variável, array, estrutura etc.) obrigatoriamente está armazenada na memória do computador. Quando criamos uma variável, o computador reserva um espaço de memória onde podemos guardar o valor associado a ela. Ao nome que damos a ela o computador associa o endereço do espaço que ele reservou na memória para guardá-la. De modo geral, interessa ao programador saber o nome das variáveis. Já o computador precisa saber onde elas estão na memória, ou seja, precisa dos seus endereços.

Ponteiros são um tipo especial de variáveis que permitem armazenar endereços de memória em vez de dados numéricos (como os tipos int, float e double) ou caracteres (como o tipo char).

No documento Linguagem c Completa e Descomp (páginas 191-200)

Documentos relacionados