Está en la página 1de 63

Tema 2 TAD Lineales: Pila, Cola y Lista

Objetivos

‰ Conocer los TAD lineales, su funcionamiento y aplicaciones


‰ Conocer la especificación de cada uno de ellos
‰ Saber realizar implementaciones alternativas
‰ Saber usar los tipos lineales para resolver problemas
‰ Conocer y utilizar los contenedores equivalentes de la STL

Contenidos

2.1 Introducción a las estructuras lineales


2.2 El TAD Pila
2.2.1 Conceptos
2.2.2 Especificación algebraica
2.2.3 Implementación
2.2.4 Consideraciones sobre TAD basados en punteros
2.2.5 El contenedor stack de la STL

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 1


Tema 2 TAD Lineales: Pila, Cola y Lista

Contenidos

2.3 El TAD Cola


2.3.1 Conceptos
2.3.2 Especificación algebraica
2.3.3 Implementación
2.3.4 El contenedor queue de la STL
2.3.5 El TAD Doble cola

2.4 El TAD Lista


2.4.1 Conceptos
2.4.2 Lista con índices
2.4.3 Lista con iteradores
2.4.4 Los contenedores vector y list de la STL

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 2


Tema 2 TAD Lineales: Pila, Cola y Lista

Duración
‰ 5 clases (7.5 h)

Bibliografía

‰ Data Structures and Algorithms in C++


Autor: Michael T. Goodrich, Roberto Tamassia, David M. Mount
Editorial: John Wiley & Sons, Inc.
Año: 2004
Págs. 143 – 252
‰ Estructuras de datos y métodos algorítmicos
Autor: Narciso Martí Oliet y otros
Editorial : Prentice-Hall, 2004
Págs. 39 – 146
‰ Diseño de programas. Formalismo y abstracción
Autor: Ricardo Peña Marí
Editorial : Prentice-Hall, 1999
Págs. 227 – 234

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 3


Tema 2 TAD Lineales: Pila, Cola y Lista
2.1 Introducción a las estructuras lineales

‰ Estructuras lineales → importantes porque aparecen con frecuencia en muchos problemas

‰ Ejemplos: una cola de clientes de un banco, la pila de ejecución de un programa, los


caracteres de una cadena o las páginas de un libro

‰ Características:
5 existe un elemento llamado primero
5 existe un elemento llamado último
5 cada elemento, excepto el primero, tiene un único predecesor
5 cada elemento, excepto el último, tiene un único sucesor

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 4


Tema 2 TAD Lineales: Pila, Cola y Lista

‰ Operaciones básicas:
5 crear la estructura vacía
5 insertar un elemento
5 borrar un elemento
5 obtener un elemento

‰ Para definir claramente el comportamiento de la estructura es necesario determinar en qué


posición se inserta un elemento nuevo y qué elemento se borra o se obtiene

‰ Principales estructuras lineales: pilas, colas y listas

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 5


Tema 2 TAD Pila
2.2 El TAD Pila
2.2.1 Conceptos

‰ Una pila es un contenedor de objetos que son insertados y


eliminados de acuerdo con el principio de que el último en
entrar es el primero en salir (LIFO, Last Input First Output)

Apilar Desapilar
Cima de
‰ Los elementos se insertan de uno en uno (apilar) la pila
a3
‰ Se sacan en el orden inverso al cual se han insertado
(desapilar) a2
‰ El único elemento que se puede observar dentro de
la pila es el último insertado (cima) a1

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 6


Tema 2 TAD Pila

‰ Aplicaciones:
5 estructuras auxiliares en numerosos algoritmos y esquemas de programación:
ƒ recorridos de árboles y grafos
ƒ evaluación de expresiones
ƒ conversión entre notaciones de expresiones (postfija, prefija, infija)

5 gestión de los registros de activación de los subprogramas activos durante la ejecución


de un programa
5 los editores de texto proporcionan normalmente un botón deshacer que cancela las
operaciones de edición recientes y restablece el estado anterior del documento. La
secuencia de operaciones recientes se mantiene en una pila
5 los navegadores permiten habitualmente volver hacia atrás en la secuencia de páginas
visitadas. Las direcciones de los sitios visitados se almacenan en una pila

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 7


Tema 2 TAD Pila
2.2.2 Especificación algebraica

espec pilas
usa booleanos
parámetro formal
género elemento
fpf Gen (pila) =
género pila
operaciones Cons (pila) =
creaPila: Æ pila Mod (pila) =
apilar: pila elemento Æ pila
parcial desapilar: pila Æ pila
parcial cima: pila Æ elemento
vacía?: pila Æ booleano
dominios de definición p: pila; e: elemento
Obs (pila) =

ecuaciones p: pila; e: elemento


desapilar (apilar (p, e)) =
cima (apilar (p, e)) =
vacia? (creaPila) =
vacia? (apilar (p, e)) =
fespec

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 8


Tema 2 TAD Pila

‰ El conjunto de generadoras es libre, ya que cualquier término formado por las operaciones
generadoras denota siempre un valor distinto del TAD Pila

‰ Los patrones necesarios para representar todas las posibles pilas se obtienen del conjunto
de las operaciones generadoras
5 creaPila: representa la pila sin ningún elemento (pila vacía)
5 apilar(p, e): representa cualquier pila con, al menos, un elemento

‰ Las operaciones desapilar y cima no están definidas para la pila vacía

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 9


Tema 2 TAD Pila
2.2.3 Implementación

Interfaz informal

‰ Paradigma TAD:
5 Es necesario especificar el tipo independientemente de su implementación
5 Una interfaz es una lista de métodos que cualquier implementación del tipo debe
proporcionar
‰ Aunque C++ no soporta de forma adecuada la definición de interfaces, para cada tipo
presentaremos una interfaz informal
template <typename T>
Pila {
public:
Pila();
bool esVacia() const;
const T& cima() const throw(PilaVaciaExcepcion);
void apilar (const T& objeto);
void desapilar() throw(PilaVaciaExcepcion);
}

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 10


Tema 2 TAD Pila

Transformación de la notación algebraica a OO

‰ La operación constante creaPila se convierte en el constructor de la clase

‰ El parámetro cuyo tipo es el que aparece en el género se convierte en el objeto sobre el


que se aplica el método
ƒ esVacía, cima y desapilar se transforman en métodos sin parámetros
ƒ apilar se transforma en un método con un único parámetro

‰ Las operaciones parciales (cima y desapilar) se convierten en métodos que lanzan


excepciones para el subconjunto del dominio para el que no están definidas

‰ Las operaciones observadoras (cima y vacía?) se implementan como métodos


constantes

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 11


Tema 2 TAD Pila
Mediante una tabla

elementos e1 e2 e3 ... en ...


n
0 1 2 ... n-1 ... capacidad - 1
indCima

template <typename T>


class PilaTabla {
public:
PilaTabla(int tam = 10);
PilaTabla(const PilaTabla& p);
bool esVacia() const;
const T& cima() const throw(PilaVaciaExcepcion);
void apilar (const T& objeto) throw(PilaLlenaExcepción);
void desapilar throw(PilaVaciaExcepcion);
~PilaTabla ();
private:
int capacidad;
T* elementos;
int indCima;
}

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 12


Tema 2 TAD Pila

‰ Consideraciones:
5 si la pila no está vacía, el elemento almacenado en elementos[indCima - 1] corresponde a
la cima de la pila
5 elementos[0] ≡ fondo de la pila
5 indCima = 0 ≡ pila vacía
‰ Ventaja: todas las operaciones de la interfaz tienen un coste temporal constante O(1)
‰ Inconvenientes:
5 reservar espacio de memoria para el máximo previsto de elementos
5 gestionar pila llena
• lanzar una excepción
• usar la clase vector de la STL

‰ Opciones para controlar la parcialidad o situaciones de error


1. controlar el posible error dentro de la operación
2. proporcionar suficientes operaciones para que el propio usuario evite el error (como
sucede en la clase stack de la STL)

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 13


Tema 2 TAD Pila
‰ En C++, se puede hacer una reserva dinámica de la memoria para los arrays mediante el
operador new
‰ Por esa razón, en la parte privada de la clase no se declara un tamaño para el array
elementos

‰ Será el constructor el que reserve el espacio necesario en función del tamaño especificado
como parámetro

PilaTabla(int tam = 10)


inicio
indCima = 0;
capacidad = tam;
elementos = nuevo T[capacidad];
fin;

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 14


Tema 2 TAD Pila

‰ Constructor de copia para la clase PilaTabla

PilaTabla(const PilaTabla& p)
var
int i;
fvar;
inicio

fin;

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 15


Tema 2 TAD Pila
Mediante una lista enlazada template <typename T>
class PilaEnlazada {
typedef Nodo<T>* PtrNodo;
public:
c PilaEnlazada();
PilaEnlazada(const PilaEnlazada& p);
bool esVacia() const;
e1 e2 ... e3 const T& cima() throw(PilaVaciaExcepcion) const;
void apilar (const T& objeto);
void desapilar throw(PilaVaciaExcepcion);
~PilaEnlazada();
private:
PtrNodo c;
}

Ventajas:
5 todas las operaciones de la interfaz tienen un coste temporal constante ⇒ O(1)
5 no hay limitaciones de tamaño

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 16


Tema 2 TAD Pila

‰ Se define una clase Nodo, que representa a cada uno de los objetos que forman
la lista enlazada

template <typename T>


class Nodo {
typedef Nodo<T>* PtrNodo;
public:
Nodo(const T& objeto);
Nodo(const T& objeto, PtrNodo psig);
Nodo(const Nodo& n);
const T& getObj() const;
PtrNodo getSig() const;
void setObj(const T& objeto);
void setSig(PtrNodo psig);
private:
T obj;
PtrNodo sig;
}

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 17


Tema 2 TAD Pila
2.2.4 Consideraciones sobre TAD basados en memoria dinámica

‰ Si se realiza una asignación entre dos variables de tipo puntero (ej., p = q), no se realiza una
copia del valor del tipo (p.e. una pila completa), sino que se duplica la forma de acceder a
ella

p 4 6 8

q 1 3 5

4 6 8
p

q 1 3 5

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 18


Tema 2 TAD Pila

‰ Constructor de copia para la clase PilaEnlazada


PilaEnlazada(const PilaEnlazada& p)
var
PtrNodo pv, n, antn;
fvar;
inicio
c = NULO;
pv = p.c;
si pv ≠ NULO entonces
n = nuevo Nodo<T>(pv->getObj());
c = n;
antn = n;
pv = pv->getSig();
mientras pv ≠ NULO hacer
n = nuevo Nodo<T>(pv->getObj());
antn->setSig(n);
antn = n;
pv = pv->getSig();
fmientras;
fsi
fin;

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 19


Tema 2 TAD Pila

‰ Cuando dejamos de necesitar una estructura dinámica, debemos ocuparnos de liberar la


memoria
‰ En caso contrario, esos objetos seguirán existiendo en memoria aunque no podamos
acceder a ellos (es el caso de la pila formada por los elementos 4-6-8 de la figura anterior)

‰ Método destructor para la clase PilaEnlazada:

~PilaEnlazada()
inicio
mientras ⎤ esVacia() hacer
desapilar();
fmientras;
fin;

‰ Método destructor para la clase PilaTabla:

~PilaTabla()
inicio
liberar [ ] elementos;
fin;

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 20


Tema 2 TAD Pila
2.2.4 El contenedor stack de la STL

‰ Uso:
#include <stack>
// …
stack<tipo_base> p;

‰ Operaciones básicas:

stack() constructor
stack(const stack&) constructor de copia
stack& operator=(const stack&) operador de asignación
bool empty() const esVacia
const tipo_base& top() const cima
void push(const tipo_base&) apilar
void pop() desapilar

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 21


Tema 2 TAD Cola
2.3 El TAD Cola

2.3.1 Conceptos

‰ Los elementos se añaden por el extremo final, y se eliminan por el extremo opuesto: frente

‰ El único elemento observable en todo momento es el primero que fue insertado

‰ Se le suele denominar estructura FIFO (First Input First Output).

Aplicaciones

¾ Colas de trabajos a realizar por una impresora

¾ Asignación de tiempo de procesador a los procesos en un sistema multiusuario (sin


prioridad)
¾ Simular situaciones reales: cajero automático, llamadas en espera, ...

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 22


Tema 2 TAD Cola
2.3.2 Especificación algebraica

espec colas
usa booleanos
parámetro formal
género elemento
fpf
género cola
operaciones
creaCola: Æ cola
añadir: cola elemento Æ cola
parcial eliminar: cola Æ cola
parcial primero: cola Æ elemento
vacía?: cola Æ booleano
dominios de definición c: cola; e: elemento

...
2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 23
Tema 2 TAD Cola

‰ Las operaciones son:


Gen (cola) =
Mod (cola) =
Obs (cola) =

‰ ¿El conjunto de generadoras es libre?

‰ Los patrones necesarios para representar todas las posibles colas se obtienen del conjunto
de las operaciones generadoras
creaCola: representa la cola sin ningún elemento (cola vacía)
añadir(c, e): representa cualquier cola con, al menos, un elemento

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 24


Tema 2 TAD Cola

ecuaciones c: cola; e: elemento


eliminar (añadir (c, e)) =

primero (añadir (c, e)) =

vacia? (creaCola) =
vacia? (añadir (c, e)) =

fespec

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 25


Tema 2 TAD Cola

2.3.3 Implementación

Interfaz informal

template <typename T>


Cola {
public:
Cola();
bool esVacia() const;
const T& primero() const throw(ColaVaciaExcepcion);
void añadir(const T& objeto);
void eliminar() throw(ColaVaciaExcepcion);
}

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 26


Tema 2 TAD Cola
Cola

primero último Ventaja:


todas las operaciones de la interfaz tienen
e1 e2 ... en un coste temporal constante ⇒ O(1)

template <typename T>


class Cola {
typedef Nodo<T>* PtrNodo;
public:
Cola();
Cola(const Cola& p);
bool esVacia() const;
const T& primero() const throw(ColaVaciaExcepcion);
void añadir(const T& objeto);
void eliminar() throw(ColaVaciaExcepcion);
~Cola();
private:
PtrNodo primero, ultimo;
}

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 27


Tema 2 TAD Cola

Cola() void eliminar() throw(ColaVaciaExcepcion);


inicio var
primero = ultimo = NULO; PtrNodo inicio;
fin; fvar;
inicio
si esVacia() entonces
void añadir(const T& objeto) lanzar ColaVaciaExcepcion();
var fsi;
PtrNodo n; inicio = primero;
fvar; si primero == ultimo entonces
inicio ultimo = NULO;
n = nuevo Nodo<T>(objeto); fsi;
si esVacia() entonces primero = primero->getSig();
primero = n; liberar inicio;
sino fin;
ultimo->setSig(n);
fsi;
ultimo = n;
fin;

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 28


Tema 2 TAD Cola
2.3.4 El contenedor queue de la STL

‰ Uso:
#include <queue>
// …
queue<tipo_base> c;

‰ Operaciones básicas:

queue() constructor
queue(const queue&) constructor de copia
queue& operator=(const queue&) operador de asignación
bool empty() const esVacia
const tipo_base& front() const primero
void push(const tipo_base&) añadir
void pop() eliminar

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 29


Tema 2 TAD Cola
2.3.5 El TAD Doble Cola

‰ Permite consultar, añadir y eliminar elementos en cualquiera de los dos extremos de la


estructura lineal
‰ Recibe también el nombre de bicola

Especificación algebraica Gen (dobleCola) =


espec dobles-colas Cons (dobleCola) =
usa booleanos, naturales
Mod (dobleCola) =
parámetro formal
género elemento
fpf Obs (dobleCola) =
género dobleCola
operaciones
creaDC: Æ dobleCola parcial -izq: dobleCola Æ dobleCola
+izq: elemento dobleCola Æ dobleCola parcial -dch: dobleCola Æ dobleCola
+dch: dobleCola elemento Æ dobleCola parcial izq: dobleCola Æ elemento
vacía?: dobleCola Æ booleano parcial dch: dobleCola Æ elemento ...
2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 30
Tema 2 TAD Cola

dominios de definición e: elemento; c: dobleCola


-izq (+izq (e, c))
-dch (+izq (e, c))
izq (+izq (e, c))
dch (+izq (e, c))

ecuaciones e, e1, e2: elemento; c: dobleCola


+dch (creaDC, e) =
+dch (+izq (e1, c), e2) =

-izq (+izq (e, c)) =

-dch (+izq (e, c)) =

esta ecuación es equivalente a las ecuaciones


-dch (+izq (e, creaDC)) =
-dch (+izq ( e1, +izq (e2, c))) =
...
2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 31
Tema 2 TAD Cola

izq (+izq (e, c)) =

dch (+izq (e, c)) =

esta ecuación es equivalente a las ecuaciones


dch (+izq (e, creaDC) =
dch (+izq (e1, +izq (e2, c))) =

vacía? (creaDC) =
vacía? (+izq (e, c)) =

fespec

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 32


Tema 2 TAD Cola

Implementación

Interfaz informal

template <typename T>


DobleCola {
public:
DobleCola();
bool esVacia() const;
const T& observarIzq() const throw(DobleColaVaciaExcepcion);
const T& observarDer() const throw(DobleColaVaciaExcepcion);
void añadirIzq(const T& objeto);
void añadirDer(const T& objeto);
void eliminarIzq() throw(DobleColaVaciaExcepcion);
void eliminarDer() throw(DobleColaVaciaExcepcion);
}

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 33


Tema 2 TAD Cola
Lista simplemente enlazada
Problema:
Doble cola
eliminar el elemento de la derecha tiene
primero último un coste temporal lineal ⇒ O(n)

e1 e2 ... en

Ventajas:
5 todas las operaciones de la interfaz tiene un coste
Lista doblemente enlazada temporal constante ⇒ O(1)

Doble cola 5 Los nodos centinelas simplifican las operaciones de


inserción y eliminación
primero último

e1 e2 ... en

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 34


Tema 2 TAD Cola
‰ Se define una clase DobleNodo, que representa a cada uno de los objetos que
forman la lista doblemente enlazada

template <typename T>


class DobleNodo {
typedef DobleNodo<T>* PtrDobleNodo;
public:
DobleNodo();
DobleNodo(PtrDobleNodo pant, PtrDobleNodo psig);
DobleNodo(const T& objeto, PtrDobleNodo pant, PtrDobleNodo psig);
DobleNodo(const DobleNodo& n);
const T& getObj() const;
PtrDobleNodo getSig() const;
PtrDobleNodo getAnt() const;
void setObj(const T& objeto);
void setSig(PtrDobleNodo psig);
void setAnt(PtrDobleNodo pant);
private:
T obj;
PtrDobleNodo sig;
PtrDobleNodo ant;
}

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 35


Tema 2 TAD Cola
‰ La clase DobleCola

template <typename T>


class DobleCola {
typedef DobleNodo<T>* PtrDobleNodo;
public:
DobleCola();
DobleCola(const Cola& p);
bool esVacia() const;
const T& observarIzq() const throw(DobleColaVaciaExcepcion);
const T& observarDer() const throw(DobleColaVaciaExcepcion);
void añadirIzq(const T& objeto);
void añadirDer(const T& objeto);
void eliminarIzq() throw(DobleColaVaciaExcepcion);
void eliminarDer() throw(DobleColaVaciaExcepcion);
~DobleCola();
private:
PtrDobleNodo primero, ultimo;
}

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 36


Tema 2 TAD Cola
void eliminarDer() throw (DobleColaVaciaExcepcion)
DobleCola() var
inicio PtrDobleNodo p;
primero = nuevo DobleNodo<T>(); fvar;
último = nuevo DobleNodo<T>(primero, NULO); inicio
primero->setSig(ultimo); si esVacia() entonces
fin; lanzar DobleColaVaciaExcepcion();
fsi;
p = ultimo->getAnt();
p->getAnt()->setSig(ultimo);
ultimo->setAnt(p->getAnt());
liberar p;
fin;

void añadirIzq(const T& objeto)


var
PtrDobleNodo n;
fvar;
inicio
n = nuevo DobleNodo<T>(objeto, primero, primero->getSig());
primero->setSig(n);
n->getSig()->setAnt(n);
fin;

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 37


Tema 2 TAD Cola

Uso:
#include <deque>
El contenedor deque de la STL // …
deque<tipo_base> dc;

deque() constructor
deque(const deque&) constructor de copia
deque& operator=(const deque&) operador de asignación
bool empty() const esVacia
Operaciones básicas: const tipo_base& front() const observarIzq
const tipo_base& back() const observarDer
void push_front(const tipo_base&) añadirIzq
void push_back(const tipo_base&) añadirDer
void pop_front() eliminarIzq
void pop_back() eliminarDer

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 38


Tema 2 TAD Lista

2.4 El TAD Lista


2.4.1 Conceptos

‰ Generalización de los TAD Pila, Cola y Doble Cola

‰ Secuencia de elementos en la que se permite el acceso para consultar, añadir o eliminar


elementos en cualquier posición

‰ Suelen utilizarse como base para la construcción de otros TAD y estructuras de datos:

ƒ matrices dispersas (listas de listas)


ƒ árboles n-arios (listas de nodos "hermanos")
ƒ grafos (listas de adyacencia)

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 39


Tema 2 TAD Lista

‰ Existen diversas formas de generar las listas. En nuestro caso elegimos un conjunto de
operaciones pequeño y libre

‰ Nos apoyamos en la definición recursiva de secuencia de elementos: colección de


elementos del mismo tipo que:
; bien es vacío, en cuyo caso se denomina secuencia vacía
; bien se obtiene tras añadir por la izquierda un elemento a otra secuencia existente

‰ Operaciones generadoras

[]
Gen (lista) =
+izq (e, l)

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 40


Tema 2 TAD Lista
2.4.2 Lista con índices
‰ Existe una posición (índice) que sirve de referencia para las operaciones de inserción,
consulta y modificación en cualquier posición
espec listas Especificación algebraica
usa booleanos, naturales
parámetro formal
género elemento
operaciones
_ == _: elemento elemento Æ booleano
_ ≠ _: elemento elemento Æ booleano
fpf
género lista
operaciones
[ ]: Æ lista parcial -izq: lista Æ lista
+izq: elemento lista Æ lista parcial -dch: lista Æ lista
[ _ ] : elemento Æ lista parcial izq: lista Æ elemento
_ & _ : lista lista Æ lista parcial dch: lista Æ elemento
+dch: lista elemento Æ lista
longitud: lista Æ natural
vacía?: lista Æ booleano ...
está?: elemento lista Æ booleano

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 41


Tema 2 TAD Lista

parcial insertar: lista nat elemento Æ lista {insertar elemento i-ésimo}


parcial eliminar: lista nat Æ lista {eliminar elemento i-ésimo}
parcial modificar: lista nat elemento Æ lista {modificar elemento i-ésimo}
parcial _ [ _ ] : lista nat Æ elemento {elemento i-ésimo}
parcial pos: elemento lista Æ natural {posición del elemento}

dominios de definición e: elemento; l: lista; i: natural


-izq (+izq (e, l))
-dch (+izq (e, l))
izq (+izq (e, l))
dch (+izq (e, l))
insertar (l, i, e) está definido sólo si (1 ≤ i) ∧ (i ≤ long (l) + 1)
eliminar (l, i) está definido sólo si (1 ≤ i) ∧ (i ≤ long (l))
modificar (l, i, e) está definido sólo si (1 ≤ i) ∧ (i ≤ long (l))
l[i] está definido sólo si (1 ≤ i) ∧ (i ≤ long (l))
pos (e, l) está definido sólo si está? (e, l)

...
2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 42
Tema 2 TAD Lista

ecuaciones e, e1, e2: elemento; l: lista; i: natural


[e] =

[]&l=
+izq (e, l1) & l2 =

long ([ ]) =
long (+izq (e, l)) =

está? (e, [ ]) =
está? (e1, +izq (e2, l)) =

insertar ([ ], i, e) =
insertar (+izq (e1, l), i, e2)) =

...
2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 43
Tema 2 TAD Lista
eliminar (+izq (e, l), i) =

modificar (+izq (e1, l), i, e2) =

+izq (e, l) [i] =

pos (e1, +izq (e2, l)) =

fespec

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 44


Tema 2 TAD Lista
Implementación

Interfaz informal template <typename T>


Lista {
public:
Lista();
bool esVacia() const;
int longitud() const;
void añadirIzq(const T& objeto);
void añadirDch(const T& objeto);
void eliminarIzq() throw(ListaVaciaExcepcion);
void eliminarDch() throw(ListaVaciaExcepcion);
const T& observarIzq() const throw(ListaVaciaExcepcion);
const T& observarDch() const throw(ListaVaciaExcepcion);
void concatenar(const Lista& list);
bool pertenece(const T& objeto) const;
void insertar(int posicion, const T& objeto) throw(PosicionErroneaExcepcion);
void eliminar(int posicion) throw(PosicionErroneaExcepcion);
void modificar(int posicion, const T& objeto) throw(PosicionErroneaExcepcion);
const T& observar(int posicion) const throw(PosicionErroneaExcepcion);
int posicion(const T& objeto) const throw(ObjetoInexistenteExcepcion);
~Lista();
}

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 45


Tema 2 TAD Lista

Lista simplemente enlazada

‰ La implementación más sencilla del TAD Lista es mediante una lista simplemente enlazada:

primero ultimo

e1 e2 ... en

template <typename T>


class Lista { n
public: num
// operaciones del TAD
private:
PtrNodo primero, ultimo;
int num;
}

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 46


Tema 2 TAD Lista
‰ En la siguiente tabla se observa el coste de las operaciones, para el peor caso, utilizando
este tipo de representación

operación coste operación coste


añadirIzq longitud
eliminarIzq pertenece
observarIzq insertar

esVacía eliminar

concatenar modificar

añadirDch observar

observarDch posición

eliminarDch

n ≡ longitud de la lista

‰ ¿Cómo se podría mejorar el coste de la operación eliminarDch?

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 47


Tema 2 TAD Lista

void eliminarDch() throw(ListaVaciaExcepcion);


Lista() var
inicio PtrNodo anterior;
primero = ultimo = NULO; fvar;
num = 0; inicio
fin; si esVacia() entonces
lanzar ListaVaciaExcepcion();
fsi
void añadirIzq(const T& objeto); si num == 1entonces
var liberar primero;
PtrNodo n; primero = ultimo = NULO;
fvar; si no
inicio anterior = primero;
n = nuevo Nodo(objeto, primero); mientras anterior->getSig() ≠ ultimo hacer
primero = n; anterior = anterior->getSig();
si num == 0 entonces fmientras
ultimo = n; anterior->setSig(NULO);
fsi; liberar ultimo;
num++; ultimo = anterior;
fin; fsi
num--;
fin;

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 48


Tema 2 TAD Lista
2.4.3 Lista con iteradores

‰ Un iterador es una generalización del concepto de puntero


‰ Un iterador asociado a una lista está formado por:
ƒ una lista L
ƒ una posición en L (posición actual)
ƒ un conjunto de operaciones para desplazar la posición actual dentro de L

‰ Un iterador abstrae los aspectos de la representación interna de la lista y, en general, de


cualquier contenedor, durante los desplazamientos y accesos para lectura o escritura ⇒
proporciona una interfaz de uso independiente del contenedor
‰ La ganancia en eficiencia de los iteradores se logra cuando se pretende realizar accesos
sucesivos a elementos consecutivos de una lista
‰ Los accesos aleatorios mediante iteradores pueden no ser posibles o ser tan ineficientes
como los accesos mediante índices

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 49


Tema 2 TAD Lista

Especificación algebraica de iterador

espec iteradores dominios de definición e: elemento; l: lista; it: iterador


usa listas, naturales
avanzar (l, it) está definido sólo si 1 ≤ posición(l, it) ≤ longitud (l)
parámetro formal
observar (+izq(e, l), it) ∧
género elemento
1 ≤ posición (+izq(e,l), it) ≤ longitud (+izq(e,l))
fpf
it es iterador de la lista que interviene en cada operación
género iterador
operaciones
ecuaciones l: lista; it: iterador
inicio: lista Æ iterador
posición (l, inicio (l)) = 1
parcial avanzar: lista iterador Æ iterador
posición (l, avanzar (l, it)) = 1 + posición (l, it)
parcial observar: lista iterador Æ elemento
parcial posición: lista iterador Æ natural
observar (l, it) = l[posición (l, it)]
fespec

Gen (iterador) = NOTA: los iteradores pueden posicionarse desde el primer


elemento de la lista hasta la posición siguiente al último
Obs (iterador) =
elemento (denominaremos a esta posición final de lista)

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 50


Tema 2 TAD Lista
Enriquecimiento de la especificación algebraica de lista con las operaciones con iteradores
usa ..., iteradores
...
operaciones
parcial insertar: lista iterador elemento Æ lista {inserta un elemento delante del iterador }
parcial eliminar: lista iterador Æ lista {elimina el elemento posicionado en el iterador}
parcial modificar: lista iterador elemento Æ lista {modifica el elemento posicionado en el iterador}
parcial observar: lista iterador Æ elemento {obtiene el elemento posicionado en el iterador}
principio: lista Æ iterador {sitúa el iterador en el primer elemento de la lista}
final: lista Æ iterador {sitúa el iterador en la posición siguiente al último elemento}
parcial ponerIterador: lista natural Æ iterador {sitúa el iterador en la posición indicada por el parámetro}

dominios de definición e: elemento; l: lista; it: iterador; n: natural


insertar (l, it, e) está definido sólo si (1 ≤ posición(l, it)) ∧ (posición(l, it) ≤ longitud (l) + 1)
eliminar (l, it) está definido sólo si (1 ≤ posición(l, it) ∧ (posición(l, it) ≤ longitud (l))
modificar (l, it, e) está definido sólo si (1 ≤ posición(l, it)) ∧ (posición(l, it) ≤ longitud (l))
observar (l, it) está definido sólo si (1 ≤ posición(l, it)) ∧ (posición(l, it) ≤ longitud (l))
ponerIterador (l, n) está definido sólo si (1 ≤ n) ∧ (n ≤ longitud (l) + 1)
it es iterador de la lista que interviene en cada operación

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 51


Tema 2 TAD Lista

‰ Ecuaciones para las nuevas operaciones:

ecuaciones e: elemento; l: lista; n: natural; it: iterador

principio (l) =

final (l) =

ponerIterador (l, n) =

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 52


Tema 2 TAD Lista

‰ La semántica del resto de las operaciones con iteradores (insertar, eliminar, modificar y
observar) se describe en función de las operaciones análogas con índices. Simplemente
se utiliza como índice el resultado de la operación posición (l, it)
‰ Aunque tengan el mismo nombre, al tener parámetros distintos, entendemos que estamos
haciendo sobrecargas de operaciones

ecuaciones e: elemento; l: lista; it: iterador


insertar (l, it, e) =

eliminar (l, it) =

modificar (l, it, e) =

observar (l, it) =


fespec

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 53


Tema 2 TAD Lista
Implementación
template <typename T>
Interfaz informal Lista {
public:

void insertar(const Iterador& it, const T& objeto);
void eliminar(const Iterador& it) throw(PosicionErroneaExcepcion);
void modificar(const Iterador& it, const T& objeto) throw(PosicionErroneaExcepcion);
const T& observar(const Iterador& it) const throw(PosicionErroneaExcepcion);
const Iterador& principio() const;
const Iterador& final() const; {sitúa el iterador en la siguiente posición al último elemento}
const Iterador& ponerIterador(int posicion) const throw(IndiceErroneoExcepcion);
}

template <typename T>


Iterador{
public:
void avanzar(const Lista& L) throw(PosicionErroneaExcepcion);
const T& observar(const Lista& L) const throw(PosicionErroneaExcepcion);
int posicion(const Lista& L) const;
}

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 54


Tema 2 TAD Lista

‰ Como todos los tipos vistos hasta hora, los iteradores tienen una interfaz común,
independientemente del contenedor al que va a estar asociado
‰ Sin embargo, su representación y la implementación de sus métodos dependerá de la
representación elegida para el contenedor (en este caso para la lista)
‰ Con una implementación de lista simplemente enlazada, el iterador consiste en un puntero
al nodo anterior para que las operaciones de inserción y borrado sean eficientes. Además,
la lista debe tener un nodo centinela al principio para poder tratar al primer elemento

Lista
num primero último

e1 ... en

anterior

Iterador
En este gráfico vemos un iterador apuntando al elemento
e1. Este hecho representa, conceptualmente, al iterador
posicionado en el elemento e2

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 55


Tema 2 TAD Lista
template <typename T>
class Lista {
typedef Nodo<T>* PtrNodo; hacemos a la clase Lista amiga de la clase iterador para
public: que los métodos de la clase Lista puedan acceder a su
parte privada
class Iterador {
friend class Lista<T>;
public:
void avanzar(const Lista& L) throw(PosicionErroneaExcepcion);
const T& observar(const Lista& L) const throw(PosicionErroneaExcepcion);
int posicion(const Lista& L) const;
private:
PtrNodo anterior;
Iterador (PtrNodo i);
}; el constructor de iterador es privado para que sólo lo utilicen
… los métodos de la clase Lista
void insertar(const Iterador& it, const T& objeto);
void eliminar(const Iterador& it) throw(PosicionErroneaExcepcion);
void modificar(const Iterador& it, const T& objeto) throw(PosicionErroneaExcepcion);
const T& observar(const Iterador& it) const throw(PosicionErroneaExcepcion);
const Iterador& principio() const;
const Iterador& final() const;
const Iterador& ponerIterador(int posicion) const throw(IndiceErroneoExcepcion);
private:
PtrNodo primero, ultimo; ‰ La clase Iterador es una clase anidada de la
int num;
}
clase Lista. Con esto se consiguen iteradores
propios para cada TAD

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 56


Tema 2 TAD Lista
void insertar(const T& objeto, Iterador& it);
Lista() inicio
inicio it.anterior->setSig(nuevo Nodo(objeto, it.anterior->getSig()));
primero = ultimo = nuevo Nodo(); si (it.anterior == ultimo) entonces ultimo = it.anterior -> getSig(); fsi
num = 0; it.anterior = it.anterior->getSig();
fin; num++;
fin;

void eliminar(const Iterador& it) throw(PosicionErroneaExcepcion);


inicio
si (it.anterior->getSig() == NULL) lanzar PosicionErroneaExcepcion();
sino
PtrNodo p = it.anterior->getSig();
si p = ultimo entonces ultimo = it.anterior; fsi
it.anterior->setSig(p->getSig());
delete p;
num--;
fsi
fin;

const Iterador& principio() const Iterador& final()


inicio inicio
devuelve nuevo Iterador (primero); devuelve nuevo Iterador (ultimo);
fin; fin;

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 57


Tema 2 TAD Lista

‰ Hay que tener un especial cuidado con el uso de iteradores: se puede emplear un iterador
definido para una lista en operaciones con otra lista
‰ Puede evitarse incluyendo un tratamiento de excepciones que compruebe que el iterador
pertenece a la lista con la que se quiere operar:
ƒ recorriendo la lista hasta encontrar el nodo al que apunta el iterador: O(n)
ƒ incluyendo en la implementación del iterador un puntero a la lista a la que pertenece: O(1)

Lista
num primero último

e1 ... en

lista anterior

Iterador

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 58


Tema 2 TAD Lista
‰ Ejemplo de mejora de la eficiencia usando listas con iteradores:
ƒ Se desea saber el número de veces que aparece un elemento en una lista

template <typename T> template <typename T>


int ocurrencias(const Lista<T>& L, const T& elemento) int ocurrencias(const Lista<T>& L, const T& elemento)
{ {
int cont = 0; int cont = 0;
for (int i = 1 ; i <= L.longitud(); i++) for (typename Lista<T>::Iterador it = L.principio();
if (L.observar(i) == elemento) cont++; it != L.final(); it.avanzar(L))
return (cont); if (it.observar(L) == elemento) cont++;
} return (cont);

(a) acceso por índice }


(b) acceso con iteradores

ƒ Implementación dinámica con índices:


ƒ Implementación dinámica con iteradores:

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 59


Tema 2 TAD Lista
2.4.4 Los contenedores vector y list de la STL

‰ Características del contenedor vector:


ƒ Es una secuencia que soporta acceso aleatorio en tiempo a constante a sus elementos mediante
un índice
ƒ Las inserciones y eliminaciones en el final se realizan en un tiempo de ejecución O(1)
ƒ Las inserciones y eliminaciones al comienzo o en medio del vector tienen un coste temporal lineal
ƒ El número de elementos en el vector puede variar de forma dinámica (la administración de
memoria es automática)

‰ Características del contenedor list:


ƒ Está implementado como una lista doblemente enlazada ⇒ permite recorridos hacia delante y
hacia atrás (define iteradores bidireccionales)
ƒ Las inserciones y eliminaciones en los extremos se realizan en un tiempo de ejecución O(1)
ƒ Las inserciones no invalidan los iteradores a elementos de la lista. Las eliminaciones sólo invalidan
los iteradores que referencian a los elementos eliminados
ƒ Las operaciones de borrado o eliminación pueden cambiar los predecedores o sucesores de los
iteradores de una lista
ƒ También existe el contenedor slist, que implementa una lista simplemente enlazada

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 60


Tema 2 TAD Lista
El contenedor vector de la STL

Operaciones básicas:
vector() constructor
vector(const vector&) constructor de copia
vector& operator=(const vector&) operador de asignación
bool empty() const esVacia Uso:
int size() const longitud #include <vector>
const tipo_base& operator[](int n) const observar
// …
void push_back(const T&) añadirDer
vector<tipo_base> v;
void pop_back() eliminarDer
iterator begin() devuelve un iterador al comienzo del vector
iterator end() devuelve un iterador al final del vector
iterator insert(iterator pos, inserta x delante de pos
const tipo_base& x)
iterator erase(iterator pos) elimina el elemento que ocupa la posición pos

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 61


Tema 2 TAD Lista
El contenedor list de la STL
Uso:
#include <list>
// …
list<tipo_base> l;
Operaciones básicas:
list() constructor
list(const list&) constructor de copia
list& operator=(const lista&) operador de asignación
bool empty() const esVacia
int size() const longitud
iterator begin() devuelve un iterador al comienzo del vector
iterator end() devuelve un iterador al final del vector
iterator insert(iterator pos, inserta x delante de pos
const tipo_base& x)
iterator erase(iterator pos) elimina el elemento que ocupa la posición pos

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 62


Tema 2 TAD Lista
El concepto de bidirectional iterator de la STL

Expresiones válidas:

*i devuelve el elemento referenciado por el iterador i


*i = e modifica el elemento referenciado por i
++i / i++ avanza el iterador
--i / i-- retrocede el iterador

2005 -2006 Estructuras de Datos II I.T. en Informática de Gestión/Sistemas Universidad de Huelva 63

También podría gustarte