Capítulo 8 Programação imperativa 8.1 Exercícios de revisão 1. Distinga entre programação imperativa e programação funcional. 2. Explique a necessidade da introdução do operador de atribuição. 3. Diga qual é a diferença entre o operador de atribuição e o operador de nomeação. 4. Diga quais são as vantagens e os inconvenientes da programação imperativa. 5. Diga o que é um efeito. Qual é o comportamento de um procedimento baseado em efeitos? 6. Quando é que se diz que um objecto tem estado? O que caracteriza o estado de um objecto? 7. Explique a diferença entre o método de passagem de parâmetros por valor e por referência. Explique estes dois métodos com exemplos em Scheme. 8.2 Exercícios de programação 1. (2) Diga o que é escrito pelo interpretador de Scheme ao avaliar cada uma das seguintes expressões. Suponha que as expressões são avaliadas pela ordem apresentada. Se a avaliação de uma expressão originar um erro, explique a razão do erro. (define x 5) (set! x "FP") (set! b 2) (vector x b 5 (* 3 2)) (define a 3) (set! a "ola") (+ a 1) a a 79
80 CAPÍTULO 8. PROGRAMAÇÃO IMPERATIVA 8.2.1 Ciclos 1. (2) Utilizando programação imperativa e um ciclo apropriado, escreva um procedimento chamado potencia que recebe dois inteiros, x e n, e que devolve x n. 2. (2) Considere o algoritmo de Euclides para calcular o máximo divisor comum entre dois inteiros: (1) o máximo divisor comum entre um número e zero é o próprio número; (2) quando dividimos um número por um menor, o máximo divisor comum entre o resto da divisão e o divisor é o mesmo que o máximo divisor comum entre o dividendo e o divisor. Usando programação imperativa e o ciclo apropriado, escreva um procedimento chamado mdc para calcular o máximo divisor comum entre dois números utilizando o algoritmo de Euclides. 3. (2) Utilizando programação imperativa e um ciclo apropriado, escreva um procedimento chamado raiz que calcula a raiz quadrada de um número positivo utilizando o algoritmo de Heron de Alexandria (ver a sua descrição nas páginas 66 a 70 do livro). 4. (2) Considere o procedimento somatorio apresentado na Página 204 do livro: (define (somatorio calc-termo lim-inf proximo lim-sup) (if (> lim-inf lim-sup) 0 (+ (calc-termo lim-inf) (somatorio calc-termo (proximo lim-inf) proximo lim-sup)))) Escreva este procedimento utilizando programação imperativa e um ciclo apropriado. 8.2.2 Listas 1. (2) Usando o ciclo mais adequado, escreva um procedimento cria-lista-inteiros que recebe um número inteiro positivo n e devolve uma lista com os números inteiros entre 0 e n. > (cria-lista-inteiros 5) (0 1 2 3 4 5) 2. (2) Usando o ciclo mais adequado, escreva um procedimento soma-elementos-lista que recebe uma lista de números e devolve a soma dos elementos da lista. > (soma-elementos-lista (0 1-2 3-4 5)) 3 3. (2) Usando o ciclo mais adequado, escreva um procedimento algum-satisfaz-lista que recebe uma lista e um predicado e devolve verdadeiro de algum dos elementos da lista satisfizer o predicado e falso em caso contrário.
8.2. EXERCÍCIOS DE PROGRAMAÇÃO 81 > (algum-satisfaz-lista (0 1 2 3 4 5) even?) > (algum-satisfaz-lista (0 1 2 3 4 5) (lambda (x) (> x 10))) 4. (2) Usando o ciclo mais adequado, escreva um procedimento quantos-satisfazem-lista que recebe uma lista e um predicado e devolve o número de elementos da lista que satisfazem o predicado. > (quantos-satisfazem-lista (0 1 2 3 4 5) even?) 3 > (quantos-satisfazem-lista (0 1 2 3 4 5) (lambda (x) (> x 10))) 0 5. (2) Usando o ciclo mais adequado, escreva um procedimento aplica-proc-lista que recebe uma lista e um procedimento e devolve uma lista que resulta de aplicar o procedimento a cada um dos elementos da lista original. > (aplica-proc-lista (0 1 2 3 4 5) sqr) (0 1 4 9 16 25) > (aplica-proc-lista (0 1 2 3 4 5) (lambda (x) (> x 10))) ( ) 6. (2) Usando o ciclo mais adequado, escreva um procedimento escolhe-pred-lista que recebe uma lista e um predicado e devolve uma lista que contém os elementos da lista original que satisfazem o predicado. > (escolhe-pred-lista (0 1 2 3 4 5) odd?) (1 3 5) > (escolhe-pred-lista (0 1 2 3 4 5) (lambda (x) (> x 10))) () 8.2.3 vectores 1. (2) Escreva um procedimento produto-vector que recebe um vector e devolve o produto de todos os elementos do vector. > (produto-vector (vector 4 5 6)) 120 > (produto-vector (vector)) 1 2. (2) Escreva um procedimento de ordem superior chamado transforma-vector! que recebe como argumentos um vector e uma operação aplicável aos elementos do vector e que modifica destrutivamente o vector recebido, aplicando a operação a cada um dos elementos do vector original. Por exemplo,
82 CAPÍTULO 8. PROGRAMAÇÃO IMPERATIVA > (define v1 (vector 2 4 6 8)) > (escreve-vector v1) [2 4 6 8] > (transforma-vector! v1 (lambda (x)(/ x 2.0))) > (escreve-vector v1) [1.0 2.0 3.0 4.0] (a) Utilize o ciclo do. (b) Utilize o ciclo dotimes. 3. (2) Utilizando o procedimento transforma-vector!, escreva uma combinação que dado um vector altera destrutivamente o vector original de modo a que cada posição passe a ter o quadrado do elemento que estava nessa posição do vector original. 4. (2) Escreva um procedimento conta-pares-vector que recebe um vector e devolve o número de elementos pares no vector. > (conta-pares-vector (vector 4 5 6)) 2 > (conta-pares-vector (vector 3 5 7)) 0 5. (2) Escreva um procedimento numero-ocorrencias-vector que recebe um vector e um número, e devolve o número de vezes que o número ocorre no vector. > (numero-ocorrencias-vector (vector 4 5 6) 5) 1 > (numero-ocorrencias-vector (vector 3 5 7) 2) 0 6. (2) Escreva um procedimento conta-vector que recebe um vector e um predicado unário, e devolve o número de elementos do vector que satisfazem o predicado. > (conta-vector (vector 4 5 6) (lambda(x) (> x 5))) 1 7. (2) Escreva os procedimentos dos exercícios 4 e 5 utilizando o procedimento conta-vector. 8. (2) Escreva um procedimento maximo-vector que recebe um vector não vazio de números e devolve o maior elemento do vector. > (maximo-vector (vector 4 5 6)) 6 > (maximo-vector (vector 7 3 6)) 7 9. (2) Escreva um procedimento todos-pares-vector? que recebe um vector e devolve verdadeiro se o vector for constituído exclusivamente por números pares e falso em caso contrário.
8.2. EXERCÍCIOS DE PROGRAMAÇÃO 83 > (todos-pares-vector? (vector 4 5 6)) > (todos-pares-vector? (vector 4 4 6)) 10. (2) Escreva um procedimento todos-vector? que recebe um vector e um predicado unário, e devolve verdadeiro caso todos os elementos do vector satisfaçam o predicado e falso em caso contrário. > (todos-vector? (vector 4 5 6) (lambda(x) (> x 5))) > (todos-vector? (vector 4 5 6) (lambda(x) (>= x 4))) 11. (2) Escreva o procedimento do exercício 9 utilizando o procedimento todos-vector?. 12. (2) Escreva um procedimento ocorre-vector? que recebe um vector e um número, e devolve verdadeiro se o número ocorrer no vector e falso em caso contrário. > (ocorre-vector? (vector 3 2 4) 3) > (ocorre-vector? (vector 3 2 4) 1) 13. (2) Escreva um procedimento existe-vector? que recebe um vector e um predicado unário, e devolve verdadeiro caso exista um elemento do vector que satisfaça o predicado e falso em caso contrário. > (existe-vector? (vector 4 5 6) (lambda(x) (> x 5))) > (existe-vector? (vector 4 5 6) (lambda(x) (>= x 4))) 14. (2) Escreva o procedimento do exercício 12 utilizando o procedimento existe-vector?. 15. (2) Escreva um procedimento quadrados-vector! que recebe um vector, e altera destrutivamente o vector original de modo a que cada posição passe a ter o quadrado do elemento que estava nessa posição do vector original. > (quadrados-vector! (vector 3 2 4)) #(9 4 16) 16. (2) Escreva um procedimento substitui-vector! que recebe um vector, um número v e um número n, e altera destrutivamente o vector substituindo todas as ocorrências de v por n. > (substitui-vector! (vector 4 3 2 4) 4 5) #(5 3 2 5)
84 CAPÍTULO 8. PROGRAMAÇÃO IMPERATIVA 17. (2) Escreva um procedimento aplica-f-vector! que recebe um vector v e um procedimento unário f, e altera destrutivamente o vector original aplicando o procedimento a cada um dos elementos do vector. > (aplica-f-vector! (vector 4 3 2 4) (lambda(x) (- x 1))) #(3 2 1 3) > (aplica-f-vector! (vector 4 3 2 4) (lambda(x) (>= x 4))) #( ) 18. (2) Escreva os procedimentos dos exercícios 15 e 16 utilizando o procedimento aplica-f-vector!. 19. (2) Escreva um procedimento inverte-vector que recebe um vector, e devolve um novo vector que resulta de inverter o vector original. > (inverte (vector 3 2 4)) #(4 2 3) 20. (2) Escreva um procedimento vector-simetrico! que recebe como argumento um vector e que altera esse vector trocando os elementos nas posições simétricas em relação ao elemento que se encontra no centro do vector. > (vector-simetrico (vector 3 2 4)) #(4 2 3) 21. (2) Escreva um procedimento junta-vectores que recebe dois vectores, e devolve o vector que resulta de juntar o segundo vector ao final do primeiro. > (junta-vectores (vector 3 2 4) (vector 1 2 3)) #(3 2 4 1 2 3) > (junta-vectores (vector) (vector 4 5 3)) #(4 5 3) 22. (2) Escreva um procedimento selecciona-pares-vector que recebe um vector, e devolve o vector com todos os números pares do vector original. > (selecciona-pares-vector (vector 4 3 2 4)) #(4 2 4) > (selecciona-pares-vector (vector 7 3 5)) #() 23. (2) Escreva um procedimento selecciona-menores-vector que recebe um vector e um número n, e devolve o vector com todos os números do vector original menores que n. > (selecciona-menores-vector (vector 4 3 2 4) 4) #(3 2) > (selecciona-menores-vector (vector 7 3 5) 1) #()
8.2. EXERCÍCIOS DE PROGRAMAÇÃO 85 24. (2) Escreva um procedimento selecciona-primos-vector que recebe um vector, e devolve o vector com todos os números primos do vector original. > (selecciona-primos-vector (vector 4 3 2 4)) #(3 2) > (selecciona-primos-vector (vector 4 6 8 9)) #() 25. (2) Escreva um procedimento remove-elemento-vector que recebe um vector e um número n, e devolve o vector que resulta de remover todas as ocorrências do número n do vector original. Sugestão: utilize o procedimento numero-ocorrencias-vector do exercício 5. > (remove-elemento-vector (vector 4 3 2 4) 4) #(3 2) > (remove-elemento-vector (vector 7 3 5) 1) #(7 3 5) 26. (2) Escreva um procedimento filtra-vector que recebe um vector v e um predicado p, e devolve o vector que resulta de ficar com todos os elementos do vector v que satisfazem o predicado p. Sugestão: utilize o procedimento conta-vector definido no exercício 6. > (filtra-vector (vector 4 3 2 1 4) (lambda(x) (< 1 x 4))) #(3 2) 27. (2) Escreva os procedimentos dos exercícios 22, 23, 24 e 25 utilizando o procedimento filtra-vector. 28. (2) Escreva um procedimento posicao-vector que recebe um vector e um número, e devolve a posição da primeira ocorrência desse número no vector. Caso o número não ocorra no vector deverá devolver falso. > (posicao-vector (vector 4 3 2 2 1 4) 4) 0 > (posicao-vector (vector 4 3 2 2 1 4) 1) 4 > (posicao-vector (vector 4 3 2 2 1 4) 6) 29. (2) Escreva um procedimento posicoes-vector que recebe um vector e um número, e devolve a lista de todas as posições em que o número ocorre no vector. > (posicoes-vector (vector 4 3 2 2 1 4) 4) (0 5) > (posicoes-vector (vector 4 3 2 2 1 4) 6) ()
86 CAPÍTULO 8. PROGRAMAÇÃO IMPERATIVA 30. (2) Escreva um procedimento posicoes-dos-pares-vector que recebe um vector, e devolve a lista de todas as posições do vector em que ocorrem números pares. > (posicoes-dos-pares-vector (vector 4 3 2 2 1 4)) (0 2 3 4) > (posicoes-dos-pares-vector (vector 5 3 5 3 1)) () 31. (2) Escreva um procedimento posicoes-p-vector que recebe um vector e um predicado, e devolve a lista de todas as posições em que o elemento do vector satisfaz o predicado. > (posicoes-p-vector (vector 4 3 2 2 1 4) (lambda(x) (< x 3))) (2 3 4) > (posicoes-p-vector (vector 4 3 2 2 1 4) (lambda(x) (> x 4))) () 32. (2) Escreva os procedimentos dos exercícios 29 e 30 utilizando o procedimento posicoes-p-vector. 33. (2) Escreva um procedimento ordenado-vector? que recebe um vector de números, e devolve verdadeiro se o vector estiver ordenado de forma crescente e falso em caso contrário. > (ordenado-vector? (vector 3 2 1 2 3)) > (ordenado-vector? (vector 3 5 7 8)) 34. (2) Escreva um procedimento capicua-vector? que recebe um vector, e devolve verdadeiro se o vector for uma capicua e falso em caso contrário. > (capicua-vector? (vector 3 2 1 2 3)) > (capicua-vector? (vector 3 2 2 3)) > (capicua-vector? (vector 3 2 1 3 2 3)) 35. (2) Escreva um procedimento remove-duplicados-vector que recebe um vector v, e devolve a lista que resulta de ficar apenas com a primeira cópia de cada elemento de v. > (remove-duplicados-vector (vector 4 3 2 2 1 4)) (4 3 2 1) > (remove-duplicados-vector (vector 7 5 3 4 6 2)) (7 5 3 4 6 2) 36. (2) Escreva um procedimento elementos-repetidos-vector que recebe um vector, e devolve a lista com uma cópia de cada elemento que aparece repetido no vector.
8.2. EXERCÍCIOS DE PROGRAMAÇÃO 87 > (elementos-repetidos-vector (vector 3 4 4 4 3 6 7)) (3 4) > (elementos-repetidos-vector (vector 3 4 6 7)) () 37. (2) Defina um procedimento aplica que recebe como argumentos um vector e uma função, e devolve o resultado de aplicar essa função à soma dos elementos do vector. 38. (2) Defina um procedimento aplica-talvez! que recebe como argumentos um vector, um elemento, e um procedimento de um argumento, e que altera destrutivamente cada elemento do vector que não seja igual ao elemento recebido para o resultado produzido pelo procedimento recebido aplicado ao elemento do vector. > (define v (vector 1 2 3 4)) > v #(1 2 3 4) > (aplica-talvez! v 3 sqr) > v #(1 4 3 16) 39. (2) Defina um procedimento ocorre-par que recebe um vector e um objecto e devolve verdadeiro se o vector contiver esse objecto um número par de vezes e falso em caso contrário. Considere que 0 é um número par. > (ocorre-par (vector 1 2 3 4) 2) > (ocorre-par (vector 1 2 3 2) 2) 40. (2) Defina um procedimento vector->lista que recebe um vector e devolve uma lista com todos os elementos do vector. Pode utilizar as operações primitivas de listas e vectores que achar necessárias. > (vector->lista (vector 1 2 3 4)) (1 2 3 4) 41. (3) Um acumulador é um funcional que recebe como argumentos uma lista e uma operação aplicável aos elementos da lista, e aplica sucessivamente essa operação aos elementos da lista original, devolvendo o resultado da aplicação da operação a todos os elementos da lista, no caso de ela não ser vazia. Defina acumuladores não destrutivos para vectores e listas, nas versões recursivas e usando ciclos. 42. (3) O procedimento ocorre-vector? do exercício 12 tem que percorrer todos os elementos do vector no caso de estar a procurar um elemento que não existe no vector. (a) No caso de o elemento a procurar existir no vector, quantos elementos do vector, em média, serão percorridos?
88 CAPÍTULO 8. PROGRAMAÇÃO IMPERATIVA (b) Supondo que o vector está ordenado por ordem crescente, defina um nova versão do procedimento ocorre-vector? que efectua uma procura sequencial mas que não tenha que percorrer todos os elementos do vector quando o elemento a procurar não existe no vector. (c) Em média, quantos elementos do vector são percorridos quando o número não existe no vector? E quando existe? 43. (3) Sabendo que o vector está ordenado por ordem crescente, é possível realizar uma procura binária, que é mais eficiente que a procura sequencial do exercício anterior. Esta procura baseia-se no facto de que se compararmos o elemento a procurar com o elemento do meio do vector podemos obter um de três resultados diferentes: 1) os dois elementos são iguais, o que significa que encontrámos o elemento que procurávamos; 2) o elemento do meio é menor, o que significa que o elemento que procuramos, se existir, estará na metade do vector com índices maiores; 3) o elemento do meio é maior, o que significa que o elemento que procuramos, se existir, estará na metade do vector com índices menores. Defina o procedimento procura-binaria-vector que realiza uma procura binária num vector. Qual a ordem de crescimento deste procedimento?