6. tipos de datos abstractos

46
6. Tipos de Datos Abstractos

Upload: wauna

Post on 24-Feb-2016

63 views

Category:

Documents


0 download

DESCRIPTION

6. Tipos de Datos Abstractos. ¿Qué es un TDA ? . E s un conjunto de datos u objetos al cual se le asocian operaciones P rovee de una interfaz con la cual es posible realizar las operaciones permitidas, abstrayéndose de la manera en como estén implementadas dichas operaciones - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 6. Tipos de Datos Abstractos

6.  Tipos de Datos Abstractos

Page 2: 6. Tipos de Datos Abstractos

¿Qué es un TDA ? • Es un conjunto de datos u objetos al cual se le asocian operaciones• Provee de una interfaz con la cual es posible realizar las operaciones

permitidas, abstrayéndose de la manera en como estén implementadas dichas operaciones

• Un mismo TDA puede ser implementado utilizando distintas estructuras de datos y proveer la misma funcionalidad

• Los lenguajes de programación orientados a objeto son consecuencia de estas ideas

Page 3: 6. Tipos de Datos Abstractos

TDA Lista• serie de N elementos E1, E2, ..., EN,

ordenados de manera consecutiva es decir, el elemento Ek (que se denomina elemento k-ésimo) es previo al elemento Ek+1

• Si la lista contiene 0 elementos se habla de una lista vacía.

• Operaciones: – insertar un elemento en la posición k, – borrar el k-ésimo elemento, – buscar un elemento dentro de la lista y – preguntar si la lista esta vacía.

Page 4: 6. Tipos de Datos Abstractos

Definición de la interfaz• Define firma de las funciones (métodos) que realizarán esto• Distintas clases implementarán esta interfaz usando

diferentes estructuras de datos, pero deben respetar la firma • El usuario puede usar cualquiera de ellas indistintamente ya

que la sintaxis de las funciones será la misma • Ejemplo para lista

interface Lista { boolean estaVacia(); void insertar(Object x, Posicion k); Posición buscar(Object x); Object buscarK(Posición k); void eliminar(Object x); void eliminar(Posicion k); }

Page 5: 6. Tipos de Datos Abstractos

Implementación• Se podría pensar en dos posibilidades: con arreglos y con lista

enlazada• Posición con arreglos sería entonces un entero (índice del lugar

del elemento).• Con lista enlazada sería un puntero (índice a lugar en la memoria) • ¿ De qué orden son los métodos en una u otra implementación ?

Método arreglo L. enlazada

boolean estaVacia();

void insertar(Object x, Posicion k);

Posicion buscar(Object x);

Object buscarK(Posición k);

void eliminar(Object x);

void eliminar(Posicion k);

Page 6: 6. Tipos de Datos Abstractos

Eficiencia en una lista enlazada• Se puede usar como posición la dirección en memoria del

elemento anterior• Se requiere una cabeza de lista• Al tener la posición, insertar y eliminar un elemento es O(1)• Buscar el elemento es siempre O(n)

Page 7: 6. Tipos de Datos Abstractos

Un  iterador de TDA’s• Para muchos TDA’s es útil definir un iterador, es decir,

objeto que permita recorrer esta estructuraEj TDAx a = new TDAx(); . . . //agregar elementos Iterador b = new Iterador(a); while (b.notEmpty()) print(b.next(); • La idea es que el iterador esconda también la impl. • El iterador se define normalmente como una interfaz• Mirar interfaz Iterator de Java

Page 8: 6. Tipos de Datos Abstractos

Un iterador de Lista con lista enlazadaclass IteradorLista implements Iterador { NodoLista actual;

public IteradorLista(Lista n) { actual=n.primero; } poublic boolean notEmpty() { return actual != null; } public Object next() { Object aux = actual.info; actual = actual.sig; return aux; }}

Page 9: 6. Tipos de Datos Abstractos

Problema. Leer las líneas de un archivo y escribirlas al revés (1º la última, 2º la penúltima, ..., última la 1ª). Indicación. Use el TDA (Tipo de Dato Abstracto) Stack (Pila) Stack: contenedor que opera con el principio LIFO (Last In

First Out), es decir, el último elemento que ingresa es el primero que sale.

TDA: tipo de dato con implementación oculta (representación privada y operaciones públicas)

Page 10: 6. Tipos de Datos Abstractos

TDA Stack Operación significado explicación new Stack()

crear stack vacío

void push(Object x) throws StackFull

x

Poner x en stack. Si está lleno produce la excepción StackFull

Object pop( ) throws StackEmpty

Sacar un valor de stack. Si está vacío produce la excepción StackEmpty

void reset( )

vaciar stack

boolean empty( ) ¿ ?

true si stack está vacío

boolean full( ) ¿ ?

true si stack está lleno

Page 11: 6. Tipos de Datos Abstractos

static public void main(String[]args) throws Exception { //crear stack para mantener líneas Stack s=new Stack(); //leer líneas y ponerlas en stack BR A=new BR(new FR(args[0])); String linea; while((linea=A.readLine())!=null){ if(s.full()) U.abort(“demasiadas lineas”); s.push(linea); } //sacar y escribir líneas de stack while( !s.empty() ) U.println((String)s.pop());//Object->String }

Page 12: 6. Tipos de Datos Abstractos

Solución 2: atrapando las excepciones (“el golpe avisa”) Stack s=new Stack(); try{ BR A=new BR(new FR(args[0])); String linea;

while((linea=A.readLine())!=null) s.push(linea);

}catch(StackFull x){ U.abortar(“demasiadas líneas”); } try{ while(true) U.println((String)s.pop()); }catch(StackEmpty x){}//no hacer nada Sintaxis: try{…}catch(Nombre x){…} “catcher” (atrapador de excepción) se ejecuta sólo si en el bloque try ocurrió la excepción nombrada cuando termina se sigue con las instrucciones sgtes al catcher.

Page 13: 6. Tipos de Datos Abstractos

TDA Stack: implementación con un arreglo

Ejemplo:

a[0] n=3 N=100

class Stack{protected Object[]a;protected int n;protected static final int N=100;//static: dato global//(para todos los objetos de la clase)

ABC

C

B

A

Page 14: 6. Tipos de Datos Abstractos

public Stack(){ a = new Object[N]; n = 0; } public boolean empty(){ return n == 0; } public boolean full(){ return n >= N; } public void reset(){ a = new Object[N]; n = 0; }

Page 15: 6. Tipos de Datos Abstractos

public void push(Object x)throws StackFull { if( n >= N ) throw new StackFull(); a[n++] = x; //a[n]=x; ++n; } public Object pop()throws StackEmpty { if( n == 0 ) throw new StackEmpty(); return a[--n];//--n; return a[n]; } }//fin class Stack throws Nombre: indica que si en el método se produce la excepción indicada, entonces no se atrapará y se trasmitirá/propagará al método que lo invocó (que a su vez la podrá atrapar o propagar) throw new Nombre(): lanza/produce/genera la excepción indicada

Page 16: 6. Tipos de Datos Abstractos

Definición de excepciones class StackFull extends Exception{} class StackEmpty extends Exception{} Exception clase predefinida clase madre de todas las excepciones excepciones de Input/Output:

class IOException extends Exception{…} class FileNoutFoundException extends IOException{…} etc

excepciones al ejecutar programas: class RunTimeException extends Exception{…} class NullPointerException extens RunTimeException{…} class ArrayIndexOutOfBoundsException extends RunTimeException{…} etc

Page 17: 6. Tipos de Datos Abstractos

Alternativa2: atrapando excepciones predefinidas public void push(Object x)throws StackFull{ try{ a[n++] = x; }catch(ArrayIndexOutOfBoundsException x){ throw new StackFull(); } } public Object pop()throws StackEmpty{ try{ return a[--n]; }catch(ArrayIndexOutOfBoundsException x){

n=0; //estaba con -1 throw new StackEmpty(); } } }//fin class Stack

Page 18: 6. Tipos de Datos Abstractos

Stack: representación con lista enlazada C B A null primero valor sgte valor sgte valor sgte class Nodo { public Object valor; //visible public Nodo sgte; //visible public Nodo(Object x,Nodo y){ valor=x; sgte=y; } }

C B A

Page 19: 6. Tipos de Datos Abstractos

class Stack { //representación: ref a primer nodo protected Nodo primero; public Stack(){ primero=null; } public boolean empty(){ return primero == null; } public boolean full(){ return false; //nunca está lleno } public void reset(){ primero=null; }

Page 20: 6. Tipos de Datos Abstractos

public void push(Object x) throws StackFull { //crear un nodo con valor x y sgte nulo _________ Nodo r=new Nodo(x,null);//r| x |null| //enlazarle lista anterior r.sgte=primero;//r| x | || y | | … //dejarlo como primero de la lista primero=r;//1º| x | || y | | … }

Page 21: 6. Tipos de Datos Abstractos

Alternativamente:public void push(Object x) throws StackFull{ //agregar al comienzo primero=new Nodo(x, primero);

//1º| x | || y | | …}

Page 22: 6. Tipos de Datos Abstractos

public Object pop() throws StackEmpty{ //excepción si lista está vacía if(primero==null) throw new StackEmpty();

//recuperar primer valor Object aux=primero.valor;//1º|x|||y|| //eliminar primer nodo primero=primero.sgte; ;//1º|y||… //devolver primer valor

return aux;}}//fin class Stack

Page 23: 6. Tipos de Datos Abstractos

Alternativamente public Object pop()throws StackEmpty{ try{

Object aux=primero.valor;//excepcion si null primero=primero.sgte;

return aux; } catch(NullPointerException x) { throw new StackEmpty(); } } }//fin class Stack

Page 24: 6. Tipos de Datos Abstractos

Ejemplo de uso: eliminación de recursividad

• Suponga que una función F realiza un llamado recursivo dentro de su código, lo que se ilustra en la siguiente figura:

Page 25: 6. Tipos de Datos Abstractos

Tail Recursion • Si la llamada recursiva es lo último que hace la función F, se

puede substituir por un ciclo while. • Este caso es conocido como tail recursion y es muy simple

eliminarla. Ejemplo:

void imprimir(int[] a, int j) // versión recursiva{ if (j<a.length) { System.out.println(a[j]); imprimir(a, j+1); // tail recursion }}void imprimir(int[] a, int j) // versión iterativa{ while (j<a.length) { System.out.println(a[j]); j=j+1; }}

Page 26: 6. Tipos de Datos Abstractos

Caso General: uso de pilas• Por ejemplo: recorrido en preorden de un arbol binario.

// "raiz" es la referencia a la raiz del arbol// llamado inicial: preorden(raiz) // version recursiva void preorden(Nodo nodo){ if (nodo!=null) { System.out.print(nodo.elemento); preorden(nodo.izq); preorden(nodo.der); }}

Page 27: 6. Tipos de Datos Abstractos

Preorden no recursivo: primera versión void preorden(Nodo nodo){ Nodo aux; Pila pila=new Pila(); // pila de nodos

pila.apilar(nodo); while(!pila.estaVacia()) // mientras la pila no este vacia

{ aux=pila.desapilar(); if (aux!=null) { System.out.print(aux.elemento); // primero se apila el nodo derecho y luego el izquierdo // para mantener el orden correcto del recorrido// al desapilar los nodos pila.apilar(aux.der); pila.apilar(aux.izq); } }}

Page 28: 6. Tipos de Datos Abstractos

Preorden no recursivo: segunda versión • dado que siempre el ultimo nodo apilado dentro del bloque if es

aux.izq podemos asignarlo directamente a aux hasta que éste sea null, es decir, el bloque if se convierte en un bloque while y se cambia el segundo apilar por una asignación de la referencia

void preorden(Nodo nodo){ Nodo aux; Pila pila=new Pila(); // pila de nodos pila.apilar(nodo); while(!pila.estaVacia()) // mientras la pila no este vacia { aux=pila.desapilar(); while (aux!=null) { System.out.print(aux.elemento); pila.apilar(aux.der); aux=aux.izq; } }}

Page 29: 6. Tipos de Datos Abstractos

Corolario• Si bien los programas no recursivos son más eficientes

que los recursivos, la eliminación de recursividad (excepto en el caso de tail recursion) le quita claridad al código del programa.

• Por lo tanto: – A menudo es conveniente eliminar el tail recursion. – Un método recursivo es menos eficiente que uno no recursivo,

pero sólo en pocas oportunidades vale la pena eliminar la recursión.

Page 30: 6. Tipos de Datos Abstractos

Problema. Simular una cola de atención de clientes de acuerdo al siguiente diálogo: Eventos: 1=llegada de cliente 2=atención de cliente 0=fin de eventos evento? 1 cliente? A A evento? 1 cliente? B A B evento? 2 se atiende A A B evento? 1 cliente? C B C … evento? 0

Page 31: 6. Tipos de Datos Abstractos

Indicación. Use una Queue (Cola) que es un contenedor que operacon el principio FIFO (First In First Out), es decir, el primerelemento que ingresa es el primero que sale.Operación significadonew Queue()

void enque(Object x)throws QueueFull

x

Object deque( )throws QueueEmpty

void reset( )

boolean empty( ) ¿ ?

boolean full( ) ¿ ?

Page 32: 6. Tipos de Datos Abstractos

Queue q=new Queue(); char evento; while((evento=U.readChar(“evento?”))!=’0’){ if(evento==’1’) try{ q.enque( U.readLine(“cliente?”) ); }catch(QueueFull x){ U.println(“rechazado”); } else if(evento==’2’) try{ U.println(“se atiende “+(String)q.deque()); }catch(QueueEmpty x){ U.println(“no hay clientes”); } else U.println(“evento incorrecto”); }

Page 33: 6. Tipos de Datos Abstractos

TDA Queue: implementación con un arreglo Ejemplo:

A B C a a[0] ... a[n-1] ... a[N-1] class Queue{ protected Object[]a; protected int n; protected static final int N=100; public Queue(){reset();} public void reset(){a=new Object[N];n=0;} public boolean empty(){return n==0;} public boolean full(){return n>=N;}

A B C

Page 34: 6. Tipos de Datos Abstractos

public void enque(Object x)throws QueueFull{ if(n>=N) throw new QueueFull(); a[n++] = x; } public Object deque()throws QueueEmpty{ if(n==0) throw new QueueEmpty();

Object aux=a[0]; for(int i=0;i<n-1;++i)

a[i]=a[i+1]; --n; return aux; } }//fin class Queue deque: O(n), es decir, depende del tamaño de la cola

Page 35: 6. Tipos de Datos Abstractos

Implementación TDA Queue: cola “flotante” en un arreglo Ejemplo: enque y deque O(1) A B C a a[0] … a[ip] ... a[iu] ... a[N-1] class Queue { protected Object[]a; protected int n; //largo de la cola protected int ip, iu;//indices de 1º y último protected static final int N=100;

A B C

Page 36: 6. Tipos de Datos Abstractos

public Queue(){ reset(); } public boolean empty(){ return n == 0; } public boolean full(){ return n >= N; } public void reset(){ a=new Object[N]; n=0;

ip=0; //índice de primer objeto que llegue iu=-1;//para que primer enque le sume 1

}

Page 37: 6. Tipos de Datos Abstractos

public void enque(Object x)throws QueueFull{ if( n >= N ) throw new QueueFull(); iu=(iu+1) % N;//++iu; if(iu==N) iu=0; a[iu] = x; ++n; } public Object deque()throws QueueEmpty{ if( n == 0 ) throw new QueueEmpty();

Object aux = a[ip]; ip = (ip + 1) % N; --n; return aux; } }//fin class Queue class QueueFull extends Exception{} class QueueEmpty extends Exception{} Propuesto: implementar usando el arreglo y sólo dos enteros

Page 38: 6. Tipos de Datos Abstractos

Representación de una Queue con una lista enlazada Alternativa1 : (enque toma tiempo proporcional a Nº de nodos) A B C null primero valor sgte valor sgte valor sgte

class Queue { protected Nodo primero; public Queue(){primero=null;} public void reset(){primero=null;} public boolean empty(){return primero==null;} public boolean full(){return false;}

Page 39: 6. Tipos de Datos Abstractos

public Object deque()throws QueueEmpty{ if(primero==null)throw new QueueEmpty();

Object aux=primero.valor; primero=primero.sgte; return aux; } public void enque(Object x)throws QueueFull{ //crear nuevo nodo Nodo r=new Nodo(x,null); //si lista vacía, agregar al comienzo if(primero==null){primero=r; return;} //agregar al final Nodo ultimo=primero; while(ultimo.sgte!=null)ultimo=ultimo.sgte; ultimo.sgte = r; } } Nota. operación O(n)

Page 40: 6. Tipos de Datos Abstractos

Alternativa 2: con referencias al primer y último nodo A B C null primero valor sgte valor sgte sgte ultimo class Queue{ protected Nodo primero, ultimo; public Queue(){ reset(); } public void reset(){ primero=ultimo=null; } public boolean empty(){ return primero==null; } public boolean full(){ return false; }

Page 41: 6. Tipos de Datos Abstractos

public void enque(Object x) throws QueueFull { Nodo r=new Nodo(x, null);

if(ultimo==null) //si lista vacía ultimo=primero=r;// dejar con un nodo

else //si no ultimo=ultimo.sgte=r;//enlazar al final } public Object deque()throws QueueEmpty {

if(primero==null)throw new QueueEmpty(); if(primero==ultimo) ultimo=null;//un nodo Object aux=primero.valor; primero=primero.sgte; return aux; } } Nota. Operaciones enque y deque O(1)

Page 42: 6. Tipos de Datos Abstractos

TDA Cola de prioridad• Una cola de prioridad es un tipo de datos abstracto que almacena un

conjunto de datos que poseen una llave perteneciente a algún conjunto ordenado, y permite insertar nuevos elementos y extraer el máximo (o el mínimo, en caso de que la estructura se organice con un criterio de orden inverso).

• Es frecuente interpretar los valores de las llaves como prioridades, con lo cual la estructura permite insertar elementos de prioridad cualquiera, y extraer el de mejor prioridad.

• Dos formas simples de implementar colas de prioridad son: • Una lista ordenada:

– Inserción: O(n) – Extracción de máximo: O(1)

• Una lista desordenada: – Inserción: O(1) – Extracción de máximo: O(n)

Page 43: 6. Tipos de Datos Abstractos

Heaps• Un heap es un árbol binario de una forma especial, que permite su

almacenamiento en un arreglo sin usar punteros. • Un heap tiene todos sus niveles llenos, excepto posiblemente el de más abajo,

y en este último los nodos están lo más a la izquierda posible. • Ejemplo:

• La numeración por niveles (indicada bajo cada nodo) son los subíndices en donde cada elemento sería almacenado en el arreglo. En el caso del ejemplo, el arreglo sería:

Page 44: 6. Tipos de Datos Abstractos

Implementación de Heaps• La característica que permite que un heap se pueda almacenar sin punteros es

que, si se utiliza la numeración por niveles indicada, entonces la relación entre padres e hijos es:

Hijos del nodo j = {2*j, 2*j+1} Padre del nodo k = floor(k/2) 

• Un heap puede utilizarse para implementar una cola de prioridad almacenando los datos de modo que las llaves estén siempre ordenadas de arriba a abajo (a diferencia de un árbol de búsqueda binaria, que ordena sus llaves de izquierda a derecha). En otras palabras, el padre debe tener siempre mayor prioridad que sus hijos .

Page 45: 6. Tipos de Datos Abstractos

Inserción en Heaps• Agregar el nuevo elemento en la primera posición libre del heap, esto es, el

próximo nodo que debería aparecer en el recorrido por niveles -> al final del arreglo. Con esto la forma del heap se preserva, pero la restricción de orden no tiene por qué cumplirse.

• Solución: hacerlo “subir” hasta un punto donde se vuelva a cumplir la condición

a[++n]=x; for(j=n; j>1 && a[j]>a[j/2]; j/=2){

# intercambiamos con el padre t=a[j]; a[j]=a[j/2]; a[j/2]=t; }

• El proceso de inserción, en el peor caso, toma un tiempo proporcional a la altura del árbol, esto es, O(log n).

Page 46: 6. Tipos de Datos Abstractos

Extracción del máximo (eliminación)• El máximo está en la raíz del árbol (casillero 1 del arreglo). Al sacarlo de ahí,

ese lugar queda vacante. Para llenarlo, tomamos al último elemento del heap y lo trasladamos al lugar vacante. En caso de que no esté bien ahí de acuerdo a su prioridad (¡que es lo más probable!), lo hacemos descender intercambiándolo siempre con el mayor de sus hijos. Es decir "se hunde" hasta su nivel de prioridad.

m=a[1]; # La variable m lleva el máximo a[1]=a[n--]; # Movemos el último a la raíz y achicamos el heap j=1; while(2*j<n) # mientras tenga algún hijo { k=2*j; # el hijo izquierdo if(k+1<=n && a[k+1]>a[k]) k=k+1; # el hijo derecho es el mayor if(a[j]>a[k]) break; # es mayor que ambos hijos t=a[j]; a[j]=a[k]; a[k]=t; j=k; # lo intercambiamos con el mayor hijo }

Este algoritmo también demora un tiempo proporcional a la altura del árbol en el peor caso, esto es, O(log n).