Sie sind auf Seite 1von 35

ETSI Telecomunicacin

Memoria Dinmica

Tema 2. Memoria Dinmica


Contenido
Gestin de Memoria Dinmica Introduccin. Datos estticos y dinmicos Asignacin dinmica de memoria Tipo Puntero Declaracin de variables de tipo puntero Operaciones con punteros Gestin dinmica de memoria Punteros a registros Operaciones sobre Listas Enlazadas Otras clases de listas enlazadas Ejemplo de Gestin de Memoria Dinmica en C/C++ Ejercicios Propuestos Bibliografa

Elementos de Programacin

Pgina 1

ETSI Telecomunicacin

Memoria Dinmica

2.1. Gestin Dinmica de Memoria


En este apartado se analizarn las causas que llevan a los lenguajes de programacin a ofrecer elementos y caractersticas necesarias para permitir la gestin de memoria de manera dinmica. Se vern cules son las ventajas e inconvenientes de esta tcnica, as como las diferencias entre tipos de datos estticos y dinmicos en cuanto a su almacenamiento en memoria principal y su tratamiento por parte de los programas (algoritmos) que los manejan. As mismo, se establecern las bases tericas necesarias para la comprensin del funcionamiento del mecanismo de gestin dinmica de memoria.

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.

2.1.2. Asignacin dinmica de memoria


Cuando se habla de asignacin dinmica de memoria se hace referencia al hecho de crear variables annimas es decir, reservar espacio en memoria para estas variables en tiempo de ejecucin del programa as como liberar el espacio reservado para dichas variables annimas, cuando ya no son necesarias, tambin durante el tiempo de ejecucin.

Instrucciones de programa

Datos estticos Lmite de datos estticos Zona dinmica fragmentada (heap)

Pila Puntero de la pila (stack pointer)

Lmite de la pila

Figura 2.1. Esquema de asignacin de memoria

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

2.2. Tipo Puntero


El tipo puntero y las variables declaradas de tipo puntero se comportan de manera diferente a las variables estticas estudiadas en los temas anteriores de las asignaturas de IC y EP. Hasta ahora, cuando se declaraba una variable de un determinado tipo, sta poda contener directamente un valor de dicho tipo, simplemente llevando a cabo una asignacin de ese valor a la variable. Con las variables de tipo puntero esto no es as. Las variables de tipo puntero permiten referenciar datos dinmicos, es decir, estructuras de datos cuyo tamao vara en tiempo de ejecucin. Para ello, es necesario diferenciar claramente entre: la variable referencia o apuntadora, de tipo puntero, y la variable annima referenciada o apuntada, de cualquier tipo, tipo que est asociado siempre al puntero. Fsicamente, el puntero no es ms que una direccin de memoria. En la figura 2.2 se muestra un ejemplo, a modo de esquema terico, de lo que podra ser el contenido de varias posiciones de memoria principal, en la que se puede ver cmo una variable apuntadora o puntero, almacenado en la posicin de memoria 7881(16, contiene, a su vez, otra direccin de memoria, la 78AC(16, la de la variable referenciada o annima, que contiene el dato 6677(16. Elementos de Programacin Pgina 4

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

... 7881(16 ... 78AA(16 78AB(16 78AC(16 78AD(16 78AE(16 ...

... 78AC(16 ... AACC(16 6743(16 6677(16 89FF(16 DC34(16 ...

Figura 2.2. Esquema de posiciones de memoria con punteros

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

Direccin de la variable car = 7C17(16 Contenido de la variable car = z

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

2.2.1. Declaracin de variables de tipo puntero


La declaracin de una variable de tipo puntero1 en el pseudolenguaje de la asignatura consiste en un tipo base, un asterisco * y el nombre de la variable. La forma general de la declaracin de una variable de tipo puntero es, segn la notacin BNF, la siguiente (en la correspondiente seccin de VARIABLES): <Def_TipoPuntero> ::= <TipoBase> *<TipoPuntero> donde <TipoBase> es el tipo base del puntero, que puede ser cualquier tipo vlido, simple o compuesto. Ejemplos de declaracin de variables de tipo puntero son los siguientes: VARIABLES N *contador // Puntero a una variable de tipo natural (N) C *car // Puntero a una variable de tipo carcter (C) As, la variable contador del ejemplo anterior no contiene un valor de tipo natural (N), sino la direccin de memoria donde estar almacenado un valor de tipo natural. El valor almacenado en la variable annima de tipo natural ser accesible a travs del puntero contador. Tambin es posible, como para el resto de los tipos simples o compuestos vistos en las asignaturas de IC y EP, declarar nuevos tipos puntero, mediante la inclusin de los mismos en la correspondiente seccin de TIPOS del algoritmo, siguiendo la sintaxis vista ms arriba. A partir de estos nuevos tipos, pueden declararse nuevas variables. Por ejemplo, TIPOS N *TipoPtrNatural // Tipo puntero a un nmero natural C *TipoPtrCaracter // Tipo puntero a un carcter ... VARIABLES TipoPtrNatural contador, ptr // Variables de tipo puntero // a un nmero natural TipoPtrCaracter car // Variable de tipo puntero a un carcter

ptr 33

Figura 2.4. Representacin grfica de punteros

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.

2.2.2. Operaciones con Punteros


Las operaciones que se pueden llevar a cabo con punteros son: Operaciones especficas de punteros. Asignacin de punteros. Comparacin de punteros.

Operadores especficos de punteros


Para trabajar con punteros se utilizan dos operadores especficos: el operador de direccin (&) y el operador de indireccin (*). Elementos de Programacin Pgina 7

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

Figura 2.6. Operador de indireccin Elementos de Programacin Pgina 8

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.

Nota: no se debe confundir el operador * de las declaraciones de punteros (N *ptrNatural)


con el operador de indireccin usado en los ejemplos anteriores (*ptrNatural = 939).

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.

ptrReal = NULO ptrReal

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

2.2.3. Gestin Dinmica de Memoria


Por gestin dinmica de memoria se entiende el hecho de crear variables annimas, es decir, reservar espacio en memoria para estas variables en tiempo de ejecucin, y tambin de liberar el espacio ocupado en memoria por una variable annima, asimismo en tiempo de ejecucin, cuando esa variable ya no es necesaria. Por tanto, antes de asignar a la variable annima de un puntero un determinado valor (por ejemplo, *ptrNatural = 333) es necesario reservar memoria para almacenar dicho valor. Reservar memoria significa que el sistema le asigna al puntero (ptrNatural) una direccin de memoria libre para su variable annima donde podr guardar el valor asignado (en este caso 333). Si la reserva de memoria no se realiza como paso previo a la asignacin anterior, se producir una violacin de acceso a memoria porque el puntero estar inicialmente apuntando a una direccin indeterminada o nula donde no es posible guardar el dato. El pseudolenguaje de las asignaturas de introduccin a la programacin consta de dos subalgoritmos predefinidos para la gestin de memoria dinmica: ASIGNAR y LIBERAR. Ambos tienen un nico parmetro, de tipo puntero (a cualquier tipo de dato). El subalgoritmo ASIGNAR, como su propio nombre indica, asigna (reserva) memoria para la variable annima del puntero cuyo identificador se le pasa como parmetro. No es necesario indicar el tamao del dato que se reserva, ya que la funcin ASIGNAR se encarga de reservar tanto espacio en memoria como sea necesario para almacenar el tipo de dato base del puntero. Por su parte, el subprograma LIBERAR libera la memoria asignada a la variable annima del puntero cuyo identificador se Elementos de Programacin Pgina 10

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 ?

ptr1 99.9 ptr2 -33.3

ptr1 -33.3 ptr2 -33.3

5)

6)

ptr1 -33.3 ptr2 -33.3

ptr1 -33.3 ptr2 ?

Figura 2.8. Ilustracin de un ejemplo de gestin dinmica de memoria

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.

2.2.4. Punteros a registros


Hasta ahora, en los apartados anteriores, en los que se ha definido el tipo puntero y sus operaciones bsicas, no se ha mostrado la verdadera utilidad de los punteros. En los ejemplos vistos hasta ahora, los punteros manejados han sido meros punteros a datos simples, como reales, naturales o caracteres. Aunque puede considerarse que se trata de una verdadera gestin dinmica de memoria, dado que es necesario asignar memoria antes de usar esos datos y liberarla cuando dejan de usarse, realmente no aporta grandes ventajas a las variables de tipo esttico. La situacin cambia cuando el tipo base de las variables puntero es un tipo complejo, como es el caso de los registros. En ese momento, se pone de manifiesto la verdadera potencialidad de los punteros como elementos para una eficiente gestin de memoria en tiempo de ejecucin, como se ver en el siguiente apartado sobre listas enlazadas. Como se ha comentado en los apartados anteriores, es posible declarar tipos y variables de tipo puntero de cualquier tipo base, ya sea ste simple o complejo. Un tipo especial, de gran utilidad, es el tipo puntero a registro. La declaracin de un puntero a un registro sigue la sintaxis vista en los apartados anteriores. Por ejemplo, TIPOS REGISTRO TipoComplejo R real, imag FINREGISTRO TipoComplejo *TipoPtrComplejo Elementos de Programacin Pgina 12

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.

ASIGNAR(ptr) ptr real ? imag ?

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.

ptr->real = 3.33 ptr->imag = -9.99 ptr real 3.33 imag -9.99

Figura 2.10. Asignacin a campos de registros apuntados por punteros

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

grupo ... nombre A n ... e z peso fisico edad 33 altura

99,9

1.99

Figura 2.11. Estructuras complejas basadas en punteros

2.3. Operaciones sobre Listas Enlazadas


Los punteros y la asignacin dinmica de memoria permiten la construccin de estructuras enlazadas. Una estructura enlazada es una coleccin de nodos, cada uno de los cuales contiene uno o ms punteros a otros nodos. Cada nodo es un registro en el que uno o ms campos son punteros. La estructura enlazada ms sencilla es la lista enlazada. Una lista enlazada consiste en un nmero de nodos, cada uno de los cuales contiene uno o varios datos, adems de un puntero; el puntero permite que los nodos formen una estructura a modo de cadena o de lista enlazada. En la figura 2.12 puede verse una representacin que ilustra este concepto. Como puede observarse en esta figura, un puntero externo apunta al primer nodo de la lista. El primer nodo es un registro que contiene (adems de los campos de datos) un puntero que apunta al segundo nodo de la lista, y as sucesivamente. El puntero del ltimo nodo apuntar a NULO, indicando que es el ltimo nodo de la lista.

Puntero externo

Puntero a siguiente

Campos de datos de un nodo (registro)

ltimo nodo de la lista (siguIente es NULO)

Figura 2.12. Esquema de lista enlazada con punteros

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.

Creacin de una lista enlazada vaca


El subalgoritmo para la creacin de una lista enlazada vaca (sin ningn elemento inicialmente) es relativamente simple: basta con inicializar el puntero externo a NULO. Este algoritmo recibir como parmetro de ES un elemento de tipo TpLista. ALGORITMO CrearLista(ES TpLista lista) INICIO lista = NULO FIN CrearLista

Insercin de un nuevo nodo en la lista enlazada


En la operacin de insercin de un nodo en una lista enlazada pueden distinguirse dos casos claramente diferenciados: Insercin de un nodo al principio de una lista. Insercin de un nodo despus de un determinado nodo existente (por ejemplo, de manera que la lista se mantenga ordenada en orden ascendente).

Elementos de Programacin

Pgina 17

ETSI Telecomunicacin

Memoria Dinmica

1) Insercin de un nuevo nodo al principio de una lista enlazada


Para insertar un nuevo nodo al comienzo de una lista enlazada deben seguirse los siguientes pasos: 1. Crear un nodo para una variable annima auxiliar, previamente declarada de tipo TpLista. ASIGNAR(ptr) // ptr antes declarado como TpLista ptr 2. Asignar un valor (carcter) al campo de datos de la nueva variable annima. ptr->caracter = d 3. Hacer que el campo siguiente del nuevo nodo apunte donde actualmente apunte el puntero externo de la lista, es decir, lista. ptr->sig = lista 4. Por ltimo, debe actualizarse el puntero externo de la lista, es decir, lista, para que apunte al primer nodo de la lista, que ser el que se acaba de introducir. lista = ptr Todo estos pasos se dan en el siguiente subalgoritmo para insertar un nuevo elemento al principio de una lista de caracteres (cuyo funcionamiento se ilustra grficamente en la figura 2.14), que recibir como parmetros la lista (puntero de tipo TpLista) y el carcter a insertar en el nuevo nodo: ALGORITMO InsertarAlPrincipio(ES TpLista lista; E C car) VARIABLES TpLista ptr // Puntero auxiliar INICIO ASIGNAR(ptr) // Nuevo nodo ptr->caracter = car ptr->sig = lista lista = ptr FIN InsertarAlPrincipio

Elementos de Programacin

Pgina 18

ETSI Telecomunicacin

Memoria Dinmica

1) y 2) ASIGNAR(ptr) ptr->caracter = d

ptr d

3) ptr->sig = lista 4) lista=ptr

ptr a

4)

3)

lista a b c

Figura 2.14. Insercin de un nodo al principio de una lista enlazada de caracteres

2) Insercin de un nuevo nodo en una posicin determinada de la lista


Cuando se desea insertar un nuevo elemento en una lista enlazada ordenada, de manera que esta permanezca ordenada despus de la insercin, los pasos a seguir seran los siguientes (para el caso de una lista de caracteres ordenados alfabticamente en orden ascendente): 1. Si la lista est vaca o el primer elemento de la lista es mayor (alfabticamente) que el elemento a insertar, se procede como en el caso anterior en el que se insertaba el elemento al principio de la lista. En otro caso, se sigue con los puntos siguientes. 2. Crear el nuevo nodo, reservando espacio para el mismo y almacenando en su campo de datos (caracter) el nuevo elemento que se desea insertar. Es aconsejable utilizar, para ello, una variable auxiliar de tipo TpLista, por ejemplo, la variable nuevoNodo. Opcionalmente, puede ponerse el puntero sig del nuevo nodo apuntando inicialmente a NULO. ASIGNAR(nuevoNodo) nuevoNodo->caracter = d nuevoNodo->sig = NULO 3. Se utiliza una nueva variable auxiliar ptr, de tipo TpLista, para recorrer cada uno de los nodos de la lista hasta encontrar en lugar exacto donde debe insertarse el nuevo elemento; para ello, ptr estar siempre apuntando al nodo anterior al nodo cuyo elemento se est comparando con el elemento a insertar, de manera que una vez que se localice el lugar de insercin sea posible enlazar correctamente el nuevo nodo en la lista, mantenindola ordenada. Esto se hara de la siguiente manera, para el ejemplo que se viene mostrando:

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

2) ASIGNAR(nNodo) nNodo->caracter = c nNodo->sig = NULO

nNodo c

3) /* Localizacin del lugar de insercin (bucle)*/

ptr

lista a b d

3) /* Enlace de punteros para mantener la ordenacin */

nNodo c

lista a b d

ptr

Figura 2.15. Insercin de un nodo en una lista ordenada

Eliminacin de un nodo de una lista enlazada


Como en el caso de la insercin de nuevos nodos, en la operacin de eliminar un nodo de una lista enlazada pueden tambin diferenciarse dos situaciones: Borrar el primer nodo de la lista enlazada. Borrar un determinado nodo de la lista enlazada.

1) Borrar el primer nodo de una lista enlazada


Los pasos a seguir son los siguientes: 1. Declaracin de un puntero auxiliar, que se inicializar de manera que apunte al primer nodo de la lista, que es el que se desea borrar. ptr = lista

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

Figura 2.16. Borrar el primer nodo de una lista enlazada

2) Borrar un determinado nodo de la lista enlazada


Para borrar un nodo concreto de la lista enlazada ordenada (diferente del primero) son necesarios dos punteros auxiliares: uno apuntando al nodo a borrar, que tendr el nombre de Elementos de Programacin Pgina 22

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

Otras operaciones con listas enlazadas


Puede completarse el conjunto de operaciones bsicas con listas enlazadas incorporando dos nuevas operaciones, de gran utilidad: visualizar una lista escribindola, por ejemplo, en la salida estndar (pantalla) y eliminar todos los nodos de una lista. Esta ltima operacin es necesaria en situaciones donde es preciso eliminar una lista completa y liberar la memoria ocupada por todos sus nodos. A continuacin se muestran ambos subalgoritmos. ALGORITMO EscribirLista(E TpLista lista) VARIABLES TpLista ptr = lista INICIO MIENTRAS ptr != NULO HACER Escribir(ptr->caracter) ptr = ptr->sig FINMIENTRAS FIN EscribirLista ALGORITMO BorrarLista(ES TpLista lista) VARIABLES TpLista ptr INICIO MIENTRAS lista != NULO HACER ptr = lista lista = lista->sig LIBERAR(ptr) FINMIENTRAS FIN BorrarLista

2.3.1. Otras clases de listas enlazadas


Otras clases de listas enlazadas son las listas doblemente enlazadas. A diferencia de las listas enlazadas vistas en los apartados anteriores, las listas doblemente enlazadas contienen dos punteros en cada nodo, adems de los campos de datos propiamente dichos. Uno de estos punteros, de manera similar a las listas enlazadas simples, apunta al siguiente nodo de la lista, mientras que el otro puntero apunta al nodo anterior, tal y como se ilustra en la figura 2.18. Disponer de dos enlaces en lugar de uno tiene varias ventajas: La lista puede recorrerse en cualquier direccin. Esto simplifica la gestin de la lista, facilitando las inserciones y las eliminaciones.

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

Creacin de una lista doblemente enlazada


Una lista doblemente enlazada se crea de la misma forma que una lista enlazada simple, esto es, inicializando el puntero externo de la lista a NULO para indicar que la lista est vaca. ALGORITMO CrearListaDoble (ES TpListaDoble listaDoble) INICIO listaDoble = NULO FIN CrearListaDoble

Insercin de un nodo en una lista doblemente enlazada


En la operacin de insertar un nodo en una lista doblemente enlazada pueden distinguirse dos casos claramente diferenciados, como en el caso de las listas simples: Insercin de un nodo al principio de la lista. Insercin del nodo despus de un determinado nodo existente (por ejemplo, para mantener la lista ordenada alfabticamente en orden ascendente).

1) Insercin de un nodo al principio de una lista doblemente enlazada


El algoritmo para insertar un nodo al comienzo de una lista doblemente enlazada que ha sido previamente creada (precondicin necesaria) se muestra a continuacin: ALGORITMO InsertaAlPrincipioDoble(ES TpListaDoble listaDoble; E C car) VARIABLES TpListaDoble ptr INICIO ASIGNAR(ptr) // Reserva de memoria ptr->caracter = car // Inicializacin de campos del nuevo nodo ptr->ant = NULO ptr->sig = NULO SI (listaDoble != NULO) ENTONCES // Lista no vaca ptr->sig = listaDoble listaDoble->ant = ptr FINSI listaDoble = ptr // Nuevo primer nodo de la lista FIN InsertaAlPrincipioDoble

2) Insercin de un nodo en una posicin determinada de una lista doblemente enlazada


Para insertar un nodo en una lista doblemente enlazada ordenada, de manera que se mantenga ordenada despus de la insercin, es necesario, en primer lugar, localizar la posicin de la lista donde debe insertarse el nodo. Un algoritmo para insertar un nodo en una posicin determinada de una lista enlazada doble es el siguiente: Elementos de Programacin Pgina 26

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

Figura 2.19. Insercin en una lista doblemente enlazada

Elementos de Programacin

Pgina 28

ETSI Telecomunicacin

Memoria Dinmica

Eliminacin de un nodo de una lista doblemente enlazada


En la operacin de eliminar un nodo de una lista doblemente enlazada pueden distinguirse dos casos claramente diferenciados, como en el caso de las listas simples: Borrar el primer nodo de la lista. Borrar un determinado nodo existente (por ejemplo, de forma que se mantenga la lista ordenada alfabticamente en orden ascendente despus de la operacin de borrar).

1) Borrar el primer nodo de la lista doblemente enlazada


ALGORITMO EliminarPrimeroDoble(ES TpListaDoble listaDoble) VARIABLES TpListaDoble ptr INICIO SI listaDoble != NULO ENTONCES // Si no, no hacemos nada ptr = listaDoble listaDoble = listaDoble->sig LIBERAR(ptr) FINSI FIN EliminarPrimeroDoble

2) Borrar un nodo de una posicin determinada de la lista


Para borrar un nodo de una posicin determinada de la lista se necesitan dos punteros auxiliares: uno apuntando al nodo a borrar, que se denominar ptr en el algoritmo que se muestra a continuacin; y otro que apunte al nodo anterior al nodo que se va a eliminar, que se llamar ant. Esto permitir dejar la lista correctamente enlazada despus de la liberacin de la memoria correspondiente al nodo borrado. ALGORITMO BorrarOrdenadaDoble(ES TpListaDoble listaDoble; E C car) VARIABLES TpListaDoble ant, ptr INICIO ant = NULO ptr = listaDoble MIENTRAS ptr != NULO Y ptr->caracter != car HACER ant = ptr ptr = ptr->sig FINMIENTRAS SI ptr != NULO ENTONCES // Se ha encontrado el elemento SI ant == NULO ENTONCES // El elemento a borrar es el primero

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

2.4. Ejemplo de Gestin de Memoria Dinmica en C/C++


En C/C++ la sintaxis de declaracin de punteros es similar a la vista para el pseudolenguaje en los apartados anteriores: se usa el asterisco (*) a continuacin del tipo base para indicar que se trata de un puntero a ese tipo base. Por otro lado, la operacin de asignacin de memoria se lleva a cabo mediante la funcin new. Para ello se asigna al puntero el resultado de invocar la funcin new para el tipo base del mismo, como se muestra en el ejemplo a continuacin. La funcin delete equivale al subalgoritmo ASIGNAR del pseudolenguaje para la liberacin de memoria. El siguiente ejemplo se presenta como una simple muestra de la sintaxis de C/C++ en el manejo de memoria dinmica mediante el uso de punteros2: #include <iostream> #include <stdlib.h> struct TpNodo{ char car; TpNodo *sig; }; typedef TpNodo *TpPtrNodo; void main(){ TpPtrNodo ptr; ptr = new TpNodo; // Asignacin de memoria ptr->car = 'a'; ptr->sig = NULL; // NULL equivale a NULO en el pseudolenguaje cout << ptr->car << endl; delete ptr; // Liberacin de memoria apuntada por ptr system("pause"); }

En la asignatura de Laboratorio de Programacin se presentarn estos conceptos de manera ms extensa y detallada.

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.

2) Dada la declaracin de tipos anterior y las variables l1 y l2 de tipo Lista, y siendo l1 la


siguiente lista enlazada:

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

3) Dada la declaracin de tipos adjunta:


a) Disea un algoritmo que inserte un elemento al inicio de una lista. b) Disea un algoritmo que inserte un elemento al final de una lista. c) Disea un algoritmo que elimine el primer elemento de una lista. d) Disea un algoritmo que elimine el ltimo elemento de una lista. e) Disea un algoritmo que elimine los datos correspondientes a una persona con un nombre determinado de una lista. f) Disea un algoritmo que devuelva una copia de una lista. g) Disea un algoritmo que devuelva la longitud de una lista. h) Disea un algoritmo que ordene una lista por el nombre de las personas. REGISTRO Persona C nombre[0..99] N telfono FINREGISTRO Nodo *Lista REGISTRO Nodo Persona elem Lista sig FINREGISTRO

Elementos de Programacin

Pgina 32

ETSI Telecomunicacin

Memoria Dinmica

4) Dadas las definiciones de tipos adjuntas, disear los siguientes algoritmos:

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.

Nodo *TipoLista REGISTRO Nodo N valor TipoLista sig FINREGISTRO

6) Hay muchas aplicaciones en las que se debe almacenar en la memoria un vector de

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.

8) Un polinomio en x, de tipo entero, de grado arbitrario se puede representar mediante una

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

Das könnte Ihnen auch gefallen