Está en la página 1de 30

Programacin y

Algoritmia


Un enfoque prctico y didctico
para el diseo de algoritmos



4 Estructuras Enlazadas

Lic. Oscar Ricardo Bruno, MDU





Contenido


Estructuras Enlazadas__________________________________________________ 3
Introduccin _______________________________________________________ 3
Estructuras enlazadas vs. estructuras indexadas _________________________ 3
Estructuras enlazadas con asignacin dinmica en memoria _______________ 3
El tipo de dato Puntero_______________________________________________ 5
Acceso a datos mediante apuntadores __________________________________ 7
Tipos de datos autorreferenciados o recursivos___________________________ 8
Estructuras de datos dinmicas lineales_________________________________ 9
El tipo pila _________________________________________________________ 9
Insertar elemento en una pila:________________________________________ 11
Desapilar: leer y eliminar un elemento ________________________________ 11
El tipo cola________________________________________________________ 12
Aadir un elemento Encolar: ________________________________________ 12
Leer un elemento de una cola Eliminar primero: ________________________ 13
El tipo lista________________________________________________________ 13
Listas simplemente enlazadas ________________________________________ 13
Eliminar elementos en una lista ______________________________________ 14
Algoritmo de insercin______________________________________________ 16
Listas circulares ___________________________________________________ 18
Operaciones bsicas con listas circulares _______________________________ 19
Aadir un elemento ________________________________________________ 19
Eliminar un elemento de una lista circular _____________________________ 20
Listas doblemente enlazadas _________________________________________ 24
Operaciones bsicas con listas doblemente enlazadas ____________________ 24
Aadir un elemento ________________________________________________ 24
Eliminar un elemento de una lista doblemente enlazada __________________ 27
A modo de sntesis con estructuras enlazadas ___________________________ 30
Estructuras Enlazadas

Objetivos de aprendizaje
Dominando los temas del presente capitulo Usted podr.
1. Manejar estructuras complejas.
2. Introducirse a la semntica de direcciones
3. Comprender como se asigna memoria dinmicamente en tiempo de ejecucin.
4. Conocer estructuras enlazadas lineales
5. Diferenciar entre estructuras indexadas y estructuras enlazadas


Introduccin:
En el presente trabajo se incorpora el concepto de asignacin dinmica en memoria.
Esto permite romper con la limitacin de tamao fijo que proporcionan las tablas
cuando es necesario trabajar con coleccin de datos el mismo tipo en memoria.
Para esto se incorporan los conceptos de estructuras enlazadas, punteros y asignacin
dinmica en memoria.

Estructuras enlazadas vs. estructuras indexadas
Como vimos una tabla es una secuencia de datos del mismo tipo donde a cada elemento
se puede acceder a travs de un ndice. En esta estructura las posiciones de memoria son
contiguas y se las puede ir recorriendo con solo incrementar el ndice. En estas
estructuras el primer elemento lgico coincide con el primero fsico, es decir se
comienza desde la primera posicin, y el siguiente lgico coincide con el siguiente
fsico, es decir al prximo elemento se accede incrementando en uno el ndice. Estas
estructuras, con esta organizacin son estructuras indexadas. Las estructuras pueden
organizarse de forma diferente. El primer elemento lgico puede no coincidir con el
primero fsico, en ese caso, para conocer donde comienza lgicamente se debe saber la
posicin de ese primero. El siguiente elemento lgico no necesariamente debe estar en
la posicin contigua, para saber donde esta ser necesario tener algo que referencie la
posicin del siguiente elemento. Una estructura con esta organizacin es una estructura
enlazada. Las estructuras enlazadas tienen la particularidad que se necesita conocer la
posicin del primer elemento y en cada posicin se tiene un registro, llamado nodo, con
al menos dos campos, uno que contenga la informacin y otro que indique o referencie
donde se encuentra el siguiente que no necesariamente debe ser el contiguo.
Por otro lado vimos que si se quiere definir en memoria una coleccin de datos del
mismo tipo mediante una tabla esta requiere establecer una capacidad mxima. Estas
son estructuras con tamao fijo, el mismo no puede ser modificado en tiempo de
ejecucin. Existe entonces riesgo que la cantidad de posiciones definidas en tiempo de
declaracin no alcancen, o, que se utilicen muy pocas de las posiciones definidas
haciendo un uso poco eficiente de los recursos.

Estructuras enlazadas con asignacin dinmica en memoria
Una estructura con asignacin dinmica es un conjunto de elementos de tipo
homogneo donde los mismos no ocupan posiciones contiguas de memoria, pueden
aparecer fsicamente dispersos manteniendo un orden lgico y son instanciados y/o
liberados en tiempo de ejecucin.

Operaciones con listas
1. Crear una estructura
2. Recorrerla, parcial o totalmente
3. Agregar o insertar nuevos elementos o nodos en distintos lugres y con criterio
variado.
4. Localizar un elemento en particular en la estructura
5. Borrar un elemento de posicion particular o previamente desconocida
La mayor facilidad de las listas es el enlace dinmico a travs de punteros que
permiten intercalar o eliminar valores sin un movimiento masivo de memoria, con solo
pedir memoria o liberarla y hacer simplemente los enlaces de los nodos involucraos.
Punteros
Es posible definir estructuras de datos complejas cuyo tamao puede cambiar en tiempo
de ejecucin, por lo que son denominadas estructuras de datos dinmicas. Se instancias
a travs de punteros.
Mediante la utilizacin de tablas se puede definir una secuencia de valores como:
TipoSecuencia = TIPO Tabla [1, LongitudMaxima] de elemento;
Con esta definicin se reserva espacio en tiempo de ejecucin para una cantidad fija de
elementos. Esta cantidad esta dada por el valor de LongitudMaxima.
Otra forma de definir una secuencia de valores seria por induccin o recursion:
La secuencia vaca es una secuencia
Un elemento concatenado a una secuencia es otra secuencia
De esta forma se declara el tipo sin especificar ninguna capacidad mxima, se define en
forma recursiva.
En esta definicin es necesario que cada elemento referencie con precisin el siguiente
elemento si es que este existe.
Una secuencia, con esta organizacin, como ya dijimos es una concatenacin de
registros llamados nodos de dos campos: uno para la informacin y otro para un
indicador al siguiente elemento. El siguiente elemento al que se referencia es un registro
del mismo tipo del actual, por referenciar a una estructura de su mismo tipo estas
estructuras se conocen como estructuras autoreferenciadas.
Para la asignacin dinmica en memoria, los elementos se enlazan a travs de un
determinado tipo de dato que disponen la mayora de lenguajes de programacin y que
se denominan puntero o apuntador, cuyos valores son referencias o punteros a variables
de un tipo.
TipoPunteroEntero = TIPO Apuntador a Entero;
Se hace una definicin de un tipo de dato con la particularidad que tendr como valor
una direccin de memoria. Se dir entonces que es un puntero al tipo de dato o que
apunta a determinado tipo de dato
Si de define
PunteroEntero = TipoPunteroEntero
Los posibles valores de PunteroEntero no sern enteros, sino referencias a enteros; esto
sera la direccin del espacio de memoria en la que se almacena el entero.
Ya se defini variable como un identificador que denota un espacio de memoria en el
que se almacena un valor del tipo asociado en la direccin.
Un valor apuntador es la direccin de una variable annima, se le asigna la direccin
a se crea en tiempo de ejecucin.
Para indicar que una variable puntero no referencia o apunta a ninguna a otra variable
se le debe asignar el valor NULO.
TipoInfo = TIPO Entero
//define la informacin que tendr el campo dato del nodo//
TipoPuntero = TIPO Apuntador a TipoNodo;
//Define un puntero que en cada instancia generara un nodo.
TipoNodo = TIPO < dato : TipoInfo; sgte : TipoPuntero >;
//Define un nodo con la informacin y la referencia al siguiente que es un puntero a la
siguiente direccin de memoria de la secuencia definida//
Se trata de una definicin recursiva o autorreferenciada siguiendo la definicin
inductiva de secuencia.
Una estructura enlazada utilizando punteros debe tener una variable que controle la
estructura, en general debe contener la direccin de memoria del primer nodo de la
misma, que debe ser de tipo puntero e inicialmente debe ser creada haciendo apuntar a
la misma al valor NULO, lo que indica que la secuencia esta vaca.
Con este tipo de estructura no es necesario especificar una capacidad mxima en la
declaracin, sino que se asigna espacio en tiempo de ejecucin, conforme se necesita, a
travs de los apuntadores, por lo que se obtienen dos importantes beneficios.
1. No se desaprovecha espacio cuando la secuencia tiene menos elementos que el
tamao mximo establecido.
2. El tamao de la secuencia no est limitado.
Solo se podra mencionar como desventaja el hecho que cada elemento adema de tener
la informacin propia debe destinar recursos para referenciar al siguiente, situacin que
puede estar a favor de las tablas. Con lar particularidades de cada estructura es
responsabilidad del programador seleccionar la ms idnea para cada caso que deba
resolver.
Como ya mencionamos estas estructuras de datos cuyo tamao puede variar en tiempo
de ejecucin se denominan estructuras de datos dinmicas, que son bsicas en
programacin, como: listas, pilas, colas y rboles binarios de bsqueda que sern
abordados en este capitulo y el siguiente.

El tipo de dato Puntero
Se ha definido un tipo de datos puntero como aquel cuyo dominio de valores est
formado por referencias o punteros a variables (direcciones de memoria) de un tipo
existente.
Si los tipos de datos se definen por sus valores y sus operaciones los valores que pueden
tener los punteros son los de direcciones de memoria o el valor NULO en caso de no
estar apuntando a una direccin definida y, entre las operaciones se pueden mencionar
la asignacin interna, la creacin o la destruccin, los lenguajes de programacin
ofrecen los mecanismos para estas operaciones.

Constantes y operaciones con punteros
No es posible el uso de literales para representar valores de tipo puntero salvo las
constantes simblicas que representan el valor NULO con sintaxis diferente segn el
lenguaje de programacin que se trate. NULO representa solo eso y no contiene un
valor de direccin de memoria vlido. Esta constante NULO es compatible de
asignacin y comparacin con cualquier tipo de dato apuntador, con independencia a
cualquiera sea el tipo de valores a los que apunta ste.
Los valores de tipo apuntador son datos internos propios de cada ejecucin del
programa, solo aceptan asignacin interna, no es correcto hacer asignaciones externas
leer o escribir con variables de tipo apuntador.
Las operaciones elementales de una variable de tipo apuntador son las de creacin de
un nuevo objeto y destruccin del objeto apuntado.
Para la creacin de un nuevo objeto apuntado dispondremos de la accin Nuevo. Esta
accin tiene un nico parmetro de tipo Apuntador a T, cualquiera sea el tipo de T, y su
efecto es el siguiente:
Reserva espacio de memoria suficiente para alojar una variable de tipo T
Asigna al el valor de la direccin de memoria que acaba de reservar, si es que se
dispone de espacio en memoria o el valor NULO en caso de no poder ejecutar la accin
de creacin.
El efecto de invocar a la accin Nuevo (Puntero) sera la creacin de una nueva variable
annima del tipo al que apunta el puntero, y la asignacin a pe de la direccin de
memoria donde se encuentra dicha variable. La nueva variable se denomina annima
porque no tiene identificador propio, y nicamente ser accesible a travs de la
direccin que la accin Nuevo ha asignado al parmetro puntero. La nueva variable est
recin creada y, por tanto, sin inicializar; no tiene un valor definido mientras no se le
asigne nada.
Aunque los lenguajes de programacin tienden a aliviar al programador de la
responsabilidad de liberar el espacio reservado a variables de tipo apuntador e
incorporan rutinas de recoleccin de basuras para liberar los espacios de memoria
reservados que ya no estn siendo utilizados, de cualquier modo es errneo el realizar
reservas de espacios de memoria que posteriormente queden reservados e inaccesibles
por la prdida de valor de la direccin donde se encuentran.
Cuando un espacio de memoria que ha sido reservado con la accin Nuevo no es ya
necesario, podemos destruir las variables en l contenidas y liberar ese espacio para que
quede disponible para futuras reservas. Para ello, utilizaremos la accin Destruir, que
ejecuta la operacin inversa de Nuevo: recibe como parmetro una variable de tipo
apuntador que contiene una direccin vlida que previamente ha sido reservada con la
accin Nuevo, y libera el espacio de memoria al que apunta este parmetro. Cuando
programemos, no debemos suponer que la accin Destruir modifica el valor del
parmetro que recibe, sino que una buena prctica es asignar el valor NULO a una
variable de tipo apuntador tras invocar Destruir. Si analizamos el siguiente fragmento de
algoritmo:
LXICO
TPEntero = TIPO Apuntador a Entero;
p, q = TPEntero;
...
ALGORITMO
...
Nuevo(p);
q p;
Destruir(q);
...
FIN
Se puede ver que con independencia de si Destruir modifica o no el valor de q, despus
de ejecutar esas tres instrucciones el apuntador p tiene un valor de direccin de memoria
que no sera vlida, pues ha sido liberada. Se dice que p queda como un apuntador
colgante, ya que no apunta a nada, o mejor dicho, apunta a una direccin que ya no es
vlida, pues ha sido liberada. Es responsabilidad del programador el mantener de
manera conveniente los valores de los apuntadores y no acceder a direcciones que no
son vlidas.

Acceso a datos mediante apuntadores
Sea TPEntero un tipo de apuntador que referencia a variables de un tipo cualquiera
TipoBase y p una variable apuntador del tipo TPuntero:
TipoPuntero = TIPO Apuntador a TipoBase;
p : TipoPuntero
Los lenguajes de programacin utilizan el operador * en notacin prefija (*Puntero) o el
operador ^ (Punteros)en notacin posfija, en esta publicacin se los utilizara en forma
indistinta, agregando el operador en notacin postfija, es decir puntero, para
referenciar al objeto apuntado por el puntero. La expresin Puntero, *Puntero o
Puntrero^ har referencia al contenido de la direccin apuntada por el puntero y ser un
identificador de la variable de tipo TipoBase a que se refiere el apuntador puntero.
Respecto al tema de la asignacin debe diferenciarse si lo que se asigna es el contenido
o lo que se asigna es la direccin. Si p y q so dos variables de tipo puntero que apuntan
al mismo tipo base hay que diferenciar que es lo que ocurre con las asignaciones
siguientes:
p = q
En este caso se le asigna al contenido de p el contenido de q. P y Q siguen apuntando a
su propia direccin de memoria, i los contenidos de esas dos direcciones es lo que se
iguala.
Por otro lado la asignacin:
p q
Hace que q apunte a la direccin apuntada por p.
En el caso en que el tipo base de un determinado tipo apuntador no sea un tipo simple,
sino un tipo estructurado, el acceso se realiza con los mismos operadores de acceso que
los datos estticos.
TipoRegistro=TIPO <Campo1:TipoDeDato1;Campo2:TipoDeDato2>
TipoPunteroRegistro = TIPO Apuntador a TipoRegistro;
PunteroRegistro : TipoPunteroRegistro
PunteroRegistro es un puntero a un registro, contiene la direccin de memoria donde se
aloja un registro, pro lo tanto el contenido de la direccin de memoria a la que apunta es
un registro.
PunteroRegistro es un p TipoPuntero.
PunteroRegistro^ es un registro que se encuentra en la direccin apuntada por el
puntero.
Si PunteroRegistro^ es un registro, el operador de acceso a un miembro de un registro
es el operador punto, por lo tanto
PunteroRegistro^.Campo1 hace referencia al miembro Campo1 del registro que esta en
la direccin de memoria apuntada por PunteroRegistro
Algunos lenguajes de programacin permiten utilizar apuntadores para referenciar
variables no annimas declaradas en el lxico. Para ello disponen de un operador
direccin_de (el operador & en el caso del lenguaje de programacin C) que dada una
variable, devuelve su direccin.

LXICO
TipoRegistro=TIPO <Campo1 : Entero ; Campo2 : Entero>
TipoPunteroRegistro = TIPO Apuntador a TipoRegistro;

Registro : TipoRegistro
PunteroRegistro : TipoPunteroRegistro

ALGORITMO
Registro.Campo1 5; //asigna valores al registro
Registro.Campo2 10;
PunteroRegistro direccin_de(Registro);//
PunteroRegistro.Campo1 35;
Escribir(Registro.Campo1); //imprime el valor 35
FIN
Obviamente, cuando una variable de tipo apuntador haga referencia a una variable
declarada en el lxico, como en el caso del ejemplo anterior, no ser posible destruir su
contenido mediante la accin Destruir, ya que solo pueden destruirse las instancias que
se crean en tiempo de ejecucin con la accin Nuevo.

Tipos de datos autorreferenciados o recursivos
Hemos mostrado que con punteros se pueden definir tipos que se autorreferencian, lo
que permite que el tamao de una estructura enlazada slo est limitado por la
disponibilidad de memoria principal. Con una nica variable de tipo puntero ser
posible referenciar a una secuencia cuyo nmero de elementos podr crecer o disminuir
en tiempo de ejecucin.
En tipo de dato recursivo o autorreferenciado es un registro, llamado nodo, que contiene
entre sus elementos al menos dos campos, uno con la informacin y el otro es un
puntero a una estructura del mismo tipo. La bibliografa denomina nodo para referir a
ese elemento ya que es el trmino utilizado habitualmente para referirse a los elementos
de una estructura dinmica.
TPNodo = TIPO Apuntador a Nodo;
Nodo = TIPO < dato : Entero; sig : TPNodo >;
Cada vez que reservemos espacio para una variable se crea una nueva variable de tipo
Nodo. Es posible construir sucesivamente una secuencia indefinidamente larga de datos
de tipo Nodo, en la que el campo sig de cada uno de ellos apunta al siguiente elemento
de tipo Nodo creado. El ltimo elemento de tipo Nodo contiene en su campo sig el valor
NULO para indicar que no existen ms elementos siguientes.
El tipo Nodo es, por tanto, un tipo de dato autorreferenciado.
La siguiente funcin CrearSecuencia lee de la entrada n valores de tipo entero, crea una
secuencia con esos valores en el orden inverso de entrada y devuelve como resultado un
apuntador al primer elemento de la secuencia. La variable r se utiliza para apuntar al
nodo creado en cada paso y p apunta al primer elemento de la secuencia. Cada nuevo
nodo se aade delante del primero.
CrearSecuencia(n : Entero) TPNodo : una funcin
LXICO
p, q, r : TPNodo;
i, v : Entero;
ALGORITMO
p NULO; //Crea la estructura
Leer(n);
i PARA [1, n] HACER
Escribir(Ingrese un valor entero: );
Leer(v);
Nuevo(r); // instancia y pide memoria
r^ = < v, p >;
p r
Guarda en el registro apuntado por r el valor v y en el
campo siguiente el puntero p, este puntero contiene la
direccion del que estaba en primer lugar por lo que se
establece como siguiente el que era primero antes.

FIN_PARA;
CrearSecuencia p
FIN

El mbito de una variable local es la accin o funcin en la que se declara.
En cambio, aun cuando todas las variables apuntador usadas en la funcin
CrearSecuencia, es decir, p y r, son parte de su lxico local y, por tanto, desaparecen
tras concluir la llamada a sta. No sucede as con las variables dinmicas creadas a
travs de ellas con las llamadas a Nuevo. La secuencia creada por la funcin sera
accesible fuera de ella a travs del valor TPNodo que retorna.
La siguiente accin recorre una secuencia y escribe los datos en ella contenidos:
EscribirSecuencia(dato p : TPNodo) : una accin
LXICO
q = TPNodo;
ALGORITMO
q = p;
MIENTRAS q NULO HACER
Escribir(q.dato);
q q.sig
FIN_MIENTRAS
FIN

DestruirSecuencia(dato-resultado p : TPNodo) : una accin
LXICO
q : TPNodo;
ALGORITMO
MIENTRAS p < > NULO HACER
q p;
p p.sig
Destruir(q)
FIN_MIENTRAS
FIN

Estructuras de datos dinmicas lineales
Dependiendo del nmero de punteros y de las relaciones entre nodos, podemos
distinguir varios tipos de estructuras dinmicas

El tipo pila
Una pila es una coleccin de elementos de un mismo tipo, posiblemente vaca, sobre la
que podemos hacer operaciones de insercin de un nuevo elemento, eliminacin de un
elemento. Una pila es una estructura de tipo LIFO (del ingls, Last-Input, First-
Output), lo cual significa que los elementos siempre sern eliminados de ella en orden
inverso al que fueron colocados, de modo que el ltimo elemento en entrar ser el
primero en salir. A este tipo de coleccin de datos se la conoce por el nombre de pila
precisamente por esta caracterstica. A la hora de retirar elementos, nicamente
podremos tomar el que est en la cima de la pila, que ser el ltimo que fue apilado.
Para definir el tipo de pila debemos, por tanto, disear las siguientes operaciones:
PilaVacia: Pila
EsPilaVacia: Pila Booleano
Apilar : Pila X TipoBase Pila
Cima : Pila TipoBase
Desapilar : Pila Pila
La lista anterior de operaciones disponibles para un tipo se conoce con el nombre de
signatura, y en ella se establecen los nombres de las operaciones y el nmero y tipo de
parmetros de cada una de ellas. En la signatura de un cierto tipo T se distinguen tres
tipos de operaciones:
1. Operaciones constructoras: son aquellas en las que el tipo T aparece como
resultado devuelto, pero no como parmetro de la operacin.
2. Operaciones modificadoras: son aquellas en las que el tipo T aparece tanto en la
lista de parmetros como en el resultado devuelto.
3. Operaciones de consulta: son aquellas en las que el tipo T aparece nicamente
en la lista de parmetros.
En el caso del tipo pila anterior, la nica operacin constructora sera PilaVacia; las
operaciones Apilar y Desapilar seran modificadoras, y las operaciones EsPilaVacia y
Cima seran de consulta. Las operaciones Cima y Desapilar tendrn como precondicin
que la pila que reciben como parmetro no sea vaca, pues para una pila vaca no estara
definida su cima ni se podra desapilar.
Se puede definir una pila de caracteres mediante las siguientes declaraciones:
TPNodoPilaCars = TIPO Apuntador a NodoPilaCars;
NodoPilaCars=Tipo < dato: Carcter; sig : TPNodoPilaCars >;
PilaCars = TPNodoPilaCars;
PilaVacia PilaCars : una funcin
ALGORITMO
PilaVacia NULO
FIN

EsPilaVacia(p : PilaCars) Carcter : una funcin
ALGORITMO
EsPilaVacia p = PilaVacia
FIN

Cima(p : PilaCars) Carcter : una funcin
PRE ( no EsPilaVacia (p) )
ALGORITMO
Cima p.dato
FIN

Apilar(p : PilaCars; c : Carcter) PilaCars : una funcin
LXICO
q : TPNodoPilaCars;
ALGORITMO
Nuevo(q);
q < c, p >;
Apilar q
FIN
Desapilar(p : PilaCars) PilaCars : una funcin
PRE ( NO EsPilaVacia(p) )
LXICO
q : PilaCars;
ALGORITMO
q p .sig;
Destruir(p);
Desapilar q
FIN

Es importante que se sepa que cuando se definen tipos de datos basados en estructuras
de datos complejas, las operaciones usuales de igualdad o desigualdad, que se realizan
por defecto mediante los operadores booleanos = y , produciran resultados que no se
corresponden con la semntica del tipo implementado. Por ejemplo, suponga que
declaramos dos variables, p1 y p2 de tipo PilaCars, y efectuamos una comparacin
como la siguiente:
SI p1 = p2 ENTONCES
...
FIN_SI;
Lo que estamos comparando en realidad no son las pilas, es decir, si constan de los
mismos elementos y estn en idntico orden, sino los apuntadores p1 y p2, puesto que
ambas variables son de tipo PilaCars el cual, a su vez, es un tipo apuntador. La
comparacin p1 = p2 devolver Verdadero si y slo si los apuntadores p1 y p2
apuntan a la misma direccin de memoria.

Insertar elemento en una pila:

Apilar en una pila vaca:
Partiendo que ya tiene el nodo a insertar y un puntero que apunte a l, adems el puntero
a la pila valdr NULO:
El proceso es:
1. nodo^.siguiente apunte a NULO
2. Pila apunte a nodo.

Meter en una pila no vaca:
Se puede considerar el caso anterior como un caso particular de ste, la nica diferencia
es el siguiente ser pila. Se puede utilizar este procedimiento para ambos casos.
El proceso sigue siendo muy sencillo:
1. Hacemos que nodo^.siguiente apunte a Pila.
2. Hacemos que Pila apunte a nodo.

Desapilar: leer y eliminar un elemento
Slo existe un caso posible, en las pilas slo se puede leer y sacar desde le extremo de la
pila.
1. Se utiliza un puntero auxiliar.
2. Se hace apuntar al auxiliar al primer elemento de la pila, es decir a Pila.
3. Se avanza con la pila, asignando a Pila la direccin del segundo nodo de la
pila Pila^.siguiente.
4. Se conserva el contenido del nodo para devolverlo como retorno. La operacin
sacar equivale a leer y borrar.
5. Se libera la memoria asignada al auxiliar, que es el nodo a liberar.
Si la pila slo tiene un nodo, el proceso sigue siendo vlido, ya que el valor de
Pila^.siguiente es NULO, y despus de eliminar el ltimo nodo la pila quedar vaca, y
el valor de Pila ser NULO.

Algoritmo de la funcin "push" Apilar:
1. Se Crea un nodo para el valor que se colocara en la pila.
2. Se hace que nodo^.siguiente apunte a Pila.
3. Pila debe apuntar al nuevo nodo.

Algoritmo de la funcin "pop" Desapilar:
1. Se hace que nodo apunte al primer elemento de la pila, es decir a Pila.
2. Se asigna a Pila la direccin del segundo nodo de la pila: Pilasiguiente.
3. Se guarda el contenido del nodo retornarlo.
4. Se libera la memoria asignada a nodo.

El tipo cola
El tipo cola difiere del tipo pila nicamente en la forma de insercin y extraccin de
elementos. Una cola es una estructurade tipo FIFO (del ingls, First-Input, First-
Output), es decir, primero en entrar, primero en salir. Se conoce con el nombre de cola
por ser la que habitualmente se utiliza en las colas de la vida cotidiana: el primero que
llega (que entra en la cola) es el primero en ser atendido (en ser eliminado de la cola).
TPNodoColaCars = TIPO Apuntador a NodoColaCars;
NodoColaCars = TIPO < dato: carcter; sig TPNodoColaCars >;
ColaCars = TPNodoColaCars;
Las operaciones propias del tipo cola son las siguientes:
ColaVacia : Cola
EsColaVacia : Cola Booleano
Encolar : Cola X TipoBase Cola
Primero : Cola TipoBase
EliminarPrimero : Cola Cola

Operaciones bsicas con colas
Por las restricciones a esta estructura tienen muy pocas operaciones disponibles. Las
colas slo permiten aadir y leer elementos:
1. Aadir: Inserta un elemento al final de la cola.
2. Leer: Lee y elimina un elemento del principio de la cola.

Aadir un elemento Encolar:
Las operaciones con colas son muy sencillas, prcticamente no hay casos especiales,
salvo que la cola est vaca.

Aadir elemento en una cola vaca:
Se parte de tener el nodo a insertar y un puntero que apunte a l, adems los punteros
que definen la cola, primero y ultimo que valdrn NULO
El proceso es muy simple, bastar con que:
1. nodo^.siguiente apunte a NULO.
2. Y que los punteros primero y ltimo apunten a nodo.

Aadir elemento en una cola no vaca:
De nuevo partiremos de un nodo a insertar, con un puntero que apunte a l, y de una
cola, en este caso, al no estar vaca, los punteros primero y ltimo no sern nulos:
El proceso sigue siendo muy sencillo:
1. Nodo^.siguiente apunte a NULO.
2. Ultimo^,siguiente apunte a nodo.
3. Y se actualiza ltimo, haciendo que apunte a nodo.

Aadir elemento en una cola, caso general:
Para generalizar el caso anterior, slo necesitamos aadir una operacin:
Siempre nodo^.siguiente apunta a NULO.
Si ultimo no es NULO, entonces ultimo^.siguiente apunta a nodo.
Si no el primero tambin es NULO, significa que la cola estaba vaca, as que primero
tambin apunta a nodo
Y se actualiza ltimo, haciendo que apunte a nodo.
.
Leer un elemento de una cola Eliminar primero:
Ahora tambin existen dos casos, que la cola tenga un solo elemento o que tenga ms de
uno.

Leer un elemento en una cola con ms de un elemento:
1. Se utilaza puntero auxiliar:
2. Se hace que auxiliar apunte al primer elemento de la cola, es decir a primero.
3. Se asigna a primero la direccin del segundo nodo de la cola:
primeroprimero^.siguiente.
4. Se guarda el contenido del auxiliar para devolverlo, la operacin de lectura en
colas implican tambin borrar.
5. Se Libera la memoria asignada a nodo.

Leer un elemento en una cola con un solo elemento:
1. Tambin se requiere un puntero auxiliar:
2. Se Hacemos que auxiliar apunte al primer elemento de la cola.
3. Se le asigna NULO
4. Se guarda el contenido del auxiliar para retornarlo.
5. Se libera la memoria asignada al primer nodo, el que queremos eliminar.
6. El ltimo debe apuntar a NULO.

El tipo lista
El tipo lista es el caso ms general de estructura de datos lineal. No existe una forma
prefijada de insercin y extraccin de elementos, de modo que stos pueden ser
insertados en, y tambin eliminados de, cualquier posicin arbitraria.

Listas simplemente enlazadas




Con las listas existe un repertorio ms amplio de operaciones bsicas que se pueden
realizar:
1. Aadir o insertar elementos.
2. Buscar o localizar elementos.
3. Borrar elementos.
4. Moverse a travs de una lista, anterior, siguiente, primero.

Insertar un elemento en una lista vaca:
El proceso es muy simple

1 Crear el nodo Nuevo(Nodo)
2 Guardar la informacin
3 nodo^.siguiente apunte a NULO
Nodo^<Valor, NULO>
4 Lista apunte a nodo Lista Nodo

Insertar un elemento en la primera posicin de una lista:
El proceso sigue siendo muy sencillo:
1. Crear el Nodo
2. Guardar la informacin
3. Nodo^.siguiente apunte a Lista, que contiene la direccin del anterior primero.
4. Lista debe apuntar al nuevo nodo.

Insertar un elemento en la ltima posicin de una lista:
Se supone una lista no vaca, el proceso en este caso tampoco es complejo, se necesita
un puntero que seale al ltimo elemento de la lista. La manera de conseguirlo es
empezar por el primero y avanzar hasta que el nodo que tenga como siguiente el valor
NULO.
1. Auxiliar primero
2. Al Nodo se le asigna el valor y NULO como siguiente Nodo^. <valor,
NULO>
3. Avanzar hasta que Auxiliar^.siguiente apunte al valor NULO.
4. Hacer que Auxiliar^.siguiente apunte al nuevo Nodo y as queda enlazado.

Insertar un elemento a continuacin de un nodo cualquiera de una lista:
En este caso, siguiendo el criterio del ejemplo anterior se hace que el nodo "anterior"
sea aquel a continuacin del cual insertaremos el nuevo nodo:
Si ya se dispone del anterior y del nuevo nodo, el proceso a seguir ser:
1. Hacer que Nodo^.siguiente apunte a anterior^.siguiente.
2. Hacer que anterior^.siguiente seale Nodo.

Recorrer una lista:
Las listas simplemente enlazadas slo pueden recorrerse en un sentido, ya que cada
nodo apunta al siguiente.
Para recorrer una lista se utiliza un puntero auxiliar como ndice:
1. Se le asigna al puntero ndice el valor de Lista.
2. Se recorre con un ciclo de repeticin que al menos debe tener una condicin, que
el ndice no sea NULO.
3. Dentro del Ciclo se asigna al ndice el valor del nodo siguiente al ndice actual.

Eliminar elementos en una lista

Eliminar el primer nodo de una lista abierta:
Es el caso ms simple. Se parte de una lista con uno o ms nodos, y se utiliza un
puntero auxiliar, Nodo:
1. Se hace apuntar a Nodo al primer elemento de la lista, es decir a Lista.
2. Se le asigna a Lista la direccin del segundo nodo de la lista:
ListaLista^.siguiente.
3. Se libera la memoria asignada al primer nodo, apuntado por Nodo.
Si la lista slo tiene un nodo, el proceso es tambin vlido, ya que el valor de
Lista^.siguiente es NULO, y despus de eliminar el primer nodo la lista quedar vaca, y
el valor de Lista ser NULO.

Eliminar un nodo cualquiera de una lista simplemente enlazada:
En todos los dems casos, eliminar un nodo se puede hacer siempre del mismo modo.
Supongamos que tener una lista con al menos dos elementos, y un puntero al nodo
anterior al que queremos eliminar. Y un puntero auxiliar nodo.

El proceso es parecido al del caso anterior:
Se busca que Nodo apunte al nodo a eliminar(1).
Se asigna como nodo siguiente del nodo anterior, el siguiente al que se quiere eliminar:
anterior^.siguiente = nodo^.siguiente.(2)
Se elimina la memoria asociada al nodo a eliminar.(3)



Si el nodo a eliminar es el ltimo, es procedimiento es igualmente vlido, ya que
anterior pasar a ser el ltimo, y anterior^.siguiente valdr NULO.

Moverse a travs de una lista
Slo hay un modo de moverse a travs de una lista abierta, hacia delante.
An as, a veces necesitaremos acceder a determinados elementos de una lista abierta.
Veremos ahora como acceder a los ms corrientes: el primero, el ltimo, el siguiente y
el anterior.

Primer elemento de una lista:
El primer elemento es el ms accesible, ya que es a ese a que apunta el puntero que
define la lista.
1. Para obtener un puntero al primer elemento bastar con copiar el puntero Lista.

Elemento siguiente a uno cualquiera:
Supongamos que tenemos un puntero nodo que seala a un elemento de una lista. Para
obtener un puntero al siguiente bastar con asignarle el campo "siguiente" del nodo,
nodo^.siguiente.

Elemento anterior a uno cualquiera:
Ya hemos dicho que no es posible retroceder en una lista, de modo que para obtener un
puntero al nodo anterior a uno dado tendremos que partir del primero, e ir avanzando
hasta que el nodo siguiente sea precisamente nuestro nodo, teniendo un puntero auxiliar
para contener el anterior.
Nodo = Primero
MIENTRAS no sea el nodo buscado HACER
Auxiliar = Nodo
Nodo = Nodo^.siguiente
FIN_MIENTRAS
Auxiliar apuntara al nodo anterior al buscado

ltimo elemento de una lista:
Para obtener un puntero al ltimo elemento de una lista se parte del primer nodo y se
avanza hasta que el nodo apunte a NULO, el auxiliar apuntara al ltimo. Tambin se
puede preguntar anticipadamente por el valor NULO evitndose de este modo el
puntero auxiliar
Suponiendo la lista no vaca
Nodo = Primero;
MIENTRAS Nodo^.siguiente <> NULO HACER
Nodo Nodo^.siguiente
FIN_MIENTRAS
En este caso Nodo, al final del ciclo apunta l ltimo nodo de la estructura

Como determinar si una lista est vaca:
Basta con comparar el puntero Lista con NULLO si Lista vale NULO la lista est vaca.

Borrar una lista completa:
El algoritmo genrico para borrar una lista completa consiste simplemente en borrar el
primer elemento sucesivamente mientras la lista no est vaca.

Algoritmo de insercin:
2. El primer paso es crear un nodo para el dato que vamos a insertar.
3. Si Lista es NULO, o el valor del primer elemento de la lista es mayor que el del
nuevo, insertaremos el nuevo nodo en la primera posicin de la lista.
4. En caso contrario, se debe buscar el lugar adecuado para la insercin, tenemos
un puntero "anterior". Lo inicializamos con el valor de Lista, y avanzaremos
mientras anterior^.siguiente no sea NULO y el dato que contiene
anterior^.siguiente sea menor que el dato a insertar.
5. Ahora anterior sealando al nodo previo al insertar, por lo que se enlazan lo
puntero de modo que el siguiente del nuevo sea el que era siguiente del anterior
y al siguiente del anterior se lo hace apuntar al nuevo nodo. Se debe recordar que
anterior contiene el valor inmediato anterior al valor insertado y el siguiente es
mayor. El nuevo nodo debe intercalarse entre ambos.
En el capitulo de algoritmos puntuales se ofrecen varios ejemplos para insertar nodos en
situaciones distintas y con distintos fines

Algoritmo para borrar un elemento:
Para eliminar un nodo se necesita disponer de un puntero al nodo anterior.
1. Lo primero ser localizar el nodo a eliminar, si es que existe. Pero sin perder el
puntero al nodo anterior.
2. Se parte del nodo primero, y del valor NULO para anterior.
3. Se avanza mientras nodo no sea NULO o mientras que el valor almacenado en
nodo sea menor que el que buscamos.
4. Ahora pueden darse tres casos:
5. Que el nodo sea NULO, esto indica que todos los valores almacenados en la lista
son menores que el que buscamos y el nodo que buscamos no existe. Entonces
se retorna sin borrar nada.
6. Que el valor almacenado en nodo sea mayor que el buscado, en ese caso tambin
se retorna sin borrar nada, ya que esto indica que el nodo que buscado no existe.
7. Que el valor almacenado en el nodo sea igual al buscado, nuevo existen dos
casos:
a. Que anterior sea NULO. Esto indicara que el nodo que se quiere borrar
es el primero, as que se modifica el valor de Lista para que apunte al
nodo siguiente al que se quiere borrar.
b. Que anterior no sea NULO, el nodo no es el primero, as que se asigna a
anterior^.siguiente la direccin de nodo^.siguiente.
Despus de 7 , se libera la memoria de nodo.


Implementacin de algoritmos para listas
TPNodoListaCars = TIPO Apuntador a NodoListaCars;
NodoListaCars=TIPO <dato : carcter; sig TPNodoListaCars >;
ListaCars = TPNodoListaCars;
Veamos como podemos implementar, haciendo uso de esta representacin, las
funciones de una posible especificacin:
ListaVacia : Lista
EsListaVacia : Lista Booleano
Long : Lista Entero
InsertaEnPos : Lista X Entero X TipoBase Lista
BorraDePos : Lista X Entero Lista
BuscaPos : Lista X TipoBase Entero
BuscaElem : Lista X Entero TipoBase
InsertaEnPos(lis:ListaCars;pos:Entero;e:Carcter)
ListaCars : una funcin
PRE { 1 pos Long(lis) + 1 }
LXICO
Res, p, q : TPNodoListaCars;
I : Entero;
ALGORITMO
Nuevo(p);
p.dato e;
SI pos = 1 ENTONCES
res p;
p.sig lis;
SI_NO
res lis;
q lis;
PARA i [3, pos] HACER
q q.sig
FIN_PARA;
p.sig q.sig;
q.sig p
FIN_SI;
InstertaEnPos res
FIN

BorraDePos(lis : ListaCars; pos : Entero) ListaCars: una
funcin
PRE { 1 pos Long(lis) }
LXICO
res, q, p : TPNodoListaCars;
i : Entero;
ALGORITMO
SI pos = 1 ENTONCES
res lis.sig;
Destruir(lis)
SI_NO
res lis;
p lis;
i RECORRIENDO [2, pos] HACER
q p;
p p.sig
FIN_RECORRIENDO;
q.sig p.sig;
Destruir(p)
FIN_SI;
BorraDePos res
FIN

Listas circulares
Una lista circular es una lista lineal en la que el ltimo nodo a punta al primero.
Las listas circulares evitan excepciones en la operaciones que se realicen sobre ellas. No
existen casos especiales, cada nodo siempre tiene uno anterior y uno siguiente.
En algunas listas circulares se aade un nodo especial de cabecera, de ese modo se evita
la nica excepcin posible, la de que la lista est vaca.
El nodo tpico es el mismo que para construir listas abiertas es una estructura
autoreferenciada que tiene un campo con la informacin y otro campo con un puntero a
una estructura del mismo tipo:

Lista es el puntero para contener el inicio de las listas, tanto abiertas como circulares.
En el caso de las circulares, apuntar a un nodo cualquiera de la lista.







A pesar de que las listas circulares simplifiquen las operaciones sobre ellas, tambin
introducen algunas complicaciones. Por ejemplo, en un proceso de bsqueda, no es tan
sencillo dar por terminada la bsqueda cuando el elemento buscado no existe.
Por ese motivo se suele resaltar un nodo en particular, que no tiene por qu ser siempre
el mismo. Cualquier nodo puede cumplir ese propsito, y puede variar durante la
ejecucin del programa.
Otra alternativa que se usa a menudo, y que simplifica en cierto modo el uso de listas
circulares es crear un nodo especial de har la funcin de nodo cabecera. De este modo,
la lista nunca estar vaca, y se eliminan casi todos los casos especiales.

Operaciones bsicas con listas circulares
A todos los efectos, las listas circulares son como las listas abiertas en cuanto a las
operaciones que se pueden realizar sobre ellas:
1. Aadir o insertar elementos.
2. Buscar o localizar elementos.
3. Borrar elementos.
4. Moverse a travs de la lista.
Cada una de estas operaciones podr tener varios casos especiales, por ejemplo,
tendremos que tener en cuenta cuando se inserte un nodo en una lista vaca, o cuando se
elimina el nico nodo de una lista.

Aadir un elemento:
El nico caso especial a la hora de insertar nodos en listas circulares es cuando la lista
est vaca.

Aadir elemento en una lista circular vaca:
Partiremos de que ya tenemos el nodo a insertar y un puntero que apunte a l, adems el
puntero que define la lista, que valdr NULO:



El proceso es muy simple:
1. lista apunta a nodo.
2. lista^.siguiente apunte a nodo.







Aadir elemento en una lista circular no vaca:
De nuevo partiremos de un nodo a insertar, con un puntero que apunte a l, y de una
lista, en este caso, el puntero no ser nulo:









El proceso sigue siendo muy sencillo:
1. Nodo^.siguiente apunte a lista^.siguiente.
2. lista^.siguiente apunte a nodo.








Aadir elemento en una lista circular, caso general:
Para generalizar los dos casos anteriores, slo necesitamos aadir una operacin:
1. Si lista est vaca hacemos que lista apunte a nodo.
2. Si lista no est vaca, hacemos que nodo^.siguiente apunte a lista^.siguiente.
3. Despus que lista^.siguiente apunte a nodo.

Buscar o localizar un elemento de una lista circular
Para buscar elementos en una lista circular slo hay que tener una precaucin, es
necesario almacenar el puntero del nodo en que se empez la bsqueda, para poder
detectar el caso en que no exista el valor que se busca. Por lo dems, la bsqueda es
igual que en el caso de las listas abiertas, salvo que podemos empezar en cualquier
punto de la lista.

Eliminar un elemento de una lista circular:
Para sta operacin podemos encontrar tres casos diferentes:
1. Eliminar un nodo cualquiera, que no sea el apuntado por lista.
2. Eliminar el nodo apuntado por lista, y que no sea el nico nodo.
3. Eliminar el nico nodo de la lista.
En el primer caso necesitamos localizar el nodo anterior al que queremos borrar. Como
el principio de la lista puede ser cualquier nodo, haremos que sea precisamente lista
quien apunte al nodo anterior al que queremos eliminar.
Esto elimina la excepcin del segundo caso, ya que lista nunca ser el nodo a eliminar,
salvo que sea el nico nodo de la lista.
Una vez localizado el nodo anterior y apuntado por lista, hacemos que lista^.siguiente
apunte a nodo^.siguiente. Y a continuacin borramos nodo.
En el caso de que slo exista un nodo, ser imposible localizar el nodo anterior, as que
simplemente eliminaremos el nodo, y haremos que lista valga NULO

Eliminar un nodo en una lista circular con ms de un elemento:
Considerando los dos primeros casos como uno slo.








El primer paso es conseguir que lista apunte al nodo anterior al que se quiere eliminar.
1. Esto se consigue haciendo que lista valga lista^.siguiente mientras
lista^.siguiente sea distinto de nodo.
2. Se hacemos que lista^.siguiente apunte a nodo^.siguiente.
3. Se elimina el nodo.









Eliminar el nico nodo en una lista circular:
Este caso es mucho ms sencillo. Si lista es el nico nodo de una lista circular:
1. Borramos el nodo apuntado por lista.
2. Hacemos que lista valga NULO.

Otro algoritmo para borrar nodos:
Existe un modo alternativo de eliminar un nodo en una lista circular con ms de un
nodo.
Si se quiere eliminar un nodo apuntado por nodo:






1. Se copia el contenido del nodo^.siguiente sobre el contenido de nodo.
2. Se hace que nodo^.siguiente apunte a nodo^.siguiente^.siguiente.
3. Se elimina nodo^.siguiente.
Si lista es el nodo^.siguiente, se hace lista = nodo.






Este mtodo tambin funciona con listas circulares de un slo elemento, salvo que el
nodo a borrar es el nico nodo que existe, y hay que hacer que lista apunte a NULO.

En una lista circular desde cualquier nodo se puede alcanzar cualquier otro. En una lista
simplemente enlazada apuntando a un nodo no es posible volver a nodos anteriores, es
necesario volver a recorrer desde el principio. En una lista circular apuntando a un nodo
se puede volver al predecesor recorriendo hacia delante.
El riesgo con esta estructura es que de no ser riguroso se puede caer en ciclos infinitos
la lista esta sin orden el puntero a lista puede apuntar, como sealamos a cualquier
nodo.
Estas lista tienen cdigo sencillo pero ineficiente. Para insertar un nodo en esta lista sin
orden:
1. Si se aceptan repeticiones simplemente habr que insertar el nodo en el lugar
donde se encuentra el puntero.
2. Si no se aceptan repeticiones habr que recorrer la lista, sin caer en ciclos
infinitos para ver si el elemento a insertar ya existe. Para evitar ciclos
infinitos se debe:
a. Guardar en un puntero auxiliar el nodo donde se encuentra el comienzo
del recorrido.
b. Detener el ciclo al encontrar el dato, si es que esta o al igualar el puntero
de recorrido con el auxiliar.

Listas Circulares Ordenadas
En estas estructuras, como en las listas simplemente enlazadas se seala con un puntero
el inicio de la estructura. El cdigo es un poco mas complejo que en las listas sin orden
pero mas eficientes ya que se evitan recorridos innecesarios.
La bibliografa discute donde debe apuntar el puntero al inicio de esta listas para
simplificar el cdigo.
En las listas simplemente enlazadas para insertar un nodo y tener la direccin del
anterior para hacer la insercin se poda recorrer con dos punteros, uno que seala al
nodo actual y otro que seala al nodo anterior. Tambin es posible evitarse el uso de dos
punteros preguntando el forma avanzada por el dato contenido en el prximo nodo.
En una lista circular no vaca ningn siguiente es NULO y el recorrido se hace con un
puntero preguntando en forma avanzada. Como en el recorrido se pregunta en forma
avanzada, el puntero debe apuntar al predecesor del primer nodo, esto por si la insercin
debiera hacerse delante del primer nodo.
Si hay un nico nodo, predecesor y sucesor apuntan a dicho nodo.

Lista circular con header
Es una lista especial donde hay un nodo especial llamado HEADER, que guarda
informacin genrica sobre los otros nodos.
Por ejemplo si los nodos tienen los nombres de las personas y los sueldos, el nodo
HEADER podra tener la cantidad de nodos de la lista, excluyndolo, el sueldo
promedio y el mnimo.
Para definir este tipo de registros los lenguajes de programacin permiten definir
registros variantes o uniones, estas estructuras tienen un tratamiento similar a los
registros y pueden tener una parte fija y una parte variante en la que se solapa la
informacin.
Las ventajas que pueden sealarse entre las listas circulares con header y sin header es:
1. El Header guarda informacin genrica sobre la lista circular. No es
necesario recorrer la lista para obtener informacin global. Se debe tener en
cuenta que al insertar o eliminar un nodo de la lista se debe actualizar la
informacin de header para que sea consistente.
2. El cdigo se simplifica porque el header esta siempre, aunque la lista este
vaca. En este caso el problema de poner el puntero a la lista esta resuelto, se
coloca siempre en el header.

Lista Circular Ordenada con HEADER

Definiciones
Nodo = (header, comn) // enumera dos valores posibles si es header o comn.
TipoPunteroCircularCon Header = TIPO Apuntador a TipoNodo;
TipoNodo = <
Sig : TipoPuntero;
Segn tag: Nodo
Header : (cant: Entero; promedio Real; mnimo Real);
// parte del nodo cabecera//
comn : (nombre Cadena; Sueldo : Real)
// Parte comn del resto de los nodos//
FIN_SEGUN
>;
TipoDato = <nombre : Cadena; sueldo : Rel>

CrearVacia (Dato_Resultadolch_TipoPunteroCircularConHeader): una accin
ALGORITMO
Nuevo(lch);
Lch^.tag header
Lch^.cant 0;
Lch^.promedio 0;
Lch^.Minimo ValorAlto;
Lch^.sig lch
FIN

esVacia (DATO lch: TipoPunteroCircularConHeader): booleano UNA ACCION
// si el siguiente es el mismo nodo entonces solo hay un nodo y este es el header//
ALGORITMO
esVacia lch = lch^.sig
FIN

insertarOrdenado(DATO_RESULTADO lch :TipoPunterCircularConHeader; DATO
dato: TipoDato)
ALGORITMO
SI (Dato.sueldo < lcj^.Minimo)
ENTONCES
Lch^.cant = Lch^.cant + 1
// el resto de las operaciones generales//
FIN_SI
Salir Falso
REPETIR
SI (lch^.sig^.nombre < dato.nombre)
ENTONCES
Lch lch^.sig
SINO
Salir verdadero
FIN_SI
HASTA que (salir o lch^.sig.tag = header)
Nuevo(Aux)
Aux^.sig lch^.sig
Lch^.sig aux
Aux^.nombre dato.nombre
Aux^.sueldo dato.sueldo
Aux^.tag comn
FIN

ImprimirOrdenado(DATO lch :TipoPunterCircularConHeader)
ALGORITMO
REPETIR
Imprimir(lch^.sig^.nombre)
Imprimir(lch^.sig^.sueldo)
Lch lch^.sig
HASTA QUE lch^.sig^.tag = header
FIN

Listas doblemente enlazadas
Una lista doblemente enlazada es una lista lineal en la que cada nodo tiene dos enlaces,
uno al nodo siguiente, y otro al anterior.
Las listas doblemente enlazadas no necesitan un nodo especial para acceder a ellas,
pueden recorrerse en ambos sentidos a partir de cualquier nodo, esto es porque a partir
de cualquier nodo, siempre es posible alcanzar cualquier nodo de la lista, hasta que se
llega a uno de los extremos.
El nodo tpico es el mismo que para construir las listas que hemos visto, salvo que
tienen otro puntero al nodo anterior:






El movimiento a travs de listas doblemente enlazadas es ms sencillo, y como veremos
las operaciones de bsqueda, insercin y borrado, tambin tienen ms ventajas.

Operaciones bsicas con listas doblemente enlazadas
Es imilar al de listas:
1. Aadir o insertar elementos.
2. Buscar o localizar elementos.
3. Borrar elementos.
4. Moverse a travs de la lista, siguiente y anterior.

Aadir un elemento:
La estructura s diferente a las vistas anteriormente por lo que se analizaran todos los
casos posibles de insercin.

Aadir elemento en una lista doblemente enlazada vaca:
tambin se parte que se dispone del nodo a inserta y el puntero que define la lista, que
valdr NULO:






El proceso es muy simple:
lista apunta a nodo.
Lista^.siguiente y lista^.anterior apunten a NULO.









Insertar un elemento en la primera posicin de la lista:
Se parte de una lista no vaca y lista apunta al primer elemento de la lista doblemente
enlazada:









El proceso es el siguiente:
Nodo^.siguiente debe apuntar a Lista.
Nodo^.anterior apuntar a Lista^.anterior.
Lista^.anterior debe apuntar a nodo.









Lista no tiene por qu apuntar a ningn miembro concreto de una lista doblemente
enlazada, cualquier miembro es igualmente vlido como referencia.

Insertar un elemento en la ltima posicin de la lista:
Igual que en el caso anterior, se parte de una lista no vaca, y de nuevo para simplificar,
que Lista est apuntando al ltimo elemento de la lista:









El proceso es el siguiente:
1. Nodo^.siguiente debe apuntar a Lista^.siguiente (NULO).
2. Lista^.siguiente debe apuntar a nodo.
3. Nodo^.anterior apuntar a Lista.









Insertar un elemento a continuacin de un nodo cualquiera de una lista:
Bien, este caso es ms genrico, ahora partimos de una lista no vaca, e insertaremos un
nodo a continuacin de uno nodo cualquiera que no sea el ltimo de la lista:



El proceso sigue siendo muy sencillo:
1. Que Nodo^.siguiente apunte a lista^.siguiente.
2. Que Lista^.siguiente apunte a nodo.
3. Que nodo^.anterior apunte a lista.
4. Que nodo^.siguiente^.anterior apunte a nodo.




Aadir elemento en una lista doblemente enlazada, caso general:
1. Si lista est vaca se hace que Lista apunte a nodo, y nodo^.anterior y
nodo^.siguiente a NULO.
2. Si lista no est vaca, entonces que nodo^.siguiente apunte a Lista^.siguiente.
3. Luego que Lista^.siguiente apunte a nodo.
4. Que nodo^.anterior apunte a Lista.
5. Si nodo^.siguiente no es NULO, entonces nodo^.siguiente^.anterior apunte a
nodo.

Buscar un elemento de una lista doblemente enlazada
En muchos aspectos, una lista doblemente enlazada se comporta como dos listas
abiertas que comparten los datos. Pero adems se tiene la ventaja que se puede avanzar
y retroceder desde cualquier nodo, sin necesidad de volver a uno de los extremos de la
lista.
Para recorrer una lista se procede de un modo parecido al que defini con las listas
simplemente enlazadas, ahora no se necesita un puntero auxiliar, y debe tenerse en
cuenta que Lista no tiene por qu estar en uno de los extremos:
Se retrocede hasta el comienzo de la lista, asignando a lista el valor de lista^.anterior
mientras lista^.anterior no sea NULO.
Se abre un ciclo de repeticin que al menos debe controlar que el puntero no sea NULO.
Dentro del ciclo se le asigna a lista la direccin del nodo siguiente.

Eliminar un elemento de una lista doblemente enlazada:
Se Analizan cuatro casos diferentes:
1. Eliminar el nico nodo de una lista doblemente enlazada.
2. Eliminar el primer nodo.
3. Eliminar el ltimo nodo.
4. Eliminar un nodo intermedio.
Para los casos que lo permitan consideraremos dos casos: que el nodo a eliminar es el
actualmente apuntado por Lista o que no.

Eliminar el nico nodo en una lista doblemente enlazada:








En este caso, ese nodo ser el apuntado por Lista.
1. Eliminamos el nodo.
2. Hacemos que Lista apunte a NULL.











Eliminar el primer nodo de una lista doblemente enlazada:
Se tienen los dos casos posibles, que el nodo a borrar est apuntado por Lista o que no.
Si lo est, simplemente hacemos que Lista sea Lista^.siguiente.






1. Si nodo apunta a Lista, se hace que Lista apunte a Lista^.siguiente.
2. que nodo^.siguiente^.anterior apunte a NULO
3. Borramos el nodo apuntado por nodo.






El paso 2 separa el nodo a borrar del resto de la lista, independientemente del nodo al
que apunte Lista.

Eliminar el ltimo nodo de una lista doblemente enlazada:
De nuevo tenemos los dos casos posibles, que el nodo a borrar est apuntado por Lista o
que no. Si lo est, simplemente hacemos que Lista sea Lista^.anterior.







1. Si nodo apunta a Lista, se hace que Lista apunte a Lista^.anterior.
2. que nodo^.anterior^.siguiente apunte a NULL
3. Se Borra el nodo apuntado por nodo.





.




Eliminar un nodo intermedio de una lista doblemente enlazada:
De nuevo tenemos los dos casos posibles, que el nodo a borrar est apuntado por Lista o
que no.
Si lo est, simplemente hacemos que Lista sea Lista^.anterior o Lista^.siguiente
Se trata de un caso ms general de los dos casos anteriores..










1. Si nodo apunta a Lista, se hace que Lista apunte a Lista^.anterior (o
Lista^.siguiente).
2. que nodo^.anterior^.siguiente apunte a nodo^.siguiente.
3. que nodo^.siguiente^.anterior apunte a nodo^.anterior.
4. Borrar el nodo apuntado por nodo.






Eliminar un nodo de una lista doblemente enlazada, caso general:
1. De nuevo estn los dos casos posibles, que Si nodo apunta a Lista,
2. Si Lista^.anterior no es NULO se hace que Lista apunte a Lista^.anterior.
3. Si Lista^.siguiente no es NULO se hace que Lista apunte a Lista^.siguiente.
4. Si ambos son NULO, se hace que Lista sea NULO.
5. Si nodo^.anterior no es NULO, se hace que nodo^.anterior^.siguiente apunte
a nodo^.siguiente.
6. Si nodo^.siguiente no es NULO, Se hace que nodo^.siguiente^.anterior
apunte a nodo^.anterior.
7. Se borra el nodo apuntado por el nodo a borrar est apuntado por Lista o que
no. Si lo est, simplemente hacemos que Lista sea Lista^.anterior, si no es
NULO o Lista^.siguiente en caso contrario.


A modo de sntesis con estructuras enlazadas
Listas simplemente enlazadas: cada elemento slo dispone de un puntero, que
apuntar al siguiente elemento de la lista o valdr NULO si es el ltimo elemento.
Pilas: son un tipo especial de lista, conocidas como listas LIFO (Last In, First Out: el
ltimo en entrar es el primero en salir).
Colas: otro tipo de listas, conocidas como listas FIFO (First In, First Out: El primero en
entrar es el primero en salir).
Listas circulares no ordenadas: el ltimo elemento apunta al primero. Cualquier nodo
puede ser el nodo de entrada y salida.
Lista circular ordenada: por convencin el puntero a la lista circular apunta al
predecesor del primer nodo.
Lista con Header: Existe un nodo especial donde se guarda informacin genrica sobre
los dems nodos.
Listas doblemente enlazadas: cada elemento dispone de dos punteros, uno a punta al
siguiente elemento y el otro al elemento anterior.
rboles: cada elemento dispone de dos o ms punteros, pero las referencias nunca son a
elementos anteriores, de modo que la estructura se ramifica y crece igual que un rbol.
rboles binarios: son rboles donde cada nodo slo puede apuntar a dos nodos.
rboles binarios de bsqueda (ABB): son rboles binarios ordenados. Desde cada
nodo todos los nodos de una rama sern mayores, segn la norma que se haya seguido
para ordenar el rbol, y los de la otra rama sern menores.
rboles AVL: son tambin rboles de bsqueda, pero su estructura est ms optimizada
para reducir los tiempos de bsqueda.
rboles B: son estructuras ms complejas, aunque tambin se trata de rboles de
bsqueda, estn mucho ms optimizados que los anteriores.
Tablas HASH: son estructuras auxiliares para ordenar listas.
Grafos: es el siguiente nivel de complejidad, podemos considerar estas estructuras
como rboles no jerarquizados.
Diccionarios. Se implementan con tablas Hash para la bsqueda.

También podría gustarte