Está en la página 1de 9

Tema 10.

Punteros
„ Introducción
„ Memoria de un ordenador
„ Gestión del Heap
Tipo de dato puntero
Tema 10.
„
„ Definición
„ Inicialización y liberación de memoria

Manejo Dinámico de „
„
Operaciones básicas
El operador @

Memoria. Punteros
„ Procesamiento de listas
„ Listas con arrays
„ Listas con punteros
„ TDA Lista con punteros
„ TDA Lista con Nodo Cabecera

Tema 10. Punteros 2

Introducción Memoria de un ordenador


„ Estructuras de datos dinámicas: el tamaño no se conoce en tiempo
de compilación sino que irá aumentado o disminuyendo „ La memoria de un ordenador está dividida en casillas o
dinámicamente durante la ejecución del programa celdas de igual tamaño
„ Una estructura de datos dinámica es una colección de elementos „ Para acceder a una casilla determinada hay que señalar
llamados nodos (normalmente de tipo registro) que se enlazan o su dirección, que identifica unívocamente a cada casilla
encadenan juntos
„ El enlace se establece asociando con cada nodo un puntero que „ Tanto en la memoria como en el procesador, la
apunta al nodo siguiente de la estructura información es procesada y transmitida mediante
„ Existen varios tipos de estructuras dinámicas (listas enlazadas, unidades denominadas palabras de memoria
grafos, árboles…) „ La longitud de cada palabra de memoria varía de una
máquina a otra, aunque hoy en día el tamaño más
habitual es de 16, 32 y 64 bits.

Nodo 1 Nodo 2 Nodo 3

Tema 10. Punteros 3 Tema 10. Punteros 4

División de la memoria principal


„ Zona de código: es la parte de la memoria donde Gestión del heap
residen las instrucciones de nuestro programa; suele
ocupar las direcciones más bajas de la memoria
„ Zona de datos: se alojan los datos estáticos de
nuestro programa, es decir, las variables globales
„ La memoria que ocupa el heap está dividida en bloques
del mismo. Suele ser un espacio de memoria de diferentes tamaños
Pila
limitado, por lo que el número y tamaño de estas
variables también está limitado. Forma junto con la „ Cuando desde el programa se solicita memoria para
Datos dinámicos
zona de código la parte estática de la memoria alojar un objeto de tamaño n, el gestor del heap le
Heap
„ La pila o stack, que suele encontrarse en las
posiciones más altas de memoria, creciendo
asigna un bloque libre de tamaño n, si lo hay, o de
dinámicamente hacia las direcciones más bajas de la tamaño t ( siendo t el valor más pequeño del tamaño de
misma. En el stack se alojarán las variables locales
de los diferentes módulos conforme estos se van Zona de datos todos los bloques libres con tamaño mayor que n). El
activando Datos estáticos bloque asignado se marca como ocupado y no puede ser
„ El heap, o zona de datos dinámicos, se encuentra Zona de código asignado a otro objeto, por lo que se desperdicia un
entre la zona de datos estáticos y la pila. Su tamaño
varía dependiendo de cómo varíe el tamaño de la pequeño trozo de memoria
pila, aunque por lo general los compiladores asignan
como heap todo el espacio que no es zona de
„ Cuando se libera un objeto, el bloque de memoria que
código y de datos estáticos. El programador no debe ocupaba pasa a ser libre, por lo que podrá ser ocupado
preocuparse de cómo se gestiona esta memoria,
sino solo de su utilización ya que es el propio
por otros objetos que lo soliciten
compilador el que se carga de ello
Tema 10. Punteros 5 Tema 10. Punteros 6

1
Inicialización y liberación de
El tipo de dato puntero
memoria
„ Un puntero es un objeto cuyo contenido es la dirección
de memoria que ocupa otro objeto de nuestro programa „ Son dos operaciones importantes
Para indicar al compilador que debe reservar espacio en el heap hay
„ El rango de valores válidos será el de las direcciones de „

memoria capaces de ser accedidas por el procesador del que inicializar el puntero con NEW(id_puntero)
ordenador, más una dirección de memoria especial, que „ Al realizar la inicialización, se asigna un bloque del heap en tiempo de
se corresponde con el puntero nulo ejecución y se marca como ocupado
„ El puntero nulo recibe nombres diferentes dependiendo „ El bloque permanece ocupado hasta que el programa libera
del lenguaje (Pascal – NIL, C – NULL) explícitamente esa zona de memoria mediante la operación
„ Declaración de una variable tipo puntero DISPOSE(Id_puntero)

Id_puntero:^tipo „ Cuando un objeto apuntado no vaya a volver a utilizarse, éste debe


liberarse. De esta manera, la memoria libre del heap aumenta, por lo
„ El ejemplo siguiente se lee como ‘p apunta a la dirección que podrá ocuparse por otros objetos. De otra forma, puede ocurrir
de memoria donde se encuentra almacenado un entero’
que el heap se llene de bloques ocupados que no están apuntados
p:^entero por ningún puntero, lo que supone un gravísimo desperdicio de
memoria
Tema 10. Punteros 7 Tema 10. Punteros 8

Ejemplo Operaciones básicas


Var p:^integer; „ Acceso al contenido de los objetos apuntados por el puntero
New(p);
„ Se utiliza el operador ^ (operador de indirección o de desreferencia)
„ Para acceder al contenido se usa Id_puntero^
30 ? Una vez que se accede al contenido se puede tratar con todas las operaciones
Heap Heap „
válidas para el tipo de datos apuntado por el puntero
„ Asignación de punteros (no está permitido asignar punteros que apunten a
? Datos Globales Datos Globales tipos de datos distintos)
p p
p:=q;
New(p); „ Asignación del contenido de los punteros
P^:=50;
p^:=q^; p^:=2300;
? Heap 30 50
Heap „ Comparación
IF (p<>q) THEN … IF (p=q) THEN …
„ Lectura y escritura: lógicamente, no se podrán realizar las operaciones de
Datos Globales Datos Globales lectura y escritura de los punteros como tales. Sí que se podrá leer o escribir
p p
el contenido de los objetos apuntados, siempre siguiendo las reglas de cada
tipo concreto
P^:=30; Dispose(p); READLN(p^); WRITELN(q^);
30 30
Heap Heap „ La constante NIL permite dar un valor a una variable puntero que no apunta
a ninguna dirección. Puesto que NIL no apunta a ninguna posición de
memoria, cualquier referencia al contenido de la posición que apunta un
Datos Globales ? Datos Globales puntero NIL es ilegal
p p
p:=NIL; p^:=10; ¡ERROR!
Tema 10. Punteros 9 Tema 10. Punteros 10

Ejemplos
Ejemplos
VAR q ? p ? „ Errores comunes TYPE
q,p:^integer; Var Empleado= RECORD
BEGIN p:^integer; Codigo:Integer;
q ? p ? Begin Nombre:string[30];
New(p); p^
NEW(p) Edad:Integer;
p^
q ? p 30 p:=2300; {asignar a p la sueldo:real;
p^:=30; p^ dirección 2300} END; 1001
NEW(p); {se reserva un VAR
q ? p 350 p Ana García
p^:=p^*10+50; p^ nuevo bloque para p:^Empleado;
p sin haber liberado BEGIN 35
? p 350 el bloque antiguo} ……
New(q); q
q^ p^ DISPOSE(p); NEW(p); 1754
p^:=2300; {intenta acceder al p^.codigo:=1001;
q^:=p^; q 350 p 350 contenido del bloque P^.nombre:=‘Ana García’;
q^ p^ que ya ha sido P^.edad:=35;
liberado} P^.sueldo:=1754;
p^:=p^+q^; q 350 p
p^
700 p:=NIL ……
q^
IF (p^=0) THEN… {intenta acceder DISPOSE(p);
al contenido de un
q:=p; q 350 p 700 ……
p^ q^ puntero nulo} END;
End;
Tema 10. Punteros 11 Tema 10. Punteros 12

2
Algunas consideraciones Ejemplo paso parámetros
„ El puntero nulo PROGRAM
{-- programa principal ------}
„ Se dice que tiene el valor NIL (o NULL) Ejemplo_paso_parametros;
BEGIN
„ Antes de utilizar un puntero, debemos asegurarnos de que su TYPE Tptr=^integer;
valor no es NIL referencia(p);
VAR p:Tptr;
„ El gestor de memoria devuelve NIL cuando no ha sido posible writeln(p^);
{--- ejemplo de paso por referencia--}
la asignación de memoria requerida por la llamada NEW Dispose(p);
PROCEDURE referencia(VAR q:Tptr);
„ Paso de parámetros BEGIN
valor(p);
„ A la hora de pasar como parámetro un puntero, debe realizarse writeln(p^);
por referencia, siempre y cuando lo que se haga dentro del New(q);
END.
módulo llamado afecte no al objeto apuntado por el puntero, q^:=20;
sino al propio puntero END;
„ En cambio, si lo que realizamos en el interior del módulo {--- ejemplo de paso por valor ---}
llamado afecta no ya al puntero sino al objeto apuntado por el
mismo, entonces es indiferente el modo de pasar el parámetro PROCEDURE valor(q:Tptr);
ya que ambos punteros - el puntero existente en memoria BEGIN
principal y el creado en la pila - apuntan al mismo espacio de New(q);
memoria
q^:=20;
END;
Tema 10. Punteros 13 Tema 10. Punteros 14

El operador @ Procesamiento de listas


„ El operador @ se puede aplicar a una variable (no puntero) y „ Operaciones básicas sobre listas
devuelve la dirección de memoria dónde está alojada dicha variable
„ Mostrar los elementos de la lista
p := @v
„ En este caso, no se está trabajando con memoria dinámica, sino con „ Insertar un elemento
memoria estática, y el puntero no va a apuntar a direcciones del „ Borrar un elemento
heap sino a direcciones del rango de la zona de datos estáticos
„ Buscar un elemento
„ Ejemplo
Var p:^integer; „ Tipos especiales de listas
v:integer; „ Pilas o listas LIFO (Last In First Out)
Begin „ Las inserciones siempre se realizan por el final
v:=10;
„ Las eliminaciones siempre se realizan por el final
p:=@v;
p^:=p^+1; „ Colas o listas FIFO (First In First Out)
writeln(v,p^); „ La inserciones siempre se realizan por el final
End. „ Las eliminaciones siempre se realizan por el principio

Tema 10. Punteros 15 Tema 10. Punteros 16

Insertar un elemento
Listas con arrays PROCEDIMIENTO insetar(
VAR lista:LISTAENTEROS; {lista de enteros}
„ Se utiliza un array unidimensional para almacenar la VAR NumElem:ENTERO; {Nº de elementos de la lista}
lista, de manera que el i-ésimo elemento de la lista se elem:ENTERO; {elemento a insertar}
corresponde con el i-ésimo elemento del array pos:ENTERO ) {posición en la que se inserta}
TIPO VARIABLES
listaenteros=ARRAY[1..Limite] de ENTEROS i:ENTERO
VARIABLES INICIO
lista:listaenteros PARA i=0 HASTA NumElem-pos HACER
lista[NumElem+1-i] ← lista[NumElem-i]
„ Operaciones inmediatas {Desplazar todos los elementos a partir de}
„ Leer y escribir los elementos de la lista FIN_PARA {la posición en la que se va a insertar}
„ Buscar un elemento de la lista Lista[pos] ← elem {Insertar el elemento en la posición ‘pos’}
NumElem ← NumElem+1 {Incrementar el nº total de elementos}
„ Limitaciones FIN_PROC
„ Los arrays deben tener una longitud fija (son estructuras Lista es (34,52,12,6,10) y NumElem es 6
estáticas) Llamada al procedimiento INSERTAR(lista,NumElem,38,3)
„ Operación de inserción y eliminación (algoritmos sencillos pero 34,52,12 ,6 ,10
ineficientes)
34,52,38,12,6,10
Tema 10. Punteros 17 Tema 10. Punteros 18

3
Listas enlazadas Lista enlazada
„ Cuándo usar estructuras dinámicas
BOA
„ El tamaño de una lista no se puede predecir a priori GATO
PERRO
„ Las operaciones de inserción y borrado son frecuentes
„ Las listas enlazadas son una secuencia de nodos que se enlazan LEON
mediante un enlace o puntero Dirección

„ Cada nodo o elemento de la lista debe tener dos campos: ………………


150 LEON 153
„ Un campo con los valores de cada elemento (datos)
151
„ Un campo que indica la posición del elemento siguiente (enlace o
152 BOA 157
puntero, representado por una flecha)
153 PERRO NIL
Lista de enteros
5 8 1 9 3 ………… 8 con arrays 154

155
Lista
156
5 8 1 9 ………… 8
157 GATO 150
158
Lista enlazada de enteros con punteros
………………

Tema 10. Punteros 19 Tema 10. Punteros 20

Implementación de listas Lista de enteros con punteros


Declaración de un nodo
„
TYPE
TYPE
TipoElemento=…; {puede ser cualquier tipo de datos} TipoElemento=Integer;
PunteroNodo=^TipoNodo;
TipoNodo = record PunteroNodo=^TipoNodo;
Elemento:TipoElemento;
Siguiente:PunteroNodo; TipoNodo= record
End;
Elemento:TipoElemento;
„ TipoElemento puede ser cualquier tipo de datos válido
„ La declaración de PunteroNodo precede a TipoNodo: ésta es la única situación en la Siguiente:PunteroNodo;
que se permite utilizar un identificador antes de ser definido
„ Cuando se implementa una lista enlazada se necesita un puntero adicional (puntero
End;
cabecera) que se utiliza para apuntar al primer elemento de la lista Lista=PunteroNodo;
„ El puntero cabecera es distinto a los elementos de la lista puesto que no contiene
ningún elemento sino solo un dato de tipo puntero, sirve simplemente para obtener el VAR
principio de la lista por lo que se trata de un putero externo que está fuera de la lista y
que debe existir siempre L:Lista; {---- Cabecera de la lista -----}
La declaración sería de la siguiente manera
„
VAR cabecera: PunteroNodo;
P:PunteroNodo; {----- Nodo individual ---------}
„ Si el valor de cabecera es NIL significa que la lista está vacía X:TipoElemento;

Tema 10. Punteros 21 Tema 10. Punteros 22

Crear una lista a partir de datos de entrada Crear una lista a partir de los
PROCEDURE crea_lista5_teclado(VAR l:lista);
VAR
datos de un fichero
i:INTEGER; x:TipoElemento; p:PunteroNodo; PROCEDURE crea_lista_fichero(VAR l:lista;VAR F:FIC);
BEGIN {Se supone que el fichero ya está creado y asignado. El tipo FIC se definió en el programa principal}
VAR
WRITELN('Introduzca 5 datos de entrada para crear la lista'); i:INTEGER; x:TipoElemento; p:PunteroNodo;
NEW(l); BEGIN
READLN(x); RESET(F);
IF NOT EOF(F) THEN BEGIN
l^.elemento:=x; READ(F,x); NEW(l);
p:=l; l^.elemento:=x;
i:=2; p:=l;
WHILE (i<=5) DO WHILE NOT EOF(F) DO
BEGIN
BEGIN READ(F,x);
READLN(x); NEW(p^.siguiente);
NEW(p^.siguiente); p:=p^.siguiente;
p^.elemento:=x;
p:=p^.siguiente; END;
p^.elemento:=x; p^.siguiente:=NIL;
i:=i+1; END
ELSE WRITELN(‘El fichero está vacío. No se puede crear la lista);
END;
CLOSE(F);
p^.siguiente:=NIL; END;
END;

Tema 10. Punteros 23 Tema 10. Punteros 24

4
Añadir un elemento al final de la
Imprimir una lista
lista
PROCEDURE imprime_lista(l:lista);
PROCEDURE add_elemento(VAR l:lista;x:TipoElemento);
VAR VAR
p:PunteroNodo;
p:PunteroNodo; BEGIN
BEGIN IF (l=NIL) THEN BEGIN
NEW(l);
p:=l; l^.elemento:=x;
l^.siguiente:=NIL;
WHILE (p<>NIL) DO END
ELSE BEGIN
BEGIN p:=l;
WHILE (p^.siguiente<>NIL) DO
WRITELN(p^.elemento); p:=p^.siguiente;
p:=p^.siguiente; NEW(p^.siguiente);
p:=p^.siguiente;
END; p^.elemento:=x;
p^.siguiente:=NIL;
END; END;
END;

Tema 10. Punteros 25 Tema 10. Punteros 26

Insertar un elemento en una lista


Borrar un elemento del final ordenada
PROCEDURE borra_ultimo(VAR l:lista); PROCEDURE inserta_elem(VAR l:lista;x:TipoElemento);
VAR VAR
p,q:PunteroNodo;
p:PunteroNodo; encontrado:boolean;
BEGIN BEGIN
IF (l=NIL) THEN WRITELN('Error.Lista vac¡a. No se puede borrar') new(q);
ELSE BEGIN q^.elemento:=x;
p:=l; IF (l=NIL) THEN BEGIN {-- la lista está vacía --}
IF (p^.siguiente=NIL) THEN BEGIN l:=q;
q^.siguiente:=NIL;
l:=NIL;
END
DISPOSE(p); ELSE BEGIN {-- al menos hay un elemento --}
END p:=l;
ELSE BEGIN IF (q^.elemento<p^.elemento) THEN BEGIN {-- se inserta en 1ª posición -}
WHILE (p^.siguiente^.siguiente<>NIL) DO q^.siguiente:=p;
p:=p^.siguiente; l:=q;
DISPOSE(p^.siguiente); END
ELSE BEGIN {-- se inserta a partir de la 2ª posición--}
p^.siguiente:=NIL;
END; ********* segmento de código en la siguiente diapositiva ***********
END;
END; END;
END; (--- fin de cuando hay al menos un elemento ----}
END;
Tema 10. Punteros 27 Tema 10. Punteros 28

Insertar un elemento en una lista TDA Lista con Punteros


ordenada
IF (p^.siguiente<>NIL) THEN BEGIN {- si hay 2 elementos o mas } „ Tipo de Dato Abstracto
encontrado:=FALSE;
WHILE (p^.siguiente^.siguiente<>NIL) AND NOT encontrado DO „ Definir el tipo de dato
BEGIN {mientras no se llegue al penúltimo} „ Definir todas las operaciones (primitivas) que se van a utilizar
IF (p^.siguiente^.elemento<q^.elemento) THEN { y no se haya encontrado dónde insertar} sobre ese tipo de dato
p:=p^.siguiente
ELSE BEGIN „ TDA Lista de enteros: Definición de tipo
q^.siguiente:=p^.siguiente; p^.siguiente:=q;
encontrado:=TRUE; TYPE
END; TipoElemento=Integer;
END; {---- Fin del while no llegue al penúltimo y no hay encontrado dónde insertar----}
IF NOT encontrado THEN BEGIN {-- insertar como último o penúltimo ---}
PunteroNodo=^TipoNodo
IF (q^.elemento<p^.siguiente^.elemento) THEN BEGIN {insertar como penúltimo } TipoNodo= record
q^.siguiente:=p^.siguiente; p^.siguiente:=q; Elemento:TipoElemento;
END
ELSE BEGIN {insertar como último} Siguiente:PunteroNodo;
q^.siguiente:=NIL; p^.siguiente^.siguiente:=q; End;
END;
END; Lista=PunteroNodo;
END
ELSE BEGIN
{----- fin del SI hay 2 o mas elementos ----}
{- hay solo un elemento. se inserta el 2º como último elemento --}
VAR
p^.siguiente:=q; L:Lista {---- Cabecera de la lista -----}
q^.siguiente:=NIL; P:PunteroNodo; {----- Nodo individual ---------}
END;

Tema 10. Punteros 29 Tema 10. Punteros 30

5
Primitivas con el TDA Lista con Implementación de primitivas
Punteros (Crear lista y Comprobar si vacía)
„ Operaciones de la lista enlazada PROCEDURE crear ( VAR l: lista );
„ Crear lista vacía { Crea la lista vacía }
BEGIN { Del procedimiento hacerNula }
„ Comprobar si la lista está vacía
l:= NIL; {Establece como último elemento de la lista la cabecera }
„ Localizar la posición END; { Del procedimiento hacerNula }
„ Recuperar elemento de una posición
„ Insertar elemento { ---------------------------------------------------- }
„ Borrar elemento FUNCTION vacia ( l: lista ) : BOOLEAN;
{ Devuelve True si la lista l está vacía, o FALSE en otro caso }
BEGIN { De la función vacía }
vacia := l = NIL;
END; { De la función vacía }

Tema 10. Punteros 31 Tema 10. Punteros 32

Localizar un elemento Recuperar un elemento


FUNCTION localizar ( x : TipoElemento ; l : lista ) : PunteroNodo ;
{ Devuelve la posición en que se encuentra el elemento x en la lista l } PROCEDURE recuperar ( VAR x: TipoElemento; p: PunteroNodo; l: lista );
VAR
{ Recupera en x el elemento que ocupa la posición p de la lista l }
p : PunteroNodo;
encontrado : boolean; BEGIN { Del procedimiento recupera }
BEGIN { De la función localiza } IF (p<>NIL) THEN { No estamos al final de la lista }
p := l; x:= p^.elemento
encontrado := FALSE; ELSE WRITELN ( ‘posicion errónea’ );
WHILE ( (p <> NIL ) AND ( NOT encontrado )) DO
END; { Del procedimiento recupera }
IF ( p^.elemento = x ) THEN
encontrado := TRUE
ELSE p := p^.siguiente;
localiza := p;
END; { De la función localiza }

Tema 10. Punteros 33 Tema 10. Punteros 34

Insertar un elemento Borrar un elemento


PROCEDURE insertar ( x: TipoElemento ; p :PunteroNodo; VAR l : lista ); PROCEDURE borrar ( p : PunteroNodo ; VAR l: lista );
{ Inserta el elemento x en la posicion p de la lista l , si p es una posición válida } { Borra el elemento que ocupa la posición p de la lista l, si p es una posición válida}
VAR VAR
q,aux : PunteroNodo; q : PunteroNodo;
BEGIN { Del procedimiento insertar } BEGIN { Del procedimiento borrar }
IF (l=NIL) THEN BEGIN {Lista está vacía, se insertará el primer elemento} IF (l=NIL) THEN {lista vacía}
NEW(l); l^.elemento:=x; l^.siguiente:=NIL; WRITELN (‘Error. No se puede borrar. Lista vacía’)
END ELSE IF (l=p) THEN BEGIN {borrar el primero de la lista}
ELSE BEGIN l:=l^.siguiente;
NEW(aux); aux^.elemento:=x; DISPOSE(p);
IF (l=p) THEN BEGIN {se inserta como el primero de la lista} END
l:=aux; l^.siguiente:=p; ELSE BEGIN {borra cualquier otro elemento}
END q:=l;
ELSE BEGIN {se inserta en cualquier otra posición} WHILE (q^.siguiente<>p) AND (q^.siguiente<>NIL) DO
q:=l; {q apuntará al anterior de p} q := q^.siguiente;
WHILE (q^.siguiente<>p) DO IF (q^.siguiente<>NIL) THEN BEGIN
q:=q^.siguiente; q^.siguiente:=q^.siguiente^.siguiente;
q^.siguiente := aux; DISPOSE ( p );
aux^.siguiente:=p; END
END; ELSE WRITLEN(‘Error. No se encuentra la posición’);
END; END;
END; { Del procedimiento insertar } END;
END; { Del procedimiento borrar }
Tema 10. Punteros 35 Tema 10. Punteros 36

6
Posición anterior a una dada
Primitivas adicionales FUNCTION anterior ( p: PunteroNodo; l : lista ) : PunteroNodo;
{ Devuelve la posicion anterior a la posicion p en la lista l. Si p no es una posición válida
o estamos al principio de la lista devuelve NIL }
VAR
aux: PunteroNodo;
„ Posición anterior encontrado: boolean;
BEGIN
„ Posición siguiente IF ( p = l ) THEN { Estamos al principio de la lista }
anterior:=NIL
„ Posición del primer elemento ELSE BEGIN
aux := l;
„ Posición del último encontrado := FALSE;
WHILE ( aux^.siguiente <> NIL ) AND ( NOT encontrado ) DO
„ … IF ( aux^.siguiente = p ) THEN
encontrado := TRUE;
ELSE aux := aux ^.siguiente;
IF encontrado THEN
anterior := aux;
ELSE anterior:=NIL;
END;
END; { De la función anterior }

Tema 10. Punteros 37 Tema 10. Punteros 38

Posición del primer y último


Posición siguiente a una dada elemento
FUNCTION primero ( l: lista ) : PunteroNodo;
FUNCTION siguiente ( p : PunteroNodo; l : lista ) : PunteroNodo;
{ Devuelve la posición del primer elemento de la lista }
{ Devuelve la posicion siguiente a p en la lista l o NIL si no es posible }
BEGIN { De la función primero }
VAR
primero := l;
q : PunteroNodo;
END; { De la función primero }
encontrado : boolean;
{ ---------------------------------------------------- }
BEGIN { De la función siguiente }
FUNCTION final ( l : lista ) : PunteroNodo;
q := l;
{ Devuelve la última posición de la lista l }
encontrado := FALSE;
VAR
WHILE ( q <> NIL ) AND ( NOT encontrado )
q : PunteroNodo;
IF ( q = p ) THEN
BEGIN { De la función final }
encontrado := TRUE
q := l;
ELSE q := q^.siguiente;
IF (q<>NIL) THEN
IF encontrado THEN
WHILE ( q^.siguiente <> NIL ) DO
siguiente := q^.siguiente
q := q^.siguiente;
ELSE siguiente:=NIL;
final := q;
END; { De la función siguiente }
END; { De la función final }

Tema 10. Punteros 39 Tema 10. Punteros 40

Implementación de listas con


Consideraciones a tener en cuenta
Nodo Cabecera „ Comprobar si la lista está vacía: l^.siguiente=NIL
L
„ Hasta ahora todos los nodos contenían información relevante
„ Las operaciones de inserción y borrado deben considerar la posición
en la que se va a realizar la operación „ Acceder al primer elemento de la lista: l^.siguiente^.elemento
„ Se puede utilizar otra implementación en la que dichas operaciones l^.siguiente^.elemento
L
fueran independientes de la posición en las que se quiere realizar 5 8 …… 7 8
„ Para ello, se usará la Implementación con Nodo Cabecera
„ Acceder a un elemento de la lista apuntado lógicamente por p:
„ El primer nodo de la lista se llama cabecera y no contiene ningún p^.siguiente^.elemento
elemento p
„ Siempre se deja el primer elemento vacío L
5 8 7 8
„ El primer nodo lógico (con información útil) de la lista será en ……
realidad el segundo nodo físico „ Comprobar si estamos en el último elemento de la lista:
L p^.siguiente^.siguiente=NIL
p
5 8 1 ………… 8
L
Lista enlazada de enteros con Nodo Cabecera 5 8 …… 7 8

Tema 10. Punteros 41 Tema 10. Punteros 42

7
Implementación de primitivas con Localizar la posición de un
Nodo Cabecera elemento en la lista
FUNCTION localizar ( x : tipoElemento ; l : lista ) : PunteroNodo ;
PROCEDURE Crear ( VAR l: lista );
{ Devuelve la posición en que se encuentra el elemento x en la lista l }
{ Crea la lista vacía } VAR
BEGIN { Del procedimiento hacerNula } p : PunteroNodo;
NEW ( l ); { Crea la celda cabecera } encontrado : boolean;
l^.siguiente := NIL; {Establece como último elemento de la lista la cabecera } BEGIN { De la función localiza }
END; { Del procedimiento hacerNula } p := l;
{ ---------------------------------------------------- } encontrado := FALSE;
FUNCTION vacia ( l: lista ) : BOOLEAN; WHILE ( p^.siguiente <> NIL ) AND ( NOT encontrado ) DO
{ Devuelve True si la lista l está vacía, o FALSE en otro caso } IF ( p^.siguiente^.elemento = x ) THEN
BEGIN { De la función vacía } encontrado := TRUE
vacia := l^.siguiente = NIL;
ELSE p := p^.siguiente;
localizar := p;
END; { De la función vacía }
END; { De la función localiza }

Tema 10. Punteros 43 Tema 10. Punteros 44

Recuperar un elemento dada una Insertar un elemento


posición PROCEDURE insertar(x: tipoElemento ; p :PunteroNodo; VAR l : lista );
{ Inserta el elemento x en la posicion p de la lista l }
VAR
PROCEDURE recuperar(VAR x: tipoElemento; p: PunteroNodo; l: lista ); q : PunteroNodo;
{ Recupera en x el elemento que ocupa la posición p de la lista l } BEGIN { Del procedimiento insertar }
BEGIN { Del procedimiento recupera } q := p^.siguiente;
IF (p^.siguiente<>NIL) THEN { No estamos al final de la lista } NEW ( p^.siguiente );
p^.siguiente^.elemento := x;
x:= p^.siguiente^.elemento
p^.siguiente^.siguiente := q;
ELSE END; { Del procedimiento insertar }
error ( ‘posicion errónea’ );
END; { Del procedimiento recupera }

Tema 10. Punteros 45 Tema 10. Punteros 46

Borrar un elemento Posición anterior


PROCEDURE borrar ( p : PunteroNodo ; VAR l: lista ); FUNCTION anterior ( p: PunteroNodo; l : lista ) : PunteroNodo;
{ Borra el elemento que ocupa la posición p de la lista l } { Devuelve la posicion anterior a la posicion p en la lista l }
VAR VAR
q : PunteroNodo; aux: PunteroNodo;
BEGIN { Del procedimiento borrar } encontrado: boolean;
IF (p^.siguiente<>NIL) THEN {posición correcta de la lista} BEGIN
BEGIN IF ( p = l ) THEN { Estamos al principio de la lista }
q := p^.siguiente; error ( ‘No hay posicion anterior’ )
p^.siguiente := q^.siguiente; ELSE BEGIN
DISPOSE ( q ); aux := l;
END; encontrado := FALSE;
END; { Del procedimiento borrar } WHILE ( aux^.siguiente <> NIL ) AND ( NOT encontrado ) DO
IF ( aux^.siguiente = p ) THEN
encontrado := TRUE;
ELSE aux := aux ^.siguiente;
IF encontrado THEN
anterior := aux;
ELSE anterior:=NIL;
END; { De la función anterior }

Tema 10. Punteros 47 Tema 10. Punteros 48

8
Posición siguiente
FUNCTION siguiente ( p : PunteroNodo ; l : lista ) : PunteroNodo;
{ Devuelve la posicion siguiente a p en la lista l }
VAR
q : PunteroNodo;
encontrado : boolean;
BEGIN { De la función siguiente }
q := l;
encontrado := FALSE;
WHILE ( q <> NIL ) AND ( NOT encontrado )
IF ( q = p ) THEN
encontrado := TRUE
ELSE q := q^.siguiente;
IF encontrado THEN
siguiente := q^.siguiente
ELSE error ( ‘posicion incorrecta ‘ );
END; { De la función siguiente }

Tema 10. Punteros 49

También podría gustarte