Вы находитесь на странице: 1из 36

Unidad 3.- Estructuras lineales estática y dinámicas.

3.1 Pilas.

3.2 Colas.

3.3 Listas enlazadas.

3.3.1 Simples.

3.3.2 Dobles.
Stack (pila)
• Una pila (Stack) es un contenedor de objetos
que se insertan y eliminan de acuerdo con el
principio: último en entrar primero en salir
(LIFO, Last Input First Output)
• Los elementos se insertan de uno en uno
(push, apilar)
• Se sacan (extraen) en orden inverso al que
se insertaron (pop, desapilar)
• Único elemento que se puede observar
(examinar) es top o cima
Stack (pila)
Aplicaciones
 Estructuras auxiliares en numerosos
algoritmos y esquemas de programación:
 Recorridos (profundidad) de árboles y grafos
 Evaluación de expresiones
 Conversión entre notaciones de expresiones
(postfija, prefija, infija)
 Operación Deshacer en editores de texto
 Operación Volver Hacia Atrás en un
navegador en la secuencia de páginas web
Stack (pila)
Implementaciones
 Mediante un array ⇒ (T *elementos; int
numElementos; int maxElem;)
 numElementos = 0 ⇒ pila vacía
 elementos[0] ⇒ fondo de la pila
 elementos[numElementos – 1] ⇒ cima de la pila

 Mediante una lista encadenada ⇒ (PNodo


elementos; int numElementos)
 No hay limitación de tamaño
Tratamiento de expresiones aritméticas (utilizando pilas)

Las expresiones aritmeticas pueden ser representadas en tres notaciones


distintas, dos de las cuales se denominan “Polacas”.

Notación Prefija.- El operador se evalúa antes que los operandos.


Prefija: <operador> <operando> <operando>

Notación Infija.- El operador se evalúa dentro de los operandos.


Infija: <operando> <operador> <operando>

Notación Postfija.- El operador se evalúa despues de los operandos.


Postfija: <operando> <operando> <operador>

Ejemplo1: Ejemplo2:
Infija: (x+z)*w/t^y-v Infija: (a+b*c)/d*k^1
Postfija: xz+w*ty^/v- Postfija: abc*+d/k1^*
Prefija: -*+xz/w^tyv Prefija: /+a*bc*d^k1
Precedencia de los operadores

1) ^ circunflejo
2) / *
3) +-

La ventaja de utilizar expresiones en notación polaca (prefija o infija)


radica en que no son necesarios los paréntesis para indicar el orden de
operación, ya que esto queda establecido por la ubicación de los
operadores de más alta prioridad, pues se ejecutan primero.
Si hubiera en una expresión 2 o más operadores de igual prioridad, se
procesa de izquierda a derecha.
Las expresiones con paréntesis se ejecutan primero.
Algoritmo para convertir una expresión infija
a una expresión de notación polaca postfija

1. Si el símbolo es un “(“, este se mete a la pila de operadores.


2. Si el símbolo es un “)”, se saca de la pila todo lo que exista hasta llegar al
primer “(“, los operadores van a la solución, a medida que salen de la pila, el
“(“ se saca pero no se agrega a la solución.
3. Si el símbolo es un operador, entonces si el operador en el tope de la pila es
de la misma o mayor precedencia, dicho operador se saca y se agrega a la
solución, continuando de esta manera hasta que el primer “(“ o un operador de
menor precedencia se encuentre en la pila, cuando esta situación ocurre,
entonces el operador en turno se mete a la pila.
4. Si el símbolo es un operando, este se agrega directamente a la solución.

Nota: Al terminar de analizar la expresión, sacar todos los símbolos que queden en
la pila y agregarlos a la solución.
Queue (cola)
• Una cola (Queue) es un contenedor de
objetos que se insertan por el extremo final
y extraen por el extremo opuesto: frente
• Siguen el principio de: primero en entrar
primero en salir (FIFO, First Input First
Output)
• El único elementos observable (accesible)
en todo momento es el primero que fue
insertado (primero en la secuencia) ⇒ frente
• TAD Queue ⇒ cuya extensión da lugar al
TAD doble cola (DQueue)
Queue (cola)
Aplicaciones
 Simular situaciones reales: caja del
supermercado, surtidor de combustible, etc.
 Colas de trabajos a realizar por cualquier
dispositivo: una impresora, un disco, etc.
 Scheduler: asignación de tiempo de
procesador a los procesos en un sistema
operativo multiusuario (sin prioridad)
 Algoritmos de búsqueda en anchura sobre
árboles y grafos
Queue (cola)

Implementaciones
 Mediante un array (Pila) ⇒ (T *elementos; int
numElementos; int maxElem;)
 numElementos = 0 ⇒ cola vacía
 frente (front) = elementos[0]
 final (back/rear) = elementos[numElementos – 1]
 Coste de las operaciones (Extraer)?
 Mediante una lista enlazada ⇒ (PNodo
frente, final; int numElementos)
 No hay limitación de tamaño
Queue (cola)
El TAD Doble Cola
• Permite consultar, añadir y eliminar
elementos en cualquiera de los dos
extremos de la estructura lineal ⇔ bicola
• Especificación algebraica ⇒ Ejercicio
• Implementaciones:
– Lista simplemente encadenada ⇒ Problema:
Extraer un elemento por la derecha coste O(n)
– Lista doblemente encadenada ⇒ Ventajas: (1)
Todas operaciones coste temporal cte. O(1) y (2)
Punteros a primero (front) y último (back)
simplifican operaciones de Insertar y Extraer
Colas
La Cola es una estructura de datos donde la
inserción de datos se hace en un extremo del arreglo
(el fin de la cola) y la recuperación/borrado de
elementos se hace en el otro extremo (el inicio de la
cola). Como el primer elemento insertado es el
primero en ser recuperado, los desarrolladores se
refieren a estas colas como estructuras FIFO (first-in,
first-out) (primero en entrar, primero en salir).

Normalmente los desarrolladores trabajan con dos


tipos de colas: lineal y circular. En ambas colas, la
inserción de datos se realiza en el fin de la cola, se
mueven hacia adelante y se recuperan/borran del
inicio de la cola. La siguiente figura ilustra las colas
lineal y circular:

La cola lineal de la figura anterior almacena cuatro enteros, con el entero 1 en primer lugar. Esa
cola está llena y no puede almacenar más datos adicionales porque rear identifica la parte final
de la cola. La razón de la posición vacía, que identifica front, implica el comportamiento lineal
de la cola. Inicialmente, front y rear identifican la posición más a la izquierda, lo que indica que
la cola está vacía. Para almacenar el entero 1, rear avanza una posición hacia la derecha y
almacena 1 en esa posición. Para recuperar/borrar el entero 1, front avanza una posición hacia
la derecha.
La cola circular de la figura anterior tiene siete datos enteros, con el entero 1 primero.
Esta cola está llena y no puede almacenar más datos hasta que front avance una
posición en sentido horario (para recuperar el entero 1) y rear avance una posición
en la misma direción (para identificar la posición que contendrá el nuevo entero). Al
igual que con la cola lineal, la razon de la posición vacía, que identifica front, implica
el comportamiento circular de la cola. Inicialmente, front y rear identifican la misma
posición, lo que indica una cola vacía. Entonces rear avanza una posición por cada
nueva inserción. De forma similar, front avanza una posición por cada
recuperación/borrado.

Las colas son muy útiles en varios escenarios de programación, uno de ellos es:

Trabajos de impresión:
Como una impresora normalmente es más lenta que un ordenador, un sistema
operativo maneja los trabajos de impresión en un subsistema de impresión, que
inserta esos trabajos de impresión en una cola. El primer trabajo en esa cola se
imprime primero, y así sucesivamente.
Listas.
Existe una gran variedad de estructuras denominadas listas.

Lista simplemente enlazada.


La más básica es la simplemente enlazada. Que puede definirse como la
secuencia de cero (lista vacía) o más elementos de un determinado tipo. Los
elementos quedan ordenados linealmente por su posición en la secuencia. Se
requiere sólo un enlace entre un elemento y su sucesor.

Los arreglos tienen un segmento contiguo en la memoria.

En las listas debe asumirse que el espacio de un nodo no es contiguo con otro;
por esta
razón no basta incrementar en uno, el puntero a un nodo, para obtener la
dirección de inicio del nodo siguiente.

Cada nodo está conectado con el siguiente mediante un puntero que es un campo
del nodo.

Los elementos del arreglo se direccionan en tiempo constante, O(1). Los


elementos de las listas tienen un costo de acceso O(n), en peor caso.
Las operaciones sobre listas deben considerar que ésta puede estar vacía, y que
esto puede requerir un tratamiento especial.

Los siguientes diagramas ilustran una lista vacía y una lista con tres elementos. Si
los nodos se crean en el heap, la variable lista debe estar definida en el stack, o
en la zona estática, con el tipo puntero a nodo.

Note que el programador no dispone de nombres de variables para los nodos,


éstos sólo pueden ser accesados vía puntero (esto debido a que en el momento
de la compilación no se conocen las direcciones de los nodos; estas direcciones
serán retornadas en tiempo de ejecución).
TAD Lista
• LISTA = colección de elementos homogéneos entre los que existe
una relación lineal
– Cada elemento de la lista, a excepción del primero, tiene un
único predecesor
– Cada elemento de la lista, a excepción del último, tiene un único
sucesor
• Nodos y enlaces
Listas: descripción lógica
• Orden de nodos afecta a la función de acceso
– Según orden de inserción
– Según clave

• Ejemplo
Lista de calificaciones ::= <Alumno> + {<Alumno>}
<Alumno>::= <<DNI>> + <<NIA>> + <Apellido1> + <Apellido2> +
<Nombre> + <Calificación>
Listas: descripción lógica
• Listas ≠ Arrays
– Listas son flexibles y permiten cambio de implementación
• Operaciones
– Insertar, Borrar, Modificar, etc.
• Tipos de listas
– Simples
– Ordenadas
– Pilas
– Colas
– Doblemente enlazadas (LDE)
– Circulares
Implementaciones
Estática Dinámica
tamaño = 4 tamaño = 3
max = 4 max = 8

tamaño = 3
Secuencial

elem[i] = G N U I S N O T

elem[i] = G N U · · · · i= 1 2 3 4 5 6 7 8
posición = i
i= min +1 +2 ... ... ... max

posición = i Vector original

Vector ampliado

tamaño = 5
Enlazada

tamaño = 3
N
G I
elem[i] = G 4 · · · · N· 5 U 0 · · · ·
U S null
i= 1 2 3 4 5 … max posición
posición = i
Listas Simples
• Lista Simple = colección de elementos homogéneos cuya relación
lineal es determinada por la posición del elemento en la lista
• Comienzo + Enlace al siguiente (≠ puntero)

• Definición:
<listaSimple> ::= <comienzo> + {<nodo>}
<nodo> ::= <informacion> + <enlace>
<informacion> ::= <<dato>>{<<dato>>}
<enlace> ::= (<<ReferenciaNodo>> | NULL)
<comienzo> :: =<enlace>
TAD Lista Simple: operaciones
Creación de una lista crearLista (nombreLista)

Comprobación del listaVacia(nombreLista) → Booleano


estado listaVacia(referenciaNodo) → Booleano
listaLlena(nombreLista) → Booleano
insertar(nombreLista, valorInfo, posicion)
Inserción de nodos
insertar(nombreLista, valorInfo)

Borrado de nodos borrar(nombreLista, valorInfo)

buscar(nombreLista, dato) → informacion


Búsqueda de un nodo
buscar(nombreLista, dato) → referenciaNodo
pertenece(nombreLista,informacion) → Booleano
Recorrido de la lista recorrer(nombreLista)

info(referenciaNodo) → Informacion
Acceso a los nodos
siguiente(referenciaNodo) → enlace
Modificación de los asignarInfo(referenciaNodo, valorInformacion)
nodos asignarEnlace(referenciaNodo, valorEnlace)
Listas Simples
• Aclaraciones a las operaciones:
– listaLlena sólo tiene sentido si lista es acotada
– acceso y modificación serán métodos get y put
• Ejemplo y pseudocódigo
– insertar (nombreLista, valorInfo, posición)
– insertar (nombreLista, valorInfo)
– borrar (nombreLista, valorInfo)
– buscar (nombreLista, dato) → ι ν φ ο ρ µ α χ ι ón
– recorrer (nombreLista)
• Inserción: casos…
Listas Ordenadas
• La posición de cada nodo viene determinada por el valor de uno o
más campos obligatorios de información del nodo denominados
clave
• No se permite tener dos nodos con la misma clave

• Definición
<listaOrdenada> ::= <comienzo> + {<nodo>}
<comienzo> ::= <enlace>
<enlace> ::= (<<ReferenciaNodo>> | NULL)
<nodo> ::= <clave> + <informacion> + <enlace>
<clave> ::= <<dato>>{<<dato>>}
<informacion> ::= {<<dato>>}
TAD Lista Ordenada: operaciones
Creación de una lista crearLista (nombreLista)

Comprobación del listaVacia(nombreLista) → Booleano


estado listaVacia(referenciaNodo) → Booleano
listaLlena(nombreLista) → Booleano
Inserción de nodos insertar(nombreLista, valorClave, valorInfo)

Borrado de nodos borrar(nombreLista, valorClave)


buscar(nombreLista, valorClave) → Informacion
Búsqueda de un nodo
buscar(nombreLista, valorClave)→ReferenciaNodo
pertenece(nombreLista,valorClave) → Booleano
Recorrido de la lista recorrer(nombreLista

Acceso a los nodos clave(referenciaNodo) → Clave


info(referenciaNodo) → Informacion
siguiente(referenciaNodo) → enlace
Modificación de los asignarClave(referenciaNodo, valorClave)
nodos asignarInfo(referenciaNodo, valorInformacion)
asignarEnlace(referenciaNodo, valorEnlace)
Pilas
• Pila = colección ordenada de elementos homogéneos en la que sólo se pueden
añadir y eliminar elementos por el principio de la misma (cabecera)⇒ filosofía
LIFO

• Definición
<pila> ::= <cabecera> + {<nodo>}
<cabecera> ::= <enlace>
<enlace> ::= (<<ReferenciaNodo>> | NULL)
<nodo> ::= <informacion> + <enlace>
<informacion> ::= <<dato>>{<<dato>>}
TAD Pila: operaciones
Creación de pila crearPila (nombrePila)

Comprobación del pilaVacia(nombrePila) → Booleano


estado pilaLlena(nombrePila) → Booleano

Inserción de push(nombrePila, valorInfo)


nodos
Extracción de pop(nombrePila) → informacion
nodos
Acceso a la cabecera(nombrePila) → informacion
cabecera*
* Opcional: Accede a la cabecera sin eliminarla

Acceso a los info(referenciaNodo) → Informacion


nodos siguiente(referenciaNodo) → Enlace

Modificación de los asignarInfo(referenciaNodo, valorInformacion)


nodos asignarEnlace(referenciaNodo, valorEnlace)
TAD Pila: ejemplos de aplicación
 Vuelta atrás en un navegador web

 Comando “undo” en un editor

 Secuencia de métodos activos en la Java Virtual Machine:

bar • Cuando se invoca un método, se


main() { PC = 1 inserta en la pila una nueva entrada
int i = 5; m=6
foo(i);
• Por cada método se guardan:
}
foo variables locales
foo(int j) {
PC = 3 valor devuelto
int k;
j=5 contador de programa
k = j+1;
k=6
bar(k);
• Cuando el método finaliza se saca
}
ese elemento de la pila y se devuelve
bar(int m) { main
el control al método que esté en la
… PC = 2
cabecera
} i=5
Colas
• Cola = colección ordenada de elementos homogéneos en la que sólo se pueden añadir
elementos por el final y se eliminan por el principio (frente)⇒ filosofía FIFO

• Definición
<cola> ::= <frente> + <final> + {<nodo>}
<frente> ::= <enlace>
<enlace> ::= (<<ReferenciaNodo>> | NULL)
<final> ::= <enlace>
<nodo> ::= <informacion> + <enlace>
< informacion > ::= <<dato>>{<<dato>>}
TAD Cola: operaciones
Creación de cola crearCola (nombreCola)

Comprobación del colaVacia(nombreCola) → Booleano


estado colaLlena(nombreCola) → Booleano

Inserción de encolar(nombreCola, valorInfo)


nodos
Extracción de desencolar(nombreCola) → informacion
nodos
Acceso a la cabecera(nombreCola) → informacion
cabecera*
* Opcional: Accede a la cabecera sin eliminarla

Acceso a los info(referenciaNodo) → Informacion


nodos siguiente(referenciaNodo) → Enlace

Modificación de los asignarInfo(referenciaNodo, valorInformacion)


nodos asignarEnlace(referenciaNodo, valorEnlace)
TAD Cola: casos particulares
• Colas circulares
– Implementación estática como array
– Referencia al primero y al último
– Aritmética módulo C (Capacidad de la cola)
– Llevar la cuenta del número de elementos
TAD Cola: casos particulares
• Colas de prioridad
TAD Cola: ejemplos de aplicación

• Listas de espera
• Acceso a recursos compartidos dedicados (v.g., impresoras)
• Multiprogramación de la CPU
Listas Doblemente Enlazadas
• Relación lineal en ambos sentidos
• Enlace a predecesor y antecesor en cada nodo
• Recorrido puede ser en ambos sentidos
• Pueden ser simples u ordenadas

• Definición:
<lde> ::= <comienzo> + {<nodo>}
<comienzo> :: = <enlace>
<enlace> ::= (<<ReferenciaNodo>> | NULL)
<nodo> ::= <informacion> + <predecesor> + <sucesor>
<predecesor> ::= <enlace>
<sucesor> ::= <enlace>
<informacion> ::= <<dato>>{<<dato>>}

Вам также может понравиться