apuntes - dit/UPM

Anuncio
Fundamentos de
Programación
Tema 5:
Estructuras de Control
Dpto. de Ingeniería de Sistemas Telemáticos
http://www.lab.dit.upm.es/~fprg/fprg.html
oct-07
1
Indice
Orden de Ejecución, Programación Estructurada
Alternativas
if
switch
Estructuras repetitivas
while
do ... while
for
Ruptura de secuencia
Saltos: break y continue
Excepciones (throw)
Recursividad
oct-07
2
Programación estructurada
Una forma de estructurar los programas para
que no sean un laberinto, sino algo fácil de
entender por uno mismo y por los demás
La idea fundamental es que los programas son
un conjunto de bloques que encajan entre sí
sobre la premisa de que cada bloque tiene un
sólo punto de entrada y un sólo punto de salida,
y la salida de uno se enchufa a la entrada del
siguiente
o sea, un lego
oct-07
3
1
Secuencias y bloques
{
sentencia 1;
// un bloque
sentencia
sentencia
sentencia
sentencia
... ... ...
sentencia
sentencia 2;
sentencia 3;
sentencia 4;
1;
2;
3;
4;
n;
}
el “;” es terminador
sentencia n;
oct-07
4
Ejecución condicional
true
condición
false
sentencia;
private int monedas
(int aDevolver, int valor) {
int cuantas= aDevolver / valor;
if (cuantas > 0)
System.out.println
(cuantas + " de " + valor);
return aDevolver % valor;
}
oct-07
5
¿Hay que poner llaves?
Caso de duda, póngase
if (condición)
sentencia1;
sentencia2;
sentencia3;
se entiende como
if (condición)
sentencia1;
sentencia2;
sentencia3;
que no es lo mismo que
if (condición) {
sentencia1;
sentencia2;
sentencia3;
}
oct-07
6
2
Ejecución condicional
public static void main (String args[]) {
if (args.length != 2) {
System.out.println
("uso: java MaquinaCambio precio entrego");
System.exit(1);
}
MaquinaCambio panaderia= new MaquinaCambio();
panaderia.daCambio(Integer.parseInt(args[0]),
Integer.parseInt(args[1]));
}
oct-07
7
Ejecución condicional
true
condición
false
sentencia 2;
if (hora < 14)
System.out.println
(“buenos dias”);
else
System.out.println
(“buenas tardes”);
sentencia 1;
oct-07
8
Ambigüedad
if (a) if (b) S1; else S2;
significa
if (a) { if (b) S1; else S2; }
oct-07
9
3
Selección múltiple
true
expr=val1
sentencia1;
false
true
expr=val2
sentencia2;
false
...
false
true
expr=valN
if (mes == 1)
...print(“enero”);
else if (mes == 2)
...print(“febrero”);
else if (mes == 3)
...print(“marzo”);
...
...
else
...print(“no se”);
sentenciaN;
false
sentenciaD;
¡¡La expresión se evalúa N
veces!!
Efectos laterales
oct-07
10
Selección múltiple
if (mes == 1)
...print(“enero”);
else if (mes == 2)
...print(“febrero”);
else if (mes == 3)
...print(“marzo”);
...
...
else
...print(“no se”);
switch (mes) {
case 1:
...print(“enero”);
break;
case 2:
...print(“febrero”);
break;
...
default:
...print(“no se”);
oct-07
11
Selección múltiple
switch (mes) {
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
System.out.println(“31 dias”); break;
case 4: case 6: case 9: case 11:
System.out.println(“30 dias”); break;
case 2:
if (bisiesto) System.out.println(“29 dias”);
else System.out.println(“28 dias”);
break;
default:
System.out.println(“no se”);
}
oct-07
12
4
Sentencias switch
Sólo funcionan sobre enteros, booleanos o
caracteres
¿por qué?
Chequean que no hay duplicados
las condiciones tienen que ser excluyentes
Mejor legibilidad
Sin “break”, el programa no saltaría al final
El “default” es opcional
oct-07
13
Bucles
Se repite una acción N veces
modelo while
se repite 0 o más veces
modelo hasta
se repite 1 o más veces
modelo for
se repite un número determinado de veces
oct-07
14
while
condición
true
sentencia;
while (!aprobado)
me.examino();
false
int n= ...;
int fact= 1;
while (n > 0) {
fact*= n;
n--;
}
oct-07
while (hace.sol())
me.banno();
15
5
do { ... } while
int i;
double e, ei;
i= 0;
ei= 1;
e= ei;
sentencia;
condición
true
do {
i++;
ei= ei/i;
e= e+ei;
System.out.println ("e= " + e);
} while (ei > 1e-10);
false
oct-07
16
for
for (int i= 0; i < 10; i++)
...print(i);
inicialización;
actualización;
condición
false
true
acción;
for (int i= 10; i > 0; i--)
...print(i);
int n= ...;
int fact= 1;
for (n= 5; n > 0; n--)
fact*= n;
oct-07
17
Ejemplo
Imprimir argumentos de línea de llamada
class ImprimeArgumentos {
public static void main (String args[]) {
for (int i=0; i < args.length; i++) {
System.out.print (“argumento “ + i);
System.out.println(“: “ + args[i]);
}
}
}
oct-07
18
6
Variables de control
Se puede inicializar cualquier número de
variables del mismo tipo
for (int i= 0, j= 10; i < 9 && j > 0; i++, j--)
acción ;
Si estaba declarada antes, al acabar el for
queda con el valor final
Si se declara en el for, sólo existe en el bucle,
por lo tanto su valor no podrá ser usado fuera
La inicialización, condición y actualización son
opcionales (¡ojo!)
oct-07
19
Elección de estructura
1. Si nº fijo de veces, elegir for
2. Si 1 ó más veces, elegir do { } while ();
3. Si 0 ó más veces, elegir while () {}
se trata de elegir la que mejor se ajuste al
concepto para mejorar la legibilidad
oct-07
20
Ruptura
La secuencia de control de un programa se puede
romper de tres maneras:
saltos (break)
bucle parcial (continue)
excepciones (Exception)
Saltos: permiten alterar el flujo de control en los
bucles y en switch
Bucle parcial: no se ejecuta todo el bucle
Excepciones: alteran el flujo de control cuando se
produce un error en alguna parte del programa
oct-07
21
7
break
Vámonos directamente a la salida
Utilizable en {}, while, do/while, for y switch
int n= 0;
while (true) {
...print(n);
if (n == 5)
break;
n++;
}
for (int n= 0; ; n++)
if (n == 5)
break;
oct-07
22
continue
La secuencia continue, dentro de un bucle,
comienza inmediatamente la siguiente iteración
del ciclo
for (int n= 0; n < 100; n++) {
if (n % 2 == 0)
continue;
...print(n);
}
oct-07
23
Saltos etiquetados
break causa la salida del bucle más interno
(cercano), el que lo encierra directamente.
Para salirnos de una serie de estructuras anidadas de una
sola vez, podemos usar la sentencia break etiquetada
break bucleExterno;
continue sigue con la iteración del bucle que lo
encierra directamente
continue etiquetado salta el resto del cuerpo de esta
estructura y todas aquellas hasta seguir con la estructura
etiquetada
continue etiqueta;
oct-07
24
8
Errores frecuentes
Hacer una vez de más o de menos
Equivocarse en caso inicial o final
Probar casos extremos: condición que no se
satisface, sólo se satisface una vez,...
Comprobar que las variables están
correctamente inicializadas
No poner condiciones exactas: por exceso mejor
while (i != 10) ...
while (i < 10) ... // por si acaso
No poner condiciones == ni != sobre reales
oct-07
25
Excepciones (I)
Las excepciones ofrecen salidas de emergencia
de bucles
de llamadas a métodos
Se pretende que el programador se centre en el
comportamiento “normal” (si todo va bien)
y que la situación excepcional aborte
oct-07
26
Excepciones (II)
Se inventan unos objetos especiales
Se clasifican como throwable (arrojables)
Se pueden crear
new Exception();
new Exception(“me ha pasado esto”);
Se pueden lanzar
throw new Exception(“me rindo”);
Se pueden atrapar al vuelo
catch (Exception e) {
System.err.println(e);
}
oct-07
27
9
Excepciones (III)
Su activación interrumpe la ejecución secuencial
Se propagan hasta que son capturadas
interrumpe toda sentencia que no la capture
La ejecución continua si existe cláusula catch
que acepte la excepción activada
Pueden ser lanzadas por un programa
con la sentencia throw
el intérprete puede activarlas por su cuenta
oct-07
28
Ejemplo
public static void main (String[] arg)
throws Exception {
for (int a= 0; a < arg.length; a++) {
int n= Integer.parseInt(arg[a]);
System.out.println(100 / n);
}
}
Va dividiendo 100 por una serie de dividendos;
si un dividendo fuera 0: explota.
oct-07
29
Ejemplo
public static void main (String[] arg) {
for (int a= 0; a < arg.length; a++) {
try {
int n= Integer.parseInt(arg[a]);
System.out.println(100 / n);
} catch (Exception e) {
System.err.println (e);
}
}
}
Detecta la división por 0, avisa y sigue
oct-07
30
10
Ejemplo
public static void main (String[] arg) {
for (int a= 0; a < arg.length; a++) {
try {
int n= Integer.parseInt(arg[a]);
if (n == 0)
throw new Exception
(“no se dividir por 0”);
System.out.println(100 / n);
} catch (Exception e) {
System.err.println (e);
}
}
}
Detecta la división por 0, avisa y sigue
oct-07
31
try {...} catch (args) {...}
Si no se lanza nada, el catch como si no existiera
Dentro del try se lanza (throw) una excepción
Se olvida el resto del código
Se ejecuta lo que diga el catch
try {
...
throw new Exception();
...
} catch (Excepcion e) {
}
oct-07
32
try ... catch ... finally
Se puede añadir un trozo finally que se ejecuta
bien cuando acaba el código normal (try)
bien cuando acaba el código excepcional (catch)
... es decir, SIEMPRE se ejecuta; incluso si try lanza una
excepción que no captura ningún catch
oct-07
33
11
catch
try {
... ... ...
} catch (claseA ida) {
... ... ...
} catch (claseB idb) {
... ... ...
} catch (classC idc) {
... ... ...
Los diferentes catch se
intentan en el orden en
que aparecen hasta que
uno de ellos casa;
después de casar con
uno, los demás se olvidan
Casar significa que la
excepción a agarrar es de
la clase indicada o de una
clase extensión de ella
(aplicándose un
upcasting)
oct-07
34
finally
try {
... ... ...
throw new Exception();
... ... ...
} catch (Exception e) {
... ... ...
} finally {
... ... ...
}
try {
... ... ...
throw new Exception();
... ... ...
} catch (Exception e) {
... ... ...
} finally {
... ... ...
}
oct-07
35
Excepciones anidadas
Sólo puede haber una excepción “en el aire” en
un momento dado
Si un catch atrapa una excepción, ésta deja de
propagarse
El catch puede a su vez lanzar una excepción
La vieja
catch (Excepcion e) { ...; throw e; }
Una nueva
catch (Excepcion e) { ...; throw new Excepcion(“...”); }
oct-07
36
12
Métodos y excepciones
Un método puede, en su cuerpo, lanzar una
excepción con el ánimo de que sea recogida en
el exterior (por aquél que lo invocó)
Debe indicar en la cabecera que puede lanzar
una excepción
nótese que puede lanzarla o no
es una opción, no una obligación
metodo (argumentos) throws Exception {
...
throws new Exception();
...
}
oct-07
37
¿Cuándo usar excepciones?
Aunque es un mecanismo de control de flujo de
ejecución
conviene NO usarlo para programar lo que es normal
Conviene usarlo cuando hay que programar una
situación anómala
el que lo lea se pondrá en situación mental de
analizar una situación excepcional
oct-07
38
Jerarquía de excepciones
Throwable
Error
Error
Error
Exception
RuntimeException
RuntimeException
RuntimeException
del
delprogramador
programador
del programador
oct-07
39
13
Throwable
public class Throwable {
public Throwable ();
public Throwable (String mensaje);
public String toString ();
public void printStackTrace ();
public void printStackTrace
(java.io.PrintStream s);
public String getMessage ();
}
oct-07
40
Herederas
public class Error extends Throwable {
public Error ();
public Error (String mensaje);
}
public class Exception extends Throwable {
public Exception ();
public Exception (String mensaje);
}
oct-07
41
Obligación de declarar
Las excepciones de clase Exception y derivadas
deben declararse en la cabecera de los métodos que
las puedan lanzar
o capturadas (catch)
Las excepciones de clase Error y RuntimeError
van implícitas
oct-07
42
14
Recursividad
oct-07
43
Recursividad
Forma de cálculo equivalente a las
demostraciones por inducción
El resultado para N se calcula en función del
resultado para N-1 y así, recursivamente, hasta llegar
a un caso 0
n = 0, n = 1
1
f ( n) = 
n * f ( n − 1) n > 1
int fact (int n) throws Exception {
if (n < 0)
throw new Exception
(“argumento no válido”);
if ( (n == 0) || (n == 1) )
return 1;
else
return n * fact (n-1);
}
oct-07
44
Recursividad
Algunos problemas admiten una solución
recursiva muy sencilla de comprender y de
demostrar que es correcta matemáticamente
más legibles
caso básico + recursividad
oct-07
45
15
Ámbito dinámico (recursivo)
i=5
x=f(5)
if (i<=1)
5*f(4)
i=4
if (i<=1)
4*f(3)
i=1
...
return 5*24
x=120
if (i<=1)
return 1
return 4*6
oct-07
46
Ámbito dinámico (recursivo)
i=5
x=f(5)
if (i<=1)
5*f(4)
i=4
if (i<=1)
4*f(3)
i=1
...
return 5*24
x=120
if (i<=1)
return 1
return 4*6
oct-07
47
Contextos anidados
fact (5)
int n= 5
return n*fact(4)
fact (4)
int n= 4
return n*fact(3)
fact (3)
int n= 3
return n*fact(2)
fact (2)
int n= 2
return n*fact(1)
fact (1)
int n= 1
return 1
oct-07
48
16
Limitaciones
Si se crean muchísimos contextos, llega un
momento que no caben en memoria y se
produce desbordamiento
stack overflow
Ocurre
cuando el problema es demasiado grande para la
memoria del sistema
número de contextos * número de variables
cuando no converge al caso 0
error de diseño de la solución
oct-07
49
Fibonacci (I)
f ( 0) = 1
f (1) = 1
fib(4)
f (n) = f (n − 2) + f (n − 1)
int fib (int n) {
if (n < 2)
return 1;
return fib(n-1) + fib(n-2)
}
fib(3)
fib(2)
fib(1)
fib(2)
fib(1)
fib(1)
fib(0)
fib(0)
Solución recursiva
Matemáticamente impecable
Pero muy costosa en recursos
o sea, muy mala solución como ingeniería
oct-07
50
Fibonacci (II)
int fib (int n) {
return aux (1, 1, n);
}
fib(4)
aux(1, 1, 4)
private int aux (int n1, int n2, int n) {
if (n < 1)
return n1;
return aux(n2, n1+n2, n-1)
}
aux(1, 2, 3)
aux(2, 3, 2)
aux(3, 5, 1)
Recursión con acumulación:
solución económica en memoria
heap overflow
¿es más rápida?
oct-07
aux(5, 8, 0)
5
51
17
Fibonacci (III)
int fib (int n) {
int n1= 1;
int n2= 1;
for (int i= 0; i < n; i++) {
int s= n1 + n2;
n1= n2;
n2= s;
}
return n1;
}
solución iterativa
solución muy económica en memoria
¿es más rápida?
oct-07
52
Recursión e iteración
while (condición)
acción;
intercambiable
... función(..) {
if (!condición)
return;
acción;
función(...);
}
¿Qué solución es más rápida?
Pues depende de si gana la batalla la habilidad del programador
o la capacidad de optimización del compilador
Hay que medir en el laboratorio
Si quedan empatados, se elige la solución más legible
suele ganar el compilador: ¿piloto F1 o conductor normal?
oct-07
53
Torres de Hanoi
origen
auxiliar
destino
Torres de Hanoi:
Mover los discos del poste origen al destino
No se puede poner un disco mayor sobre otro menor
Sólo se mueve un disco a la vez
El poste restante se puede usar como auxiliar
oct-07
54
18
Torres de Hanoi
Solución iterativa compleja
Mejor solución recursiva:
mover n-1 discos de poste origen a poste auxiliar
mover un disco de origen a destino
mover n-1 discos de poste auxiliar a destino
oct-07
55
Torres de Hanoi
n-1
1
n-1
2
n-1
3
4
n-1
oct-07
56
Torres de Hanoi
class Hanoi {
public static void torres (int ndiscos, int orig,
int dest, int aux) {
if (ndiscos == 1) {
System.out.println (orig + “ ---> “ + dest);
return;
}
torres (ndiscos -1, orig, aux, dest);
System.out.println (orig + “ ---> “ + dest);
torres (ndiscos -1, aux, dest, orig);
}
public static void main (String[ ] args) {
System.out.println (“Cuantos discos: “);
int n = SimpleIO.readInt();
torres (n, 1, 3, 2);
}
}
oct-07
57
19
Descargar