clase 23: Stacks y Queues Problema.

Slides:



Advertisements
Presentaciones similares
ESTRUCTURA DE DATOS Unidad 03 PILAS.
Advertisements

Pilas y Colas Fundamentos Estructuras de Datos (Programación 2)
ÁRBOLES EN C UNIVERSIDAD “ALONSO DE OJEDA” Facultad de Ingeniería
Estructuras de datos y algoritmos
1 Extensión de un Estructura de Datos Agustín J. González ELO-320: Estructura de Datos y Algoritmos.
Programación y Estructuras de Datos
Árboles binarios. Algoritmos básicos
PROGRAMACION DE ESTRUCTURAS DE DATOS
Programación II Colas Igor Santos Grueiro.
Oscar Bedoya. Edificio 331, 2º piso, E.I.S.C. Estructuras de datos y algoritmos.
Integrantes: Esteban Jiménez Guesseppe Lozada Mario Rodriguez Gustavo Tenorio Fabio.
ÁRBOLES DE EXPRESION.
ARBOLES PARCIALMENTE ORDENADOS ESTRUCTURAS DE DATOS.
Cont. Arbol Binario de Búsqueda (2). Sobre los recorridos Las versiones recursivas de los recorridos son costosas debido a la gran cantidad de llamadas.
Tema Nº4.
Estructuras dinámicas de datos, TAD Lista, parte 2
COLAS, IMPLEMENTACIÓN A PARTIR DE LISTAS Y PARA PILAS
Pilas Una pila es una estructura lineal de elementos en donde se pueden agregar o eliminar datos únicamente por uno de los dos extremos. En consecuencia.
Igor Santos Grueiro. De este tipo de pilas NO vamos a hablar.
Tema 6: Clases Antonio J. Sierra.
C++ LISTAS C++ 11/04/2017 Ing. Edgar Ruiz Lizama.
Estructuras de Datos MC Beatriz Beltrán Martínez.
Árboles, montículos y grafos Cola de prioridades, montículos
Ordenamiento, Heapsort y Colas de prioridad
PILAS, COLAS, RECURSIVIDAD.
Heaps Mauro Maldonado Abril/2005. Introducción La estructura heap es frecuentemente usada para implementar colas de prioridad. En este tipo de colas,
ESTRUCTURAS DE DATOS I Conocer, comprender y analizar algunos de los principales tipos de estructuras de datos.
7.  El TDA Diccionario.
Estructura de Datos y Algoritmos
Diseño y análisis de algoritmos
Estructuras de Datos Arreglos.
Arboles M.C. José Andrés Vázquez FCC/BUAP
ARBOLES ESTRUCTURAS DE DATOS.
Pila1UVM Pilas. Pila2UVM Pila3UVM 2.1 Objetivos El estudiante manejará el tad Pila contigua.
Material de apoyo Unidad 4 Estructura de datos
1 Asignación Dinámica de Memoria Agustín J. González Versión original de Kip Irvine ELO 329.
Pilas y Colas Estructuras de Datos.
TDA PILA ESTRUCTURAS DE DATOS.
Ordenación y Búsqueda.
Árboles Recomendado: 1. Nivelación Funciones
Árboles Binarios Estructuras de Datos.
Computación I Primer Semestre 2006 Capítulo IV Ciclos y Colecciones (con un sabor a algoritmos)
1. Desarrollo de Programas iterativos usando invariante
PILAS Una pila es una estructura de datos o lista de elementos, a la cual se le puede insertar o eliminar su contenido sólo por uno de sus extremos, llamado.
Estructura de Datos M.C. José Andrés Vázquez Flores FCC/BUAP
TIPOS ABSTRACTOS DE DATOS. 2  Un Tipo Abstracto de Dato (TAD) es un modelo constituido por un conjunto de objetos y una colección de operaciones realizables.
Unidad 6: Árboles.
Arboles B (búsqueda externa)
Son estructuras de datos que almacenan y recuperan sus elementos atendiendo a un estricto orden (LIFO Last – in, first –out Ultimo en entrar – primero.
1 Asignación Dinámica de Memoria Agustín J. González ELO 329.
Punteros, referencias Listas enlazadas Arboles
Estructuras de datos Fundamentos de análisis y diseño de algoritmos.
Ayudantia 3: Pilas- Colas
Árboles Binarios de Búsqueda (ABB)
R ECORRIDO DE ÁRBOLES BINARIOS POR AMPLITUD O POR NIVELES Elaborado por: Luis Alberto Fonseca Esquivel Eduardo Acosta Casillas.
Estructura de Datos..
PROGRAMACION DE Pilas o Stacks
Árboles Equilibrados Estructuras de Datos MC Beatriz Beltrán Martínez Primavera 2015.
Metodología de Programación Ayudantía 4 lelagos.ublog.cl 2009.
PILAS Una pila es una estructura de datos o lista de elementos, a la cual se le puede insertar o eliminar su contenido sólo por uno de sus extremos, llamado.
INTRODUCCIÓN A LA PROGRAMACIÓN ORIENTADA A OBJETOS Tipo.
ESTRUCTURAS LINEALES “LA PILA”
Listas Dinámicas.
1 ListaUna Lista se define como una serie de N elementos E 1, E 2,..., E N, ordenados de manera consecutiva, es decir, el elemento E k (que se denomina.
UNIVERSIDAD DIEGO PORTALES Facultad de Ingeniería Programación Avanzada TIPOS ABSTRACTOS DE DATOS TAD Tema: TIPOS ABSTRACTOS DE DATOS TAD Subtema: COLAS.
2. Arreglos e invariantes. Arreglos Un arreglo es una coleccion ordenada de elementos del mismo tipo – Tipos de datos primitivos (int, …) – Referencias.
Clase25: Listas Enlazadas
Clase 23: Stacks y Queues 27-octubre J.Alvarez.
Clase25: Listas Enlazadas
Clase25: Listas Enlazadas
Transcripción de la presentación:

clase 23: Stacks y Queues Problema. Leer las líneas de un archivo que contiene un programa en Java y verificar que todos los paréntesis estén bien balanceados 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) 27-octubre J.Alvarez

static public void main(String[]args) { Stack s=new Stack(); BR A=new BR(new FR(args[0])); String linea; boolean ok = true; while((linea=A.readLine())!=null){ for(int i=0; i< linea.size(); i++) { char c = linea.charAt(i); if (c == ´{´ || c== ´(´ || == ´[´) { if(s.full()) U.abort(“overflow”); if (c == ´{´) s.push(“}”); else if (c == ´[´) s.push(“]”); else s.push(“)”); } else if (c == ´}´ || c== ´)´ || == ´]´) { if(s.empty() || !c.equals((String)s.pop()) { ok = false; break; } } //stack deberia estar vacío al final if ( !s.empty() || !ok) System.out.println(“error en los paréntesis”);

clase 23: Stacks y Queues 27-octubre J.Alvarez

Solución 2: atrapando las excepciones (“el golpe avisa”) static public void main(String[]args) throws Exception{ Stack s=new Stack(); BR A=new BR(new FR(args[0])); String linea; boolean ok = true; try { while((linea=A.readLine())!=null){ for(int i=0; i< linea.size(); i++) { char c = linea.charAt(i); if (c == ´{´ || c== ´(´ || == ´[´) { s.push(c+””); //ponemos un String (objeto) } else if (c == ´}´ || c== ´)´ || == ´]´) { if(!c.equals((String)s.pop()) { ok = false; break; } } } catch (StackEmpty e) { ok = false; } } catch (StackFull e) { U.abort(“overflow”); } //stack deberia estar vacío al final if (!ok) System.out.println(“error en los paréntesis”);

Alternativamente: public void push(Object x) throws StackFull { //agregar al comienzo primero=new Nodo(x, primero); //1º| x | || y | | … }

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

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:

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) { j=j+1;

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); }

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); }

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; }

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.

clase 23: Stacks y Queues 27-octubre J.Alvarez

Clase25: Listas Enlazadas

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)

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:

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 .

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).

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).

Transformar un arreglo en un heap Sacando lso elemento del arreglo y poniéndolos en un heap: O(n log n) y ocupa el doble de memoria Modificarlo para hacerlo más eficiente y en el mismo arreglo. La idea es invertir el orden de las "mitades" del arreglo, haciendo que el "input" esté a la izquierda y el "heap" a la derecha.

Transformar un arreglo en un heap En realidad, si el "heap" está a la derecha, entonces no es realmente un heap, porque no es un árbol completo (le falta la parte superior), pero sólo nos interesa que en ese sector del arreglo se cumplan las relaciones de orden entre a[k] y {a[2*k],a[2*k+1]}. En cada iteración, se toma el último elemento del "input" y se le "hunde" dentro del heap de acuerdo a su nivel de prioridad. La razón es que, al ser "hundido", un elemento paga un costo proporcional a su distancia al fondo del árbol. Dada las características de un árbol, la gran mayoría de los elementos están al fondo o muy cerca de él, por lo cual pagan un costo muy bajo. En un análisis aproximado, la mitad de los elementos pagan 0 (ya están al fondo), la cuarta parte paga 1, la octava parte paga 2, etc. Sumando todo esto, tenemos que el costo total está acotado por