Beruflich Dokumente
Kultur Dokumente
Memoria Dinmica
Elementos de Programacin
Pgina 1
ETSI Telecomunicacin
Memoria Dinmica
2.1.1. Introduccin
Los tipos de datos, tanto simples como estructurados, vistos hasta ahora en los temas anteriores de las asignaturas de Introduccin a los Computadores (IC) y Elementos de Programacin (EP), sirven para describir datos o estructuras de datos cuyos tamaos y formas se conocen de antemano. Sin embargo, en muchos programas es necesario que las estructuras de datos estn diseadas de manera que su tamao y forma vare a lo largo de la ejecucin de aquellos. Con esto se consigue, fundamentalmente, que estos programas funcionen de manera ms eficiente y con un aprovechamiento ptimo de los recursos de almacenamiento en memoria principal. Las variables de todos los tipos de datos vistos hasta el momento son denominadas variables estticas, en el sentido en que se declaran en el programa, se designan por medio del identificador declarado, y se reserva para ellas un espacio en memoria en tiempo de compilacin de los programas. El contenido de la variable esttica puede cambiar durante la ejecucin del programa o subprograma donde est declarada, pero no as el tamao en memoria reservado para ella. Esto significa que la dimensin de las estructuras de datos a las que se refieren estas variables debe estar determinada en tiempo de compilacin, lo que puede suponer una gestin ineficiente de la memoria, en el sentido de que puede implicar el desperdicio (por sobredimensionamiento) o la insuficiencia (por infradimensionamiento) de memoria. Sin embargo, son muchos los lenguajes de programacin que ofrecen la posibilidad de crear y destruir variables en tiempo de ejecucin, de manera dinmica, a medida que van siendo necesitadas durante la ejecucin del programa. Puesto que estas variables no son declaradas explcitamente en el programa y no tienen identificador (nombre) asignado, se denominan variables annimas. El pseudolenguaje utilizado en las asignaturas de IC y EP permite el uso de este tipo de variables. Para ello, ofrece los mecanismos y la sintaxis necesaria para su creacin, a la vez que proporcionar una manera de referirse a estas Elementos de Programacin Pgina 2
ETSI Telecomunicacin
Memoria Dinmica
variables para el acceso a los datos que contienen y la asignacin de valores a los mismos. Todo esto se lleva a cabo mediante el empleo del tipo puntero, cuyas caractersticas se expondrn en los siguientes apartados. Datos estticos: su tamao y forma es constante durante la ejecucin de un programa y, por tanto, se determinan en tiempo de compilacin. El ejemplo tpico son los arrays. Tienen el problema de que hay que dimensionar la estructura de antemano, lo que puede conllevar desperdicio o falta de memoria. Datos dinmicos: su tamao y forma es variable (o puede serlo) a lo largo de un programa, por lo que se crean y destruyen en tiempo de ejecucin. Esto permite dimensionar la estructura de datos de una forma precisa: se va asignando memoria en tiempo de ejecucin segn se va necesitando.
Instrucciones de programa
Lmite de la pila
Elementos de Programacin
Pgina 3
ETSI Telecomunicacin
Memoria Dinmica
La zona de la memoria principal del computador donde se reservan espacios para asignarlos a variables dinmicas se denomina heap o montn. Cuando el sistema operativo carga un programa para ejecutarlo y lo convierte en proceso, le asigna cuatro partes lgicas en memoria principal: instrucciones, datos (estticos), pila y una zona libre. Esta zona libre (heap) es la que va a contener los datos dinmicos. En cada instante de la ejecucin del programa, el heap tendr partes asignadas a datos dinmicos y partes libres disponibles para asignacin de memoria, como puede observarse en la figura 2.1. El mecanismo de asignacin-liberacin de memoria durante la ejecucin del programa hace que esta zona est usualmente fragmentada (ver figura 2.1), siendo posible que se agote su capacidad si no se liberan las partes utilizadas ya inservibles. (La pila tambin vara su tamao dinmicamente, pero la gestiona el sistema operativo, no el programador.) Para trabajar con datos dinmicos son necesarias dos cosas: Subalgoritmos predefinidos en el lenguaje (pseudolenguaje) que permitan gestionar la memoria de forma dinmica (asignacin y liberacin). Algn tipo de dato con el que sea posible acceder a esos datos dinmicos (ya que con los tipos vistos hasta ahora en las asignaturas de IC y EP slo se puede acceder a datos con un tamao y forma ya determinados).
ETSI Telecomunicacin
Memoria Dinmica
De esta manera se ilustra cmo el puntero contiene una direccin de memoria que apunta a la posicin de memoria donde se almacena un dato de cierto tipo asociado al puntero.
Direccin
Contenido
Puntero
Variable referenciada
Definicin: un puntero es una variable cuyo valor es la direccin de memoria de otra variable Segn su definicin, un puntero se refiere indirectamente a un valor, por lo que no hay que confundir una direccin de memoria con su contenido (ver figura 2.3).
VARIABLES C car = z Direccin ... ... 7C16(16 ... 7C17(16 z 7C18(16 ... ... ...
Figura 2.3. Esquema de posiciones de memoria donde se muestra la diferencia entre la direccin de una variable y su contenido Una variable de tipo puntero no puede apuntar a cualquier variable annima; debe apuntar a variables annimas de un determinado tipo. El tipo de la variable annima debe ser incluido en la especificacin del tipo de la variable puntero.
Elementos de Programacin
Pgina 5
ETSI Telecomunicacin
Memoria Dinmica
ptr 33
Para abreviar, se suele llamar puntero a una variable de tipo puntero, por lo que, a partir de ahora, se utilizar ms asiduamente ese primer trmino por ser de uso ms comn y conciso.
Elementos de Programacin
Pgina 6
ETSI Telecomunicacin
Memoria Dinmica
El hecho de que la variable ptr, declarada en el ejemplo anterior, est apuntado a un dato de tipo natural de valor, por ejemplo, 33, puede representarse grficamente como en la figura 2.4 (siendo muy til este tipo de representacin para posteriores operaciones donde intervienen punteros de una manera ms compleja, como en el caso de las listas enlazadas que se analizarn al final del captulo). Un puntero puede apuntar a cualquier tipo de dato predefinido del pseudolenguaje o bien definido por el usuario, tanto tipos simples como tipos compuestos. Es importante tener en cuenta, en el caso de tipos definidos por el usuario, que primero debe declararse el tipo de datos al que apuntar el puntero (un array, un registro, etc.) y, posteriormente, el tipo de datos puntero a ese tipo definido por el usuario. Por ejemplo, TIPOS REGISTRO TipoComplejo R parteReal, parteImaginaria FINREGISTRO TipoComplejo *TipoPtrComplejo /* TipoPtrComplejo es un tipo puntero a un registro */ VARIABLES TipoComplejo *ptr1 // Puntero a un registro TipoPtrComplejo ptr2 // Puntero a un registro De esta forma, en el ejemplo anterior, ptr1 y ptr2 son variables de tipo puntero que contendrn direcciones de memoria donde estarn almacenadas variables (annimas) de tipo TipoComplejo. Es importante, por tanto, que el dato al que apunte el puntero sea del tipo base del que se ha declarado ste. Puede considerarse como una buena norma de estilo, la declaracin del tipo de datos puntero a <TipoBase> inmediatamente despus de la propia declaracin de <TipoBase>, como se ha hecho en el ejemplo anterior para TipoPtrComplejo y TipoComplejo, respectivamente.
ETSI Telecomunicacin
Memoria Dinmica
El operador de direccin (&) es un operador monario (slo requiere un operando) que devuelve la direccin de memoria del operando. Por ejemplo, ... VARIABLES Z valor, dato = -333 Z *ptrValor ... INICIO ... valor = 999 ptrValor = &valor En el ejemplo anterior se consigue que el puntero ptrValor contenga la direccin de memoria donde est almacenado el dato que contiene la variable valor, es decir, 999. Puede decirse que la instruccin ptrValor = &valor significa ptrValor recibe la direccin de valor. Esto puede verse grficamente en la figura 2.5.
ptrValor = &valor Direccin ... ... 7C16 ... 7C17 999 valor 7C18 -333 dato 7C19 7C17 ptrValor ...
Figura 2.5. Operador de direccin El operador de contenido o indireccin (*) es el operador complementario del operador de direccin (&). Es tambin un operador monario, que devuelve el valor de la variable annima ubicada en la direccin a la que apunta el puntero. Continuando con el ejemplo anterior, si ptrValor contiene la direccin de memoria de la variable valor, entonces es posible hacer la siguiente asignacin: dato = *ptrValor
dato = *ptrValor Direccin ... ... 7C16 ... 7C17 999 valor 7C18 999 dato 7C19 7C17 ptrValor ...
ETSI Telecomunicacin
Memoria Dinmica
Esta asignacin colocar el valor de la posicin de memoria 7C17(16, es decir el nmero 999, en la variable dato, como se esquematiza en la figura 2.6.
Asignacin de punteros
Justo despus de declarar un puntero con la sintaxis vista en el apartado 2.2.1, el puntero contiene un valor indeterminado. Por ello, no es correcto, desde el punto de vista del pseudolenguaje, hacer uso del puntero (por ejemplo a la derecha de una asignacin en la que aparece precedido del operador de indireccin) antes de asignarle valor al mismo. Una primera manera de inicializar el valor de un puntero es asignarle el valor nulo. De esta manera podemos considerar que el puntero, en lugar de apuntar a una posicin indeterminada cuyo acceso sera incorrecto (porque podra contener cualquier dato incluso de otros programas), no estar apuntando a ninguna parte. La manera de que dispone el pseudolenguaje de realizar esta inicializacin es mediante la asignacin al puntero, independientemente de su tipo, de la constante predefinida NULO. Podramos considerar que el pseudolenguje garantiza que no existe ningn dato en la posicin NULO. Por ejemplo, si se declara la variable ptrReal como un puntero a un nmero real (R), sera posible hacer la siguiente asignacin, indicando que ptrReal no apunta a ninguna parte en este momento: ptrReal = NULO Esto se representar grficamente como en la figura 2.7.
Figura 2.7. Asignacin de NULO a una variable de tipo puntero Es posible asignar el valor de una variable puntero a otra variable puntero, siempre que ambas sean del mismo tipo. Por ejemplo, R *ptrReal1, *ptrReal2=NULO ... ptrReal1 = ptrReal2 En este ltimo ejemplo la variable ptrReal1 apuntar a donde apunte la variable ptrReal2, en este caso a NULO. Es importante tener en cuenta que si ptrReal1, antes de la
Elementos de Programacin
Pgina 9
ETSI Telecomunicacin
Memoria Dinmica
asignacin, estaba apuntando a una variable annima de tipo real (y, por tanto, tena un valor distinto del valor NULO), sta ser a partir de ahora inaccesible, puesto que la nica manera de acceder a ella era a travs del puntero ptrReal1 y ahora ste apunta a otra variable annima o, como en este ejemplo, a NULO.
Comparacin de punteros
Es posible comparar dos variables de tipo puntero en una expresin relacional usando operadores relacionales de igualdad (==), desigualdad (!=) y comparacin (<, >, <=, >=). Dos variables puntero son iguales si ambas apuntan a la misma variable annima o ambas estn inicializadas al valor NULO. Los punteros que constituyen los operandos de estas operaciones relacionales binarias deben ser siempre del mismo tipo. Sin embargo, siempre es posible comparar cualquier puntero (igualdad o desigualdad) con el valor NULO. Ejemplo, SI (ptr1 < ptr2) ENTONCES Escribir(ptr1 apunta a una direccin menor que ptr2) FINSI
ETSI Telecomunicacin
Memoria Dinmica
pasa como parmetro. Como efecto lateral derivado de la llamada a la funcin LIBERAR para un determinado puntero, se le asigna a ste la constante NULO. Por ejemplo, VARIABLES R *ptr1, *ptr2 // 1) Declaracin de punteros INICIO ASIGNAR(ptr1) // 2) Reserva memoria ASIGNAR(ptr2) // 2) Reserva memoria *ptr1 = 99.9 // 3) Asignacin de valor a la variable annima *ptr2 = -33.3 // 3) Asignacin de valor a la variable annima *ptr1 = *ptr2 // 4) Asigna 333 al dato apuntado por ptr1 ptr1 = ptr2 /* 5) Asignacin de punteros. Se pierde la referencia al dato previamente apuntado por ptr1!!!! */ LIBERAR(ptr2) /* 6) Se libera la memoria a la que apunta ptr2 Se pone ptr2 a NULO */ *ptr1 = -999 // Error! La posicin est liberada
1) 2) 3) 4)
ptr1 ? ptr2 ?
ptr1 ? ptr2 ?
5)
6)
Elementos de Programacin
Pgina 11
ETSI Telecomunicacin
Memoria Dinmica
En la figura 2.8 se ilustra el funcionamiento del ejemplo anterior. Como puede comprobarse, hay que diferenciar claramente entre la asignacin de punteros (operacin 5 en el ejemplo) y la asignacin de valores a las variables annimas correspondientes a esos punteros (operaciones 3 y 4). Por otro lado, es importante sealar la necesidad de una correcta gestin de la memoria dinmica que evite dejar posiciones de memoria inaccesibles, como ocurre como resultado de la operacin 5 en el ejemplo anterior, as como acceder a posiciones de memoria incorrectas (no asignadas al puntero), como ocurre en la operacin 6 de dicho ejemplo. Es importante sealar aqu que la funcin ASIGNAR del pseudolenguaje se comporta de manera ideal, en el sentido en que se considera que la memoria tiene una capacidad terica infinita y siempre es posible reservar espacio para nuevos datos. En esto la semntica de la funcin ASIGNAR difiere de la de las funciones equivalentes en los lenguajes de programacin reales (incluyendo C/C++) donde s existen las inevitables limitaciones de recursos de almacenamiento y no siempre se satisfacen las peticiones de reserva, por lo que dichas funciones necesitan devolver algn dato que indique si la reserva ha sido efectuada correctamente.
ETSI Telecomunicacin
Memoria Dinmica
VAR TipoPtrComplejo ptr En este ltimo ejemplo la variable ptr es un puntero a un dato de tipo registro, concretamente de tipo TipoComplejo. En el momento en que tenga lugar una asignacin de memoria a ptr ste apuntar a una posicin de memoria donde se almacenan los datos correspondientes a los dos campos que contiene el registro: real y imag. Esto puede representarse grficamente como en la figura 2.9.
Figura 2.9. Asignacin de memoria para un puntero a registro Para acceder a los campos del registro puede combinarse el operador de indireccin (*) con la notacin punto, ayudndose de los parntesis para tener que evitar establecer una precedencia en estos operadores. Por ejemplo, podra hacerse lo siguiente: (*ptr).real = 3.33 (*ptr).imag = -9.99 Adems de esta notacin, el pseudolenguaje introduce una nueva notacin mediante el operador -> (podemos llamarlo flechita) como simplificacin del uso combinado del operador de indireccin y la notacin punto. Basta con intercalar este nuevo operador entre el identificador del puntero y del campo para indicar que se accede a ese campo de la variable annima de tipo registro. Por ejemplo, las dos operaciones equivalentes a las anteriores seran: ptr->real = 3.33 ptr->imag = -9.99 El resultado, de una u otra forma, sera el ilustrado en la figura 2.10.
Elementos de Programacin
Pgina 13
ETSI Telecomunicacin
Memoria Dinmica
Como se ha comentado ms arriba, el tipo base de un puntero puede ser tan complejo como se quiera, incluyendo registros o arrays que, a su vez, contienen otros registros o arrays y as sucesivamente. De la misma manera, es posible declarar registros que contienen campos de tipo puntero e, incluso, arrays de punteros. La utilidad y el uso de cada uno de estos tipos dependern de la aplicacin. Sirvan simplemente como muestra los siguientes ejemplos, cuyo funcionamiento se ilustra en la figura 2.11: TIPOS REGISTRO TpConstitucion // Registro con dos punteros R *peso, *altura FINREGISTRO C TpNombre[1..100] REGISTRO TpDatosPersonales TpNombre nombre TpConstitucion fisico /* Este campo es un registro con punteros */ N edad FINREGISTRO TpDatosPersonales *TpPtrDatosPersonales // Puntero a registro TpPtrDatosPersonales TpArrayPtrs[1..200] // Array de punteros TpNombre *TpPtrArray // Puntero a un array de caracteres VARIABLES TpArrayPtrs grupo TpPtrArray miNombre ... INICIO ... ASIGNAR(grupo[1]) /* Reservo memoria para el primer puntero del array /* ASIGNAR(grupo[1]->fisico.peso) /* Reservo memoria para el campo peso del campo fisico del primer puntero del array */ *(grupo[1]->fisico.peso) = 99.9 ASIGNAR(miNombre) // Reservo memoria para el array de caracteres *miNombre[1]=A // O bien (*miNombre)[1] = A ...
Elementos de Programacin
Pgina 14
ETSI Telecomunicacin
Memoria Dinmica
99,9
1.99
Puntero externo
Puntero a siguiente
Elementos de Programacin
Pgina 15
ETSI Telecomunicacin
Memoria Dinmica
Para ilustrar la listas enlazadas se mostrar a continuacin cmo definir, crear y manipular (insertar elementos, buscar, eliminar, etc.) una lista enlazada cuyos nodos contienen un nico campo de datos (adems de un puntero al siguiente nodo) de tipo carcter (C). Como se ha dicho anteriormente, los elementos de las listas (en este caso caracteres) se guardan como campos de registros que, adems, contienen un puntero que sirve de enlace con el siguiente nodo de la lista que contiene el siguiente elemento. Para este ejemplo se va a declarar el tipo TpLista, que se definir como un tipo puntero a un tipo registro TpNodo que contiene un campo de tipo carcter y un puntero de tipo TpLista. Ntese que la declaracin de TpLista es recursiva, en el sentido de que necesita TpNodo para efectuarse, a la vez que TpNodo hace uso nuevamente de TpLista. Esta licencia se le concede al pseudolenguaje de la asignatura para aumentar su expresividad y permitir este tipo de declaraciones en las que se declara un tipo en base a otro tipo que, a su vez, vuelve a recurrir al primero en su definicin. TIPOS TpNodo *TpLista REGISTRO TpNodo C caracter // Elemento del nodo TpLista sig // Puntero al siguiente nodo FINREGISTRO Otra manera de hacer esto, completamente equivalente a la anterior, consiste en declarar primero el registro, declarando el puntero sig como un puntero al mismo TpNodo para, posteriormente, declarar TpLista. De esta manera, TIPOS REGISTRO TpNodo C caracter // Elemento del nodo TpNodo *sig // Puntero al siguiente nodo FINREGISTRO TpNodo *TpLista
lista a b c
Figura 2.13. Lista enlazada de caracteres En cualquier caso, se puede dibujar cada nodo de la lista enlazada como una caja con dos campos: un carcter y un puntero. De esta forma, en la figura 2.13 se muestra una lista enlazada con tres caracteres donde lista es una variable de tipo TpLista (puntero externo) Elementos de Programacin Pgina 16
ETSI Telecomunicacin
Memoria Dinmica
que apunta al primer nodo de la lista enlazada. Para ello sera necesaria, en primer lugar, la siguiente declaracin de datos: VARABLES TpLista lista Con esta estructura declarada, para almacenar una cadena de caracteres de cualquier tamao bastar con ir leyendo (por ejemplo, por teclado) los caracteres uno a uno e ir creando para cada uno un nuevo nodo (variable annima de tipo registro) donde almacenarlo, haciendo siempre que cada nodo enlace con el siguiente y que el ltimo nodo de la lista apunte a NULO. Si la entrada se realiza por teclado, puede establecerse un convenio para indicar dnde acaba la introduccin de caracteres. Por ejemplo, el retorno de carro (carcter 13 en la tabla ASCII) puede servir de indicador de fin de la entrada de datos. A partir de lo expuesto, pueden identificarse tres operaciones bsicas sobre listas enlazadas: Creacin de una lista enlazada vaca. Insercin de un nuevo nodo en la lista enlazada. Eliminacin de un nodo en la lista enlazada.
Elementos de Programacin
Pgina 17
ETSI Telecomunicacin
Memoria Dinmica
Elementos de Programacin
Pgina 18
ETSI Telecomunicacin
Memoria Dinmica
1) y 2) ASIGNAR(ptr) ptr->caracter = d
ptr d
ptr a
4)
3)
lista a b c
Elementos de Programacin
Pgina 19
ETSI Telecomunicacin
Memoria Dinmica
ptr = lista MIENTRAS (ptr->sig != NULO) Y (nuevoNodo->carcter > ptr->sig->caracter) HACER ptr = ptr->sig FINMIENTRAS nuevoNodo->sig = ptr->sig ptr->sig = nuevoNodo El algoritmo quedara de la siguiente manera (grficamente, en la figura 2.15): ALGORITMO InsertarOrdenada(ES TpLista lista; E C car) VARIABLES TpLista nuevoNodo, ptr INICIO SI lista == NULO O lista->carcter >= car ENTONCES InsertarAlPrincipio(lista, car) SINO ASIGNAR(nuevoNodo) nuevoNodo->caracter = car nuevoNodo->sig = NULO ptr = lista MIENTRAS ptr->sig != NULO Y (car > ptr->sig->caracter HACER ptr = ptr->sig FINMIENTRAS nuevoNodo->sig = ptr->sig ptr->sig = nuevoNodo FINSI FIN InsertarOrdenada
Elementos de Programacin
Pgina 20
ETSI Telecomunicacin
Memoria Dinmica
nNodo c
ptr
lista a b d
nNodo c
lista a b d
ptr
Elementos de Programacin
Pgina 21
ETSI Telecomunicacin
Memoria Dinmica
2. Se actualiza el puntero externo de la lista (lista) para que apunte al segundo elemento de la misma, si existe, o bien a NULO. Para ello, basta con hacer: lista = lista->sig 3. Por ltimo, es importante liberar la memoria correspondiente al nodo que se desea eliminar y al que est apuntando actualmente el puntero auxiliar ptr. LIBERAR(ptr) El algoritmo (ilustrado en la figura 2.16) quedara de la siguiente manera: ALGORITMO EliminarPrimero(ES TpLista lista) VARIABLES TpLista ptr INICIO SI lista != NULO ENTONCES // Si no, no hay que eliminar nada ptr = lista lista = lista->sig LIBERAR(ptr) FINSI FIN EliminarPrimero
1)
ptr
lista a b c
2) y 3)
ptr
lista a b c
ETSI Telecomunicacin
Memoria Dinmica
ptr en el algoritmo que sigue, y otro puntero que apunte al nodo anterior al nodo que debe eliminarse, que se denominar ant. De este modo, la operacin de enlace de los nodos para saltar el nodo eliminado ser bastante simple, como se muestra en algoritmo BorrarOrdenada. La localizacin del nodo a borrar debe tener en cuenta el hecho de que la lista est ordenada y de que puede que el elemento no exista. Si la lista no estuviese ordenada, lo nico que sera diferente en este algoritmo sera la forma de localizar el nodo a borrar. ALGORITMO BorrarOrdenada(ES TpLista lista; E C car) VARIABLES TpLista ptr, ant=NULO INICIO SI lista != NULO ENTONCES // Si no, no hay que hacer nada ptr = lista MIENTRAS ptr != NULO Y ptr->caracter != car HACER ant = ptr ptr = ptr->sig FINMIENTRAS SI ptr != NULO ENTONCES // Encontrado SI ant == NULO ENTONCES // Es el primer elemento lista = lista->sig SINO ant->sig = ptr->sig FINSI LIBERAR(ptr) FINSI FINSI FIN BorrarOrdenada En la figura 2.17 se muestra la operacin de eliminacin de un nodo (que contiene la letra b) en una lista enlazada ordenada.
ant
ptr
lista a b c
Figura 2.17. Eliminacin de un nodo en una lista enlazada ordenada Elementos de Programacin Pgina 23
ETSI Telecomunicacin
Memoria Dinmica
Elementos de Programacin
Pgina 24
ETSI Telecomunicacin
Memoria Dinmica
Mayor tolerancia a fallos. Se puede recorrer la lista tanto con los enlaces hacia delante como con los enlaces hacia atrs, con lo que si algn enlace queda invalidado por algn error, se puede reconstruir la lista utilizando el otro enlace. El inconveniente principal de estas listas es que a la hora de realizar operaciones de insercin o eliminacin de nodos es mayor el nmero de punteros que hay que mover para mantener la lista correctamente enlazada. Eso requiere que la implementacin de las operaciones deba ser ms cuidadosa que en el caso de las listas simples. Existe un caso especial de lista doblemente enlazada donde el puntero que apuntan al nodo anterior del primer nodo de la lista, en lugar de estar apuntando a NULO, apunta al ltimo elemento de la lista, mientras que el puntero que apunta al nodo siguiente del ltimo nodo de la lista, en lugar de apuntar a NULO, apunta al primer nodo de la lista. Este tipo de lista se denomina lista doblemente enlazada circular y permite, entre otras cosas, hacer recorridos completos de la lista sin necesidad de empezar en el primer nodo y sin tener que cambiar el sentido del recorrido. Tambin es posible implementar listas simples circulares, donde el campo sig del ltimo nodo de la lista apunta al primer nodo de la lista.
lista
datos datos datos
Figura 2.18. Lista doblemente enlazada La forma de construir una lista doblemente enlazada es similar a la de la lista enlazada simple, con la principal diferencia de que hay que mantener dos enlaces en lugar de uno. Por tanto, el registro que constituye cada nodo debe contener, adems de los campos de datos, dos campos de tipo puntero a un nodo. Siguiendo con listas de caracteres, puede hacerse: TIPOS TpNodo *TpListaDoble REGISTRO TpNodo C caracter TipoListaDoble ant, sig FINREGISTRO Las operaciones bsicas realizables con listas doblemente enlazadas coinciden con el caso de las listas enlazadas simples, y son: Creacin de una lista doblemente enlazada. Insercin de un nodo en una lista doblemente enlazada. Eliminacin de un nodo en una lista doblemente enlazada. Elementos de Programacin Pgina 25
ETSI Telecomunicacin
Memoria Dinmica
ETSI Telecomunicacin
Memoria Dinmica
ALGORITMO InsertarOrdenadaDoble (ES TpListaDoble listaDoble; E C car) VARIABLES TpListaDoble ptr, ant, nuevo INICIO SI listaDoble == NULO O listaDoble->caracter >= car) ENTONCES InsertaAlPrincipoDoble(listaDoble, car) SINO ASIGNAR(nuevo) nuevo->caracter = car nuevo->sig = NULO nuevo->ant = NULO ant = listaDoble ptr = listaDoble->sig // Apunta al segundo nodo o NULO MIENTRAS ptr != NULO Y car > ptr->caracter HACER ant = ptr ptr = ptr->sig FINMIENTRAS SI ptr == NULO ENTONCES // Se inserta al final nuevo->ant = ant ant->sig = nuevo SINO // Se inserta en medio de la lista nuevo->sig = ptr nuevo->ant = ant ant->sig = nuevo ptr->ant = nuevo FINSI FINSI FIN InsertarOrdenadaDoble
Elementos de Programacin
Pgina 27
ETSI Telecomunicacin
Memoria Dinmica
En la figura 2.19 se muestra el funcionamiento de este algoritmo. Ntese el movimiento de punteros necesario para mantener la lista enlazada.
listaDoble
ant
ptr
Elementos de Programacin
Pgina 28
ETSI Telecomunicacin
Memoria Dinmica
Elementos de Programacin
Pgina 29
ETSI Telecomunicacin
Memoria Dinmica
listaDoble = listaDoble->sig SI listaDoble != NULO ENTONCES // Hay ms nodos en la lista listaDoble->ant = NULO FINSI SINO SI ptr->sig == NULO ENTONCES // Borrar el ltimo ant->sig = NULO SINO // El elemento a borrar est en medio de la lista ant->sig = ptr->sig ptr->sig->ant = ant FINSI LIBERAR(ptr) FINSI FIN BorrarOrdenadaDoble
Elementos de Programacin
Pgina 30
ETSI Telecomunicacin
Memoria Dinmica
Elementos de Programacin
Pgina 31
ETSI Telecomunicacin
Memoria Dinmica
Ejercicios Propuestos
1) Dada la siguiente declaracin de tipos adjunta:
TIPOS Nodo *Lista REGISTRO Nodo Z elem Lista sig FINREGISTRO a) Disea un algoritmo que imprima cada uno de los elementos de una lista. b) Disea un algoritmo que devuelva una copia de una lista. c) Disea un algoritmo que devuelva la longitud de una lista. d) Disea un algoritmo que elimine el ltimo elemento de una lista. e) Disea un algoritmo que ordene los elementos de una lista.
l1
a) Qu diferencia existe entre las dos ALGORITMO Ejemplo(E Lista p) instrucciones l2=l1 y Copiar(l1, l2), la INICIO cual duplica una lista? SI p !=NULO ENTONCES b) Qu valor contiene l2->sig tras realizar la p->elem = 10 secuencia de instrucciones?: FINSI l2=l1; LIBERAR(l1) FIN Ejemplo c) Dado el algoritmo Ejemplo adjunto, donde p se pasa por valor, y el estado inicial de la lista l1, qu ocurrir a la lista apuntada por l1 tras la siguiente llamada: Ejemplo(l1)?
Elementos de Programacin
Pgina 32
ETSI Telecomunicacin
Memoria Dinmica
a) Borrar todos los nodos de una lista enlazada y liberar Nodo *TipoPuntero toda la memoria. REGISTRO Nodo b) Duplicar una lista enlazada. N valor c) Borrar el nodo que contiene el mximo valor de una TipoPuntero sig lista enlazada. FINREGISTRO d) Intercambiar el valor n-simo con el m-simo de la lista. e) Concatenar dos listas enlazadas. f) Borrar el n-simo elemento de la lista. g) Disear el algoritmo con la siguiente cabecera: ALGORITMO TipoPuntero Busca(E TipoPuntero lista; E N elem) que devuelva el puntero al nodo que contiene el natural elem, si existe, y NULO en caso contrario. h) Dada la siguiente cabecera: ALGORITMO TipoPuntero InsBusca(ES TipoPuntero lista; E N elem) aada elem a lista, si no est en ella, y siempre devuelve un puntero al nodo que contiene elem.
5) Sea el tipo TipoLista adjunto. Resolver los siguientes apartados en base a este
tipo. a) Disea un algoritmo Purgar(...) que elimine todos los elementos duplicados una lista. b) Disea un algoritmo BorrarUltimo(...) que elimine de una lista el ltimo nodo que contiene la informacin k. c) Dadas dos listas enlazadas ordenadas, l1 y l2 de tipo TipoLista, escribe un algoritmo que mezcle las dos listas (pasadas como parmetros) en otra, de forma que esta ltima est tambin ordenada. l1 y/o l2 pueden estar vacas. Resolverlo de dos formas: Sin modificar las listas l1 y l2, creando una lista nueva. Modificando las listas l1 y l2, sin reservar memoria adicional.
grandes dimensiones. Si la mayora de los elementos del vector son ceros, ste puede representarse ms eficientemente utilizando una lista enlazada con punteros, en la que cada nodo es un registro con tres campos: el dato en esa posicin si es distinto de cero, el ndice de esa posicin y un puntero al siguiente nodo. Por ejemplo, para un vector de longitud 7 la lista
25
14
representa el vector (25, 0, 0, 0, -14, 0, 0). Dado un tipo TVector de longitud constante Dim disea algoritmos para: a) Calcular su Producto_Escalar, pasndole como entrada v1 y v2 de tipo TVector. Devolver un vector nuevo. b) Insertar un valor teniendo en cuenta que si ya existe, se debe eliminar el valor anterior. Si la posicin est fuera de rango, no har nada. Y si es cero el valor a insertar no deber quedar guardado en la lista ningn nodo de ndice cero. Elementos de Programacin Pgina 33
ETSI Telecomunicacin
Memoria Dinmica
c) Obtener el valor en una determinada posicin del vector. d) Mejorar los apartados anteriores redefiniendo el tipo TVector como un registro de dos campos, uno de ellos contendr el vector en el formato anterior y el otro indicar la longitud, la cual ya no ser necesariamente constante.
7) Una forma de almacenar un nmero natural de valor mayor que el permitido en una
computadora es introducir cada dgito, de tipo natural, en un nodo de una lista enlazada. Por ejemplo, la siguiente lista representa al nmero 357:
numero
a) Escribe un algoritmo que tome como parmetro un puntero a una lista enlazada que represente un nmero de la forma indicada y devuelva el nmero correspondiente en una variable de tipo natural. b) Disea tambin un algoritmo que lea por teclado una sucesin de dgitos, de tipo carcter, y los introduzca como dgitos de tipo natural en una lista enlazada. c) Disea dos algoritmos que realicen, respectivamente, la suma y producto de nmeros representados de esta forma.
lista enlazada, donde cada nodo contiene 1) el coeficiente, 2) el exponente de un trmino del polinomio, y 3) un puntero al siguiente nodo. Por ejemplo, el polinomio P(x)25x 14x5 se representara como indica la figura adjunta:
p 25 1 -14 5
a) Define el tipo TPolinomio que represente un polinomio mediante una lista enlazada con punteros. b) Escribe una funcin que evale un polinomio en un punto x: ALGORITMO Z Evaluar(E TPolinomio p; E Z valor) c) Escribe una funcin que obtenga el coeficiente del trmino de un determinado grado: ALGORITMO TPolinomio Coeficiente(E TPolinomio p1; E N grado) d) Escribe una funcin que sume 2 polinomios p1 y p2: ALGORITMO TPolinomio Sumar(E TPolinomio p1, p2) e) Escribe una funcin que realice la derivada de un polinomio P, con la siguiente cabecera: ALGORITMO TPolinomio Derivada(E TipoPolinomio p)
9) Supn que tienes diseado el tipo conjunto (coleccin no ordenada de elementos distintos)
mediante una lista enlazada dinmica con los tipos adjuntos: a) Queremos disear las operaciones interseccin Elemento *Conjunto y unin de dos conjuntos: Cmo seran las REGISTRO Elemento cabeceras de los dos algoritmos que realizaran Z elem estas tareas?. Al disear estos algoritmos, Conjunto sig modificas alguno de los dos conjuntos con los FINREGISTRO que operas? Se ve eso reflejado en las cabeceras? b) Disea los algoritmos de acuerdo con las cabeceras del apartado a).
Elementos de Programacin
Pgina 34
ETSI Telecomunicacin
Memoria Dinmica
Bibliografa
Aho, A. V., Hopcroft, J. E., & Ullman, J. D. (1988). Estructuras de Datos y Algoritmos. Addison Wesley Iberoamericana. Cerrada, J. A., & Collado, M. (1995). Programacin I. UNED. Dale, N., & Weems, C. (1989). Pascal (2 ed.). McGraw Hill. Helman, P., Veroff, R., & Carrano, F. (1991). Intermediate Problem Solving and Data Structures. Walls & Mirrors (2 ed.). The Benjamin/Cummings Publishing. Horowitz, E., & Sahni, S. (1999). Fundamentals of Data Structures in Pascal (4 ed.). W. H. Freeman & Co. Joyanes, L. (1996). Fundamentos de Programacin. Algoritmos y Estructuras de Datos. (2 ed.). McGraw Hill. Langsam, Y., Augenstein, M. J., & Tanenbaum, A. M. (1995). Data Structures using C and C++ (2 ed.). Prentice Hall. Weiss, M. A. (1995). Estructuras de Datos y Algoritmos. Addison Wesley Iberoamericana.
Elementos de Programacin
Pgina 35