Tipos abstractos de datos. Tipos Lista, Pila y Cola.

Anuncio
Partes de un Tipo Abstracto de Datos
I
Parte pública: Disponible para el usuario externo.
I
Introducción a la Computación (Matemática)
I
Primer Cuatrimestre de 2015
I
Parte privada: Sólo accesible desde dentro del TAD. ¡El
usuario externo nunca debe ver ni meterse en esto!
I
Tipos Abstractos de Datos
Nombre y tipos paramétricos (ej: Fecha, Lista(ELEM)).
Operaciones, sus especificaciones y posiblemente sus órdenes
de complejidad temporal.
I
I
Estructura de representación del TAD.
Invariante de representación: qué propiedades debe cumplir
la estructura elegida para que tenga sentido como la
representación de una instancia del TAD.
Algoritmos de las operaciones para la estructura de
representación elegida.
1
2
TAD Fecha
Operaciones públicas (para f , f1 , f2 : Fecha; d, m, a : Z):
I
CrearFecha(d, m, a) → Fecha
I
Dı́a(f ) → Z
I
Mes(f ) → Z
I
Año(f ) → Z
I
Menor(f1 , f2 ) → B
I
FechaSiguiente(f ) → Fecha
Con esto, un usuario del TAD puede programar algo como:
ContarDı́as(f1 , f2 ) → Z:
RV ← 0
while (Menor(f1 , f2 )) {
RV ← RV + 1
f1 ← FechaSiguiente(f1 )
}
Olvidamos las listas de Python...
Solamente tenemos B, Z, R y tuplas.
(hasta el final de la clase de hoy!)
3
4
TAD Lista(ELEM)
TAD Lista(ELEM)
Operaciones (cont.):
I
Operaciones:
I
CrearLista() → Lista(ELEM): Crea una lista vacı́a.
I
L.Agregar(x): Inserta el elemento x al final de L.
I
L.Longitud() → Z: Devuelve la cantidad de elementos de L.
I
L.Iésimo(i) → ELEM: Devuelve el i-ésimo elemento de L.
Precondición: 0 ≤ i < L.Longitud().
I
L.Cantidad(x) → Z: Devuelve la cantidad de veces que aparece el
elemento x en L.
L.Insertar(i, x): Inserta el elemento x en la posición i de L, pasando
los elementos de la posición i y siguientes a la posición
inmediata superior. Pre: 0 ≤ i ≤ L.Longitud().
(Si L = a0 , .., an−1 , se convierte en L = a0 , .., ai−1 , x, ai , .., an−1 .)
I
L.BorrarIésimo(i): Borra el i-ésimo elemento de L
Precondición: 0 ≤ i < L.Longitud().
(Si L = a0 , .., an−1 , se convierte en L = a0 , .., ai−1 , ai+1 , .., an−1 .)
I
donde L : Lista(ELEM); i : Z; x : ELEM (entero, char, etc.).
L.Indice(x) → Z: Devuelve el ı́ndice (0 .. L.Longitud() − 1) de la
primera aparición de x en L. Pre: L.Cantidad(x) > 0.
donde L : Lista(ELEM), i : Z, x : ELEM (entero, char, etc.).
... y agregamos cualquier otra función que consideremos útil.
6
5
TAD Lista(ELEM) - Ejemplo de uso
TAD Lista(ELEM) - Posible implementación
Encabezado: Máximo : L ∈ Lista(Z) → Z
Precondición: {L = L0 ∧ L.Longitud() > 0}
Poscondición: {(∀i) 0 ≤ i < L0 .Longitud() ⇒ L0 .I ésimo(i) ≤ RV
∧ L0 .Cantidad(RV ) > 0}
Vamos a representar una lista como una cadena de nodos.
Definamos primero qué es un nodo.
Nodo(ELEM) : hvalor : ELEM, siguiente : Ref(Nodo)i
h...i define una tupla.
m ← L.I ésimo(0)
i ←1
while (i < L.Longitud()) {
if (L.I ésimo(i) > m) {
m ← L.I ésimo(i)
}
i ←i +1
}
RV ← m
Ref(Nodo) es una referencia a una instancia de tipo Nodo. Puede
tomar el valor especial None (“referencia a nada”).
Construcción de un nuevo Nodo:
I
n ← Nodo(x, r )
Acceso a los campos de un nodo n:
7
I
n.valor devuelve el campo valor .
I
n.siguiente devuelve el campo siguiente.
8
TAD Lista(ELEM) - Posible implementación
TAD Lista(ELEM) - Posible implementación
Primero elegimos una estructura de representación del TAD
Lista(ELEM) (que es privada).
L.Agregar(x):
nuevo ← Nodo(x, None)
if (L.cabeza = None) {
L.cabeza ← nuevo
}
else {
aux ← L.cabeza
while (aux.siguiente 6= None) {
aux ← aux.siguiente
}
aux.siguiente ← nuevo
}
L.longitud ← L.longitud + 1
Lista(ELEM) == hcabeza : Ref(Nodo), longitud : Zi
Después describimos el invariante de representación de esta
estructura. En este caso longitud siempre debe ser igual a la
cantidad de nodos encadenados a partir de cabeza, y en la cadena
de nodos no deben formarse ciclos.
Por último, damos los algoritmos de las operaciones del TAD
Lista(ELEM) para la estructura de representación elegida:
CrearLista() → Lista(ELEM):
RV .cabeza ← None
RV .longitud ← 0
10
9
TAD Lista(ELEM) - Posible implementación
Partes de un Tipo Abstracto de Datos
L.Longitud() → Z:
RV ← L.longitud
I
Parte pública: Disponible para el usuario externo.
I
I
L.Iésimo(i) → ELEM:
aux ← L.cabeza
while (i > 0) {
aux ← aux.siguiente
i ←i −1
}
RV ← aux.valor
(Pre: 0 ≤ i < L.Longitud())
I
Parte privada: Sólo accesible desde dentro del TAD. ¡El
usuario externo nunca debe ver ni meterse en esto!
I
I
I
Y ası́ con las otras operaciones del TAD Lista(ELEM): Cantidad,
Insertar, BorrarIésimo e Indice.
11
Nombre y tipos paramétricos (ej: Fecha, Lista(ELEM)).
Operaciones, sus especificaciones y posiblemente sus órdenes
de complejidad temporal.
Estructura de representación del TAD.
Invariante de representación: qué propiedades debe cumplir
la estructura elegida para que tenga sentido como la
representación de una instancia del TAD.
Algoritmos de las operaciones para la estructura de
representación elegida.
12
TAD Lista(ELEM) - Posible implementación
Complejidad temporal de los algoritmos vistos para esta estructura
de representación.
I
CrearLista() → Lista(ELEM)
I
L.Agregar(x)
I
L.Longitud() → Z
I
L.Iésimo(i) → ELEM
I
L.Cantidad(x) → Z
I
L.Insertar(i, x)
I
L.BorrarIésimo(i)
O(n)
I
L.Indice(x) → Z
O(n)
O(1)
O(n)
O(1)
O(n)
O(n)
O(n)
donde L : Lista(ELEM), i : Z, x : ELEM (entero, char, etc.).
14
13
TAD Pila(ELEM)
Problema: Paréntesis balanceados
Operaciones:
I
CrearPila() → Pila(ELEM): Crea una pila vacı́a.
I
P.Apilar(x): Inserta el elem. x sobre el tope de la pila P.
I
P.Vacı́a?(P) → B: Dice si la pila P está vacı́a.
I
P.Tope() → ELEM: Devuelve el elemento del tope de P.
Precondición: ¬P.Vacı́a?().
I
Dado un string, determinar si los caracteres { }, [ ], ( ) están
balanceados correctamente.
Ejemplos:
P.Desapilar(): Borra el elemento del tope de P.
Precondición: ¬P.Vacı́a?().
I
“{a(b)x[()]}” está balanceado.
I
“}”, “a(b))” y “[[})” no están balanceados.
¿Se les ocurre una solución? Sugerencia: usar el tipo Pila.
donde P : Pila(ELEM), x : ELEM (entero, char, etc.).
Las pilas tienen estrategia LIFO (last in, first out).
15
16
TAD Pila(ELEM) - Posible implementación
TAD Pila(ELEM) - Posible implementación
Algoritmos de las operaciones del TAD Pila(ELEM) para la
estructura de representación elegida:
CrearPila() → Pila(ELEM):
RV .ls ← CrearLista()
Estructura de representación del TAD Pila(ELEM):
Pila(ELEM) == hls : Listai
P.Apilar(x):
P.ls.Agregar(x)
Invariante de representación de esta estructura:
En este caso no hay nada que decir. Según la estructura de
representación elegida, cualquier lista es una representación válida
de una pila.
P.Vacı́a?() → B:
RV ← (P.ls.Longitud() = 0)
P.Tope() → ELEM:
(Pre: ¬P.Vacı́a?())
RV ← P.ls.Iésimo(P.ls.Longitud() − 1)
P.Desapilar():
(Pre: ¬P.Vacı́a?())
P.ls.BorrarIésimo(P.ls.Longitud() − 1)
17
18
19
20
TAD Pila(ELEM) - Posible implementación
La complejidad temporal de los algoritmos vistos para esta
estructura de representación dependen de la complejidad de las
operaciones del TAD Lista. Suponiendo la implementación del
TAD Lista que vimos, los órdenes son:
I
CrearPila() → Pila(ELEM)
I
P.Apilar(x)
I
P.Vacı́a?() → B
I
P.Tope() → ELEM
I
P.Desapilar()
O(1)
O(n)
O(1)
O(n)
O(n)
¿Se les ocurre otra estructura de representación que nos permita
bajar todos estos a O(1)?
TAD Cola(ELEM)
Repaso de la clase de hoy
Operaciones:
I
CrearCola() → Cola(ELEM): Crea una cola vacı́a.
I
TAD Lista(ELEM).
I
C .Encolar(x): Agrega el elemento x al final de la cola C .
I
TAD Pila(ELEM).
I
C .Vacı́a?() → B: Dice si la cola C está vacı́a.
I
TAD Cola(ELEM).
I
C .Primero() → ELEM: Devuelve el primer elemento de C .
Precondición: ¬C .Vacı́a?().
I
C .Desencolar(): Borra el primer elemento de C .
Precondición: ¬C .Vacı́a?().
Próximos temas
I
I
donde C : Cola(ELEM), x : ELEM (entero, char, etc.).
Conjunto(ELEM) y Diccionario(T1 , T2 ).
Técnicas algorı́tmicas:
I
Backtracking. 8 reinas.
Las colas tienen estrategia FIFO (first in, first out).
21
22
Descargar