Algoritmos y Estructuras de Datos I Auxiliares Definir funciones

Anuncio
Auxiliares
asignan un nombre a una expresión e
aux f (argumentos) : tipo = e;
Algoritmos y Estructuras de Datos I
f es el nombre.
los argumentos son opcionales; si están instancian variables de e.
Segundo cuatrimestre de 2011
tipo es el tipo del resultado de la expresión e.
e es la expresión nombrada por f .
Departamento de Computación - FCEyN - UBA
f puede usarse en la especificación en vez de la expresión e.
Especificación - clase 3
Ejemplo
aux suc(x : Int) : Int = x + 1;
Lenguaje de especificación
Se puede usar, por ejemplo, en la postcondición de un problema.
Las expresiones auxiliares facilitan la lectura y la escritura de
especificaciones. Funcionan como abreviaturas.
1
Definir funciones auxiliares vs. especificar problemas
2
Tipos enumerados
Definimos funciones auxiliares
I
son expresiones del lenguaje, de un cierto tipo
I
usamos la función dentro de las especificaciones
I
una función auxiliar puede estar definida mediante una o más
auxiliares.
I
tipo Nombre = constantes;
Especificamos problemas
I
una especificación es un contrato que debe cumplir un
algoritmo para ser solución del problema.
I
en la especificación de un problema (o de un tipo) no
podemos usar la especificación de otro problema.
I
en la especificación de un problema (o de un tipo) sı́ podemos
usar las funciones auxiliares ya definidas.
Cantidad finita de elementos.
Cada uno, denotado por una constante
3
I
Nombre (del tipo): tiene que ser nuevo
I
constantes: nombres nuevos separados por comas
I
Convención: todos con mayúsculas
I
ord(a) da la posición del elemento en la definición
(empezando de 0)
I
Inversa: ord−1
4
Tipos enumerados. Ejemplos
Tipo upla
El tipo Bool es básico; está predefinido ası́:
Definimos el tipo Dı́a ası́:
Uplas, de dos o más elementos, de cualquier tipo.
(T1 , T2 , ...Tn ): Tipo de las n-uplas de elementos de tipo
T1 , T2 , ... Tn , donde n es fijo. El tipo upla es
tipo Dı́a = Lunes, Martes, Miércoles, Jueves, Viernes, Sábado, Domingo;
primitivo del lenguaje de especificación.
tipo Bool = 0, 1, -;
I
I
I
I
I
I
Ejemplos
Valen
(Int, Int) son los pares ordenados de enteros.
ord(Lunes) == 0
Dı́a(2) == Miércoles
Jueves < Viernes
(Int, Char, Bool) son la triplas ordenadas con un entero, luego un
carácter y luego un valor booleano.
Podemos definir
prm, sgd, 3esimo, nesimo dan sus componentes.
aux esFinde(d : Dı́a) : Bool = (d == Sábado || d == Domingo);
Ejemplo
prim((7, 5)) == 7
Otra forma
aux esFinde2(d : Dı́a) : Bool = d > Viernes;
5
Secuencias ( o listas)
6
Secuencias. Notación
La secuencia vacı́a (de elementos de cualquier tipo) se escribe [ ]
Una secuencias de elementos de tipo T es una sucesión finita de
elementos de tipo T (importa el órden).
Una forma de escribir un elemento de tipo secuencia de tipo T es
escribir dentro de un juego de corchetes cada uno de los elementos
de tipo T separados por comas.
T es un tipo arbitrario
Ejemplos
[T ] es el tipo de las secuencias cuyos elementos son de tipo T
una secuencia de Int
Hay secuencias de Int, de Bool, de Dı́as, de 5-uplas;
[1, 1 + 1, 3, 2 ∗ 2, 3, 5]
también hay secuencias de secuencias de tipo T .
una secuencia de secuencias de Int
etcétera
[[12, 13], [-3, 9, 0], [5], [], [], [3]]
7
8
Secuencias por comprensión
Secuencias por comprensión. Ejemplos
[expresión | selectores, condiciones]
[expresión | selectores, condiciones]
expresión: cualquier expresión válida del lenguaje
[x | x ∈ [1, 2, 3, 4, 5, 6, 7, 8, 9], x
selectores: tienen la forma variable ∈ secuencia, donde variable se
instancia en cada uno de los elementos de la secuencia.
mod 2 == 0] == [2, 4, 6, 8]
condiciones: son expresiones de tipo Bool sobre una o más variable.
En caso de que no haya condiciones, se considera siempre verdadero.
[ [x] | x ∈ [ ‘a‘,‘l‘,‘g‘,‘o‘,‘r‘,‘i‘ ,‘t‘, ‘m‘, ‘o‘, ‘s‘, ‘ ‘, ‘I‘] ] ==
[ [ ‘a‘ ], [ ‘l‘ ], [ ‘g‘ ], [ ‘o‘ ], [ ‘r‘ ], [ ‘i‘ ], [ ‘t‘ ], [ ‘m‘ ], [ ‘o‘ ], [ ‘s‘ ], [ ‘ ‘ ], [ ‘I‘ ] ]
Esta notación da una nueva secuencia que contiene, uno tras otro, los
valores de la expresion calculados a partir de los elementos indicados por
los selectores que cumplen las condiciones.
[(x, y ) | x ∈ [1, 2], y ∈ [1, 2, 3], x < y ] == [(1, 2), (1, 3), (2, 3)]
A las variables dentro de los selectroes se las llama ligadas.
A las demás se las llama libres.
9
Secuencias por comprensión, varios selectores
10
Secuencias dadas por intervalos
[expresión1 ..expresión2 ]
[(x, y )|x ← a, y ← b, x =/= y ]
Las expresiones tienen que ser del mismo tipo, discreto y
totalmente ordenado (por ejemplo, Int, Char, enumerados)
es distinto de
La secuencia tiene todos los valores del tipo entre expresión1 y
expresión2 (ambos inclusive)
[(x, y )|y ← b, x ← a, x =/= y ]
Sı́, el orden importa...
Si no vale expresión1 ≤ expresión2 , la secuencia es vacı́a
Con un paréntesis en lugar de un corchete, se excluye uno de los
extremos o ambos
[(x, y )|x ← [1, 2], y ← [3, 4]] == [(1, 3), (1, 4), (2, 3), (2, 4)]
Ejemplos:
I
[(x, y )|y ← [3, 4], x ← [1, 2]] == [(1, 3), (2, 3), (1, 4), (2, 4)]
I
I
I
11
[5..9] == [5, 6, 7, 8, 9]
[5..9) == [5, 6, 7, 8]
(5..9] == [6, 7, 8, 9]
(5..9) == [6, 7, 8]
12
Ejemplos de secuencias por comprensión
Ejemplos de secuencias por comprensión y auxiliares
Divisores comunes (asumir a y b positivos)
aux divCom(a, b : Int) : [Int] =
Cuadrados de los elementos impares
[x|x ← [1..a + b], divide(x, a), divide(x, b)];
aux cuadImp(a : [Int]) : [Int] = [x ∗ x|x ← a, ¬divide(2, x)];
aux divide(a, b : Int) : Bool = b mod a == 0;
Ejemplo:
Ejemplo:
cuadImp([1..9)) == [1, 9, 25, 49]
divCom(8, 12) == [1, 2, 4]
¿Cuáles son variables libres y cuáles ligadas?
13
Ejemplos de secuencias por comprensión y auxiliares
14
Operaciones con secuencias
I
Longitud: long (a : [T ]) : Int
I
I
Suma de los elementos distintos
I
aux sumDist(a, b : [Int]) : [Int] = [x + y | x ← a, y ← b, x 6= y ];
Indexación: indice(a : [T ], i : Int) : T
I
I
Ejemplo:
I
I
sumDist([1, 2, 3], [2, 3, 4, 5]) == [3, 4, 5, 6, 5, 6, 7, 5, 7, 8]
I
requiere 0 ≤ i < |a|;
Elemento en la i-ésima posición de a
La primera posición es la 0
Notación: indice(a, i) se puede escribir a[i] y también ai
Cabeza: cab(a : [T ]) : T
I
I
15
Longitud de la secuencia a
Notación: long (a) se puede escribir |a|
requiere |a| > 0;
Primer elemento de la secuencia
16
Más operaciones con secuencias
I
Cola: cola(a : [T ]) : [T ]
I
I
I
y más operaciones con secuencias
I
requiere |a| > 0;
La secuencia sin su primer elemento
I
I
Pertenencia: en(t : T , a : [T ]) : Bool
I
I
I
I
Indica si el elemento aparece (al menos una vez) en la
secuencia
Notación: en(t, a) se puede escribir t en a y también t ∈ a
t∈
/ a es ¬(t ∈ a)
I
Agregar cabeza: cons(t : T , a : [T ]) : [T ]
I
I
Sublista de a en las posiciones entre d y h (ambas inclusive)
Cuando no es 0 ≤ d ≤ h < |a|, da la secuencia vacı́a
otra secuencia cambiando el elemento que hay en una
posición: cambiar (a : [T ], i : Int, val : T ) : [T ]
I
Una secuencia como a, agregándole t como primer elemento
Notación: cons(t, a) se puede escribir t : a
Secuencia con los elementos de a, seguidos de los de b
Notación: conc(a, b) se puede escribir a + +b
Subsecuencia: sub(a : [T ], d, h : Int) : [T ]
I
I
I
Concatenación: conc(a, b : [T ]) : [T ]
I
requiere 0 ≤ i < |a|;
Igual a la secuencia a, pero el valor en la posición i es val
17
Subsecuencias con intervalos
18
Operaciones sobre secuencias que dan números
I
I
Sumatoria: sum(sec : [T ]) : T
I
Notación para obtener la subsecuencia de una secuencia dada
que está en un intervalo de posiciones
I
I
I
I
Admite intervalos abiertos
I
I
I
I
I
I
I
a[d..h] == sub(a, d, h)
a[d..h) == sub(a, d, h − 1)
a(d..h] == sub(a, d + 1, h)
a(d..h) == sub(a, d + 1, h − 1)
a[d..] == sub(a, d, |a| − 1)
a(d..] == sub(a, d + 1, |a| − 1)
I
Productoria: prod(sec : [T ]) : T
I
I
I
I
19
T debe ser un tipo numérico, es decir, Float o Int
Calcula la suma de todos los elementos de la secuencia
Si sec es vacı́a, el resultado es 0
P
Notación: sum(sec) se puede escribir
sec
Ejemplo:
P
aux potNegDosHasta(n : Int) : Float = [2−m | m ← [1..n]];
T debe ser un tipo numérico (Float, Int)
Calcula el producto de todos los elementos de la secuencia
Si sec es vacı́a, el resultado es 1
Q
Notación: prod(sec) se puede escribir sec
20
Operaciones con secuencias que dan un valor booleano
Variante notacional de todos( )
(∀ selectores, condiciones) expresión
I
todos(sec : [Bool]) : Bool
I
Es verdadero solamente si todos los elementos de la secuencia son
verdaderos (o la secuencia es vacı́a)
I
I
alguno(sec : [Bool]) : Bool
Término de tipo Bool
Afirma que todos los elementos de una lista por comprensión
cumplen una propiedad
Equivale a escribir todos([expresión | selectores, condiciones])
Ejemplo: “todos los elementos en posiciones pares son
mayores que 5”:
auxpar (n : Int) : Bool = n mod 2 == 0;
Es verdadero solamente si algún elemento de la secuencia es
verdadero (y ninguno es Indef)
aux posParM5(a : [Float]) : Bool =
(∀i ← [0..|a|), par (i)) a[i] > 5;
Esta expresión es equivalente a
todos([a[i] > 5|i ← [0..|a|), par (i)]);
21
Variante notacional de alguno( )
22
Cantidad de ocurrencias en una secuencia
Para contar cuántos elementos de una secuencia cumplen una condición
medimos la longitud de una secuencia definida por comprensión
(∃ selectores, condiciones)expresión
I
Hay algún elemento que cumple la propiedad
Ejemplos:
¿Cuántas veces aparece el elemento x en la secuencia a?
I
Equivale a alguno([expresión | selectores, condiciones])
aux cuenta(x : T , a : [T ]) : Int = long ([y |y ← a, y == x]);
I
Notación: en lugar de ∃ se puede escribir existe o existen
Podemos usarla para saber si dos secuencias tienen los mismos elementos
(quizás en otro orden)
Ejemplo:
“Hay algún elemento de la lista que es par y mayor que 5”:
aux mismos(a, b : [T ]) : Bool =
(|a| == |b| ∧ (∀c ← a) cuenta(c, a) == cuenta(c, b));
aux hayParM5(a : [Int]) : Bool = (∃x ← a, par (x)) x > 5;
¿Cuántos primos positivos hay que sean menores a n?
Es equivalente a
aux primosMenores(n : Int) : Int = long ([y | y ← [0..n), primo(y )]);
aux primo(n : Int) : Bool =
(n ≥ 2 ∧ ¬(∃m ← [2..n)) n mod m == 0);
alguno([x > 5|x ← a, par (x)]);
23
24
Acumulación
Ejemplos de acumulación
Suma
aux sum(l : [Float]) : Float = acum(s + i | s : Float = 0, i ← l);
acum(expresión | inicializacion, selectores, condición)
Construye un valor a partir de una o más secuencias, acumulando valores
Productoria
inicializacion tiene la forma acumulador : tipoAcum = init
aux prod(l : [Float]) : Float = acum(p ∗ i | p : Float = 1, i ← l);
I
acumulador es un nombre de variable (nuevo) de tipo tipoAcum
I
init es una expresión de tipo tipoAcum
Fibonacci
aux fiboSuc(n : Int) : [Int] =
acum(f + +[f [i − 1] + f [i − 2]] | f : [Int] = [1, 1], i ← [2..n]);
expresión: es arbitraria, y puede (y suele) aparecer el acumulador
si n ≥ 1, da los primeros n + 1 números de Fibonacci
si n == 0, da [1, 1]
por ejemplo, fiboSuc(5) == [1, 1, 2, 3, 5, 8]
selectores y condición son como en las secuencias por comprensión
Importante: acumulador no puede aparecer en la condición
El n-ésimo número de Fibonacci (n ≥ 1)
El valor inicial de acumulador es el valor de init Por cada valor de los
selectores, tenemos un valor de expresión que se acumula en la variable
acumulador. El resultado es el valor final del acumulador.
aux fibo(n : Int) : Int = (fiboSuc(n − 1))[n − 1];
por ejemplo, fibo(6) == 8
26
25
Más ejemplos de acumulación
Ejemplos de especificación con listas y acumulación
Sumar los inversos multiplicativos de los reales en una lista
Concatenación de elementos de una secuencia de secuencias
problema sumarInvertidos(a : [Float]) = result : Float {
requiere 0 ∈
/ a; P
asegura result = [1/x | x ← a];
}
aux concat(a : [[T ]]) : [T ] =
acum(l + +c | l : [T ] = [], c ← a);
por ejemplo, concat([[1, 2], [3], [4, 5, 6]]) == [1, 2, 3, 4, 5, 6]
Precondición: que el argumento no contenga ningún 0
Si no, la poscondición podrı́a indefinirse.
Secuencias por comprensión
Formas equivalentes:
El término [expresión | selectores, condición] es equivalente a
acum(res + +[expresión] | res : [T ] = [], selectores, condición);
27
I
requiere (∀x ← a) x 6= 0;
I
requiere ¬(∃x ← a) x == 0;
I
requiere ¬(∃i ← [0..|a|)) a[i] == 0;
28
Especificación. Nombres para las condiciones
Un ejemplo de sobrespecificación usando secuencias
Problema: dada una lista, retornar una lista con los mismos elementos
que no esté ordenada de menor a mayor.
Problema: Dar el ı́ndice del menor elemento de una lista de enteros no
negativos y distintos entre sı́.
problema Desordena(a : [Int]) = res : [Int] {
asegura mismos(a, res);
asegura (∀i ← [0..|res| − 1)) res[i] ≥ res[i + 1]];
aux cuenta(x : T , b : [T ]) : Int = long ([y |y ← b, y == x]);
aux mismos(a, b : [T ]) : Bool = (|a| == |b| ∧
(∀c ← a) cuenta(c, a) == cuenta(c, b));
}
está sobrespecificado porque impone el órden de mayor a menor.
problema ı́ndiceMenorDistintos(a : [Float]) = res : Int {
requiere NoNegativos: (∀x ← a) x ≥ 0;
requiere Distintos: (∀i ← [0..|a|), j ← [0..|a|), i 6= j) ai 6= aj ;
asegura 0 ≤ res < |a|;
asegura (∀x ← a) a[res] ≤ x;
}
Nombramos las precondiciones, para aclarar su significado
I
Los nombres también pueden usarse como predicados en cualquier
lugar de la especificación
I
El nombre no alcanza, hay que escribir la precondición en el lenguaje
Ası́ sı́ está bien:
problema Desordena(a : [Int]) = res : [Int] {
asegura mismos(a, res);
asegura (∃i ← [0..|res| − 1)) res[i] > res[i + 1]];
aux cuenta(x : T , b : [T ]) : Int = long ([y |y ← b, y == x]);
aux mismos(a, b : [T ]) : Bool = (|a| == |b| ∧
(∀c ← a) cuenta(c, a) == cuenta(c, b));
}
Otra forma de escribir la segunda precondición:
requiere Distintos2: (∀i ← [0..|a|)) a[i] ∈
/ a[0..i);
29
Otro ejemplo de sobre especificación
Problema:
dar los ı́ndices de los numeros pares de una lista, en cualquier órden.
problema ı́ndicesDePares(a : [Int]) = res : [Int]{
asegura 0 ≤ |res| ≤ |a|;
asegura res == [i|i ← [0..|a|), a[i]mod2 == 0] ;
}
sobrespecifica el problema, porque exige que res siga el órden de a.
Ası́ sı́ está bien:
problema ı́ndicesDePares(a : [Int]) = res : [Int]{
asegura 0 ≤ |res| ≤ |a|;
asegura mismos(res, [i|i ← [0..|a|), a[i]mod2 == 0]);
}
31
30
Descargar