listas enlazadas - Paginas Prodigy

Anuncio
LISTAS ENLAZADAS
UNIDAD IV
____________________________________________________________________________________________________
UNIDAD IV
LISTAS ENLAZADAS
4.1. REPRESENTACIÓN DE LISTAS ENLAZADAS
4.1.1. IMPLEMENTACION DE LISTA ENLAZADA USANDO ARREGLOS
LISTAS ENLAZADAS.- Se define como un conjunto de elementos(nodos) en donde cada nodo se
compone al menos de dos campos en donde un campo contiene el dato o información del nodo y el otro
campo la dirección del siguiente nodo, con lo cual los datos o información no tienen que estar en
direcciones contiguas de memoria, las listas enlazadas emplean puntero o apuntadores para poder iniciar
la lista se requiere de un puntero que su única función Serra la de apuntar al primer elemento de la lista,
además en el ultimo nodo de la lista su apuntador deberá ser a un nulo o cero para indicar el final de la
lista.
NODO
Dato
(información)
enlace
(puntero)
LISTA ENLAZADA
LISTA
5
2
8
10
6
DIFERENTES FORMAS DE INDICAR APUNTADOR NULO
4





4
11
NULL
Las características que deberá tener un alista enlazada para definirse, se listan a continuación.
El tipo de sus elementos.
Campo de información (datos).
Campos enlace (puntero).
Un puntero de cabecera que permite acceder al primer elemento de la lista.
Un medio para detectar el ultimo elemento de la lista puntero nulo (NULL).
____________________________________________________________________________________________________
ESTRUCTURA DE DATOS
ING. OSORNIO
64
LISTAS ENLAZADAS
UNIDAD IV
____________________________________________________________________________________________________








Para procesar una lista enlazada se necesitan las siguientes informaciones.
Primer nodo (cabecera).
El tipo de elementos.
El tamaño de la lista (la definición de sus elementos o nodos).
Las operaciones que normalmente se ejecutan con listas enlazadas son.
Recuperar información de un nodo especifico (acceso a un elemento).
Encontrar el nodo que contiene una información especifica (localizar la posición de un elemento
dado).
Insertar un nuevo nodo en un lugar especifico de la lista.
Insertar un nuevo nodo en relación a una información particular.
Borrar (eliminar) un nodo existente que contiene información especifica.
En el lenguaje C la forma de constituir una lista enlazada será a través de estructuras de datos que
dentro de sí contienen un campo que es un puntero el cual apunta a estructuras del mismo tipo y a esto
se le conoce como estructura auto referenciada, a continuación se da un ejemplo.
struct node
{
int data;
struct node *nextptr;
};
Para el manejo de la asignación dinámica de memoria se requiere de emplear malloc() y free() en
donde la función malloc se empleara para tomar como argumento el numero de bytes a asignarse y
devuelve un apuntador de tipo void a la memoria asignada, y los apuntadores tipo void pueden
asignarse a una variable de cualquier tipo de apuntador, deberá emplearse conjuntamente con el
operador sizeof(), la función free() se empleara para liberar la memoria asignada dinámicamente y la
regresa al sistema, para que pueda ser asignada de nuevo mediante una llamada de malloc, sizeof() es
un operador que devuelve el tamaño del tipo de dato que se ponga entre paréntesis, el valor devuelve
es en bytes.
Las lista enlazadas en turbo C se construirán a partir de estructuras auto referenciadas en donde
cada elemento de la lista (nodo) están conectados por los enlaces del apuntador de aquí que la lista se
le llama enlazada, la lista debe de contar con un apuntador al primer elemento, uno o mas nodos y un
nodo, el ultimo que contenga el apuntador hacia un valor nulo (NULL) para indicar el final de la lista,
a continuación se dará un ejemplo de lista enlazada en partes de modo que se pueda explicar que es lo
que hace cada una de esas partes.
Una lista enlazada es una colección lineal de estructuras autorreferenciadas llamadas nodos,
conectadas por enlace de apuntador –de ahí el termino lista “enlazada”. Se tiene acceso a una lista
enlazada via un apuntador al primer nodo de la lista. Se puede tener acceso a los nodos subsecuentes
via el apuntador de enlace, en el ultimo nodo de una lista, se define a NULL. En la lista enlazada los
datos se almacenan dinámicamente – cada nodo se crea conforme sea necesario. Un nodo puede
contener datos de cualquier tipo, incluyendo otras struct. Las pilas y las colas de espera tambien son
estructuras lineas de datos, y como veremos, son versiones restringidas de listas enlazadas. Los arboles
son estructuras no lineales de datos.
____________________________________________________________________________________________________
ESTRUCTURA DE DATOS
ING. OSORNIO
65
LISTAS ENLAZADAS
UNIDAD IV
____________________________________________________________________________________________________
Las listas de datos pueden ser almacenadas en arreglos, pero las listas enlazadas proporcionan
varias ventajas. Una lista enlazada es apropiada cuando no es predecible de inmediato el numero de
elementos de datos s representarse en la estructura. Las listas enlazadas son dinamicas, por lo que
conforme sea necesario la longitud de una lista puede aumentar o disminuir. Por su parte, el tamaño de
un arreglo no puede ser modificado, porque la memoria del arreglo es asignada en tiempo de
compilación. Los arreglos pueden llenarse. Las listas enlazadas solo se llenan cuando el sistema no
tiene suficiente memoria para satisfacer las solicitudes de asignación dinamica de almacenamiento.
Las listas enlazadas pueden mantenerse en orden, insertando cada elemento nuevo en el punto
apropiado dentro de la lista.
Normalmente, los nodos de las listas no estan almacenados en memoria en forma contigua. Sin
embargo, lógicamente, los nodos de una lista enlazada, aparecen como contiguos. En la siguiente
figura se ilustra una lista enlazada con varios nodos.
LISTA
5
2
8
6
10
El programa que se presenta enseguida, manipula una lista de carácteres. El programa da dos
opciones: 1) insertar un carácter en la lista en orden alfabético (función insert) y 2) borra un carácter
de la lista (función deleded). Este es un programa grande y complejo. Sigue un análisis detallado
respecto al programa.
Las dos funciones primarias de las lista enlazadas son insert y deleted. La función isEmpty (esta
vacía) se conoce como una función predicada – no altera en forma alguna la lista; mas bien determina
si la lista esta vacia (es decir, si el apuntador al primer nodo de la lista es NULL). Si la lista esta
vacía, se regresa 1; de lo contrario se regresa 0. La función printList imprime la lista.
En la lista los carácteres se insertan en orden alfabético (lo hace el programa). La función insert
recibe la dirección de la lista y el carácter a insertarse. Es necesaria la dirección de la lista cuando se
va a insertar un valor en el inicio de la lista. Proporcionar la dirección de la lista permite que se pueda
modificar la lista( el apuntador al primer nodo de la lista) vía una llamada por referencia. Dado, que la
lista de caracteres ó dicha es un apuntador (a su primer elemento), pasar la dirección de la lista crea un
apuntador a un apuntador (es decir, una doble indirección). Este es un concepto complejo y requiere
de cuidadosa programacion. Los pasos para la inserción de un caracter en la lista son como sigue.
1. Crear un nodo llamado malloc la dirección de la memoria asignada, asignando el carácter a
insertarse a newPtr ->data, asignando NULL a newPtr -> nextPtr
2. Inicialice previousPtr a NULL, y currentPtr a *sPtr ( el apuntador al inicio de la ista). Los
apuntadores previousPtr y currentPtr se utilizan para almacenar las posiciones del nodo anterior
al punto de inserción y del nodo posterior al punto de inserción
3.
En tanto currentPtr no sea NULL y el valor a insertar sea mayor que currentPtr->dato, asigne
currentPtr a previousPtr y avance currentPtr al siguiente nodo en la lista. Esto posiciona en la lista
____________________________________________________________________________________________________
ESTRUCTURA DE DATOS
ING. OSORNIO
66
LISTAS ENLAZADAS
UNIDAD IV
____________________________________________________________________________________________________
el punto de inserción del valor.
4.
Si previousPtr es NULL, se inserta el nodo como primer nodo de la lista. Asigne *sPtr a newPtr>nextPtr (el nuevo enlace de nodo apunta al anterior primer nodo), asigne newPtr a sPtr ( *sPtr
apunta al nuevo nodo). Si previousPtr no es NULL, el nuevo nodo se inserta en su lugar. Asigne
newPtr a previousPtr->nextPtr (el nodo anterior apunta al nuevo nodo), y asigne currentPtr a
newPtr->nextPtr (el enlace de nuevo nodo apunta al nodo actual).
En los siguientes diagramas se muestra como es que se inserta un nodo en la lista enlazada.
*sPtr
previousPtr
A
currentPtr
B
D
E
newPtr
C
*sPtr
previousPtr
A
B
currentPtr
D
E
newPtr
C
En la siguiente figura se ilustra la insercion de un nodo conteniendo el carácter C en una lista
ordenada. La parte a) de la figura muestra la lista y el nuevo nodo antes de la insercion. La parte b) de la
figura muestra el resultado de la insercion del nuevo nodo. Loa apuntadores rreasignados estan
representados por flechas y lineas punteadas
La funcion deleted recibe la direccion del apuntador hacia el principio de la lista y un carácter a
borrarse. Los pasos para borrar un carácter de la lista son como siguen:
1.
Si el carácter a borrarse coincide con el primer carácter del primer nodo de la lista, asigna *sPtr
____________________________________________________________________________________________________
ESTRUCTURA DE DATOS
ING. OSORNIO
67
LISTAS ENLAZADAS
UNIDAD IV
____________________________________________________________________________________________________
a tempPtr (tempPtr sera utilizado para liberar, usando free, la memoria no necesaria), asigna
(*sPtr)->nextPtr a sPtr a (sPtr ahora apunta al segundo node de la lista), free libera la memoria
apuntada por tempPtr, y regresa el carácter que fue liberado.
2. De no ser asi, inicializa previousPtr con sPtr e inicializa currentPtr con (*sPtr)->nextPtr .
3.
En tanto currentPtr no sea NULL y el valor a borrarse no sea igual currrentPtr->data, asigna
currentPtr a previousPtr, y asigna currentPtr->nextPtr a currentPtr. Esto localizara el carácter a
borrarse, si esta contenido dentro de la lista.
4.
Si currentPtr no es NULL, asigna currentPtr a tempPtr, asigna currentPtr->nextPtr a previousPtr>nextPtr, libera al nodo al cual apunta tempPtr, y regresa el carácter que fue borrado de la lista.
Si currentPtr es NULL regresa el carácter NULL (‘\0’), para significar que el carácter a borrarse
no fue encontrado dentro de la linea.
A continuacion se darán 2 diagramas a bloques que nos muestran como se borra un elemento o
nodo de la lista enlazada.
*sPtr
previousPtr
curenttPtr
a)
A
*sPtr
B
C
previousPtr
currentPtr
D
E
b)
A
B
C
D
E
tempPtr
En la figura anterior se ilustra el borrado de un nodo de una lista enlazada. La parte a) de la figura
muestra la lista enlazada, antes de la operación de inserción anterior. La parte b) muestra la reasignación
del elemento de enlace de previousPtr y la asignación de currentPtr a tempPTr. El apuntador tempPtr se
utiliza para liberar la memoria asignada par almacenar C.
La funcion printList recibe un apuntador al inicio de la lista como un argumento y se refiere al
apuntador como currentPtr. La funcion primero determina si la lista esta vacia, si es asi, printList
imprime”la lista esta vacia” y termina. De lo contrario los datos en la lista. En tanto currentPtr no sea
NULL, currentPtr ->data sera impreso por la funcion, y currentPtr ->nextPtr sera signado a currentPtr.
____________________________________________________________________________________________________
ESTRUCTURA DE DATOS
ING. OSORNIO
68
LISTAS ENLAZADAS
UNIDAD IV
____________________________________________________________________________________________________
Note que si en el ultimo nodo el enlace de la lista no es NULL, el algoritmo de impresión es idéntico para
listas enlazadas, pilas y colas de espera.
/* PROGRAMA DE UNA LISTA*/
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
*/
/* Incluye el fichero stdio.h las funciones scanf y printf */
/* Incluye el fichero conio.h las funciones clrscr*/
/* Incluye el fichero stdlib.h las funciones malloc y free
struct listNode
{
char data;
struct listNode *nextPtr;
};
/* Definicion estructura autoreferenciada */
/* Miembro de la estructura, dato de tipo caracter */
/* Miembro, tipo puntero al mismo tipo de estructura */
typedef struct listNode LISTNODE;
/* Renombrar la struct listNode con LISTNODE */
typedef LISTNODE *LISTNODEPTR; /* Renombrar la LISTONODE con *LISTNODE */
void insert (LISTNODEPTR , char);
char deleted (LISTNODEPTR *, char);
int isEmpty (LISTNODEPTR);
void printList(LISTNODEPTR);
void instructions(void);
/* Funcion de insertar caracter */
/* Funcion de borrar caracter */
/* Funcion de lista vacia */
/* Funcion de imprimir lista */
/* Funcion de menu de instrucciones */
/* Programa principal es aquí desde donde se mandan a ejecución a las funciones que permitiran insertar
y
borrar elementos de la lista enlazada, este programa contiene un puntero startPtr el cual se empleara para
apuntar al primer dato o nodo de la lista y definir si existen elementos o no existrir elementos el valor de
este puntero permanecera en un NULL, tambien contiene la ejecución de la función de instrucciones la
cual le indicara al usuario que hacer, después hay una estructura while que hace repetitivo todo el
programa y dentro de esta hay una estructura de selección múltiple la cual permitira ejecutar por decisión
del usuario que desea hacer es decir insertar un elemento, borrar el elemento o salir del programa*/
main()
{
LISTNODEPTR startPtr = NULL;
int opcion;
char item;
/* Declaracion de la variable (de una estructura), starPtr
igual a NULL */
/* Declaracion de la variable opcion de tipo entero */
/* Declaracion de la variable item de tipo caracter */
clrscr();
instructions();
printf("?");
scanf("%d",&opcion);
/* Limpiar pantalla */
/* Llamada a la funcion de instrucciones */
/* Imprimir el sigo de interrogacion ? */
/* Almacenar la opcion elegida */
while (opcion != 3 )
/* Mientras la opcion sea diferente a 3 realiza lo siguiente */
{
switch(opcion)
{
/* switch evalua el numero de opcion */
____________________________________________________________________________________________________
ESTRUCTURA DE DATOS
ING. OSORNIO
69
LISTAS ENLAZADAS
UNIDAD IV
____________________________________________________________________________________________________
case 1: printf("Introduzca un caracter: ");
/* Si es 1 ejecuta lo siguiente*/
scanf("\n%c",&item);
/* Almacena en item el caracter a insertar */
insert(&startPtr,item);
/* Llamada a la funcion de insertar, enviando
los argumento de la direccion de starPtr y item
donde esta el caracter */
printList(startPtr);
/* Llamada a la funcion de imprimir lista */
break;
/* Finalizar cas 1 y switch */
case 2: if( ! isEmpty(startPtr))
/* Si es 2 evalua si lo que regresa la llamada a la
funcion lista vacia es cero y con el inveror se
vuelve 1 (verdarero) y ejecuta los siguiente*/
{
printf("Introduzca el caracter a borrar: ");
scanf("\n %c",&item);
/* almacena en item el caracter a borrar */
if(deleted(&startPtr,item))
/* Ir a la funcion de borrar carácter, para
ver si existe el caracter y borrarlo, regresa
un cero si no lo encuentra y se sale de if*/
{
printf("\n%c borrado ",item); /* Imprime el caracter encontrado */
printList(startPtr);
/* Llamada aa la funcion de imprimir */
}
else
/* Si no cumplio if ejecuta lo siguiente */
printf("%c no encontrado.\n\n",item);
}
else
/* Si la evaluación de 1er. if fue 0 ejecuta lo sig */
printf("La lista esta vacia \n\n");
break;
/* Salir de case 2 y de switch */
default: printf("Opcion no valida \n\n");
/*Si la opcion fue diferente a 1 y 2 ejecuta*/
instructions();
/* Llamad a la funcion de
instrucciones */
break;
}
printf("?");
scanf("%d",&opcion);
}
printf("Final de la ejecución. \n");
return 0 ;
}
/* Salir de default y de switch */
/* fin de switch */
/* Almacenar la nueva opcion seleccionada */
/* Fin de while (opcion !=3) */
/* Si es la opcion 3 imprimir lo siguiente */
/* El programa se ejecuto con éxito */
/*Fin de la funcion principal */
/* función instrucciones (subprograma) que despliega en pantalla las opciones de lo que puede hacer el
programa es decir un menu de opciones*/
void instructions(void)
/* Funcion instrucciones, el !er Void indica que no regresa
un valor y el segundo que no recibe argumentos */
{
printf("Introduzca su opcion \n"
" 1 Para insertar un elemento dentro de la lista \n"
____________________________________________________________________________________________________
ESTRUCTURA DE DATOS
ING. OSORNIO
70
LISTAS ENLAZADAS
UNIDAD IV
____________________________________________________________________________________________________
" 2 Para borrar un elemento de la lista.\n"
" 3 Para finalizar. \n");
}
/*función insertar (subprograma) la cual permitr insertar nuevos elementos (nodos) ademas de ir
ordenados alfabéticamente los nodos*/
/* Funcion de insertar un nodo con carácter y enlace */
void insert(LISTNODEPTR *sPtr, char value)
/* El 1er. void porque no regresa ningun
valor, recibe los argumentos (dirección de starPtr
la asignara a *sPtry y el item (carácter) a value */
{
LISTNODEPTR previousPtr, currentPtr, newPtr; /*Declaracion de las variables de estructura */
newPtr = (LISTNODEPTR) malloc(sizeof(LISTNODEPTR)); /* Crear un nuevo nodo llamado
malloc asignando a newPtr la direccion
de la memoria asignada */
if (newPtr != NULL)
/* Si el nuevo nodo es diferente a NULL ejecuta lo
siguiente */
{
newPtr->data = value;
/* Asignale el carácter a insertarse al miembro de
la estructura newptr->data */
newPtr->nextPtr = NULL;
/* Asignale NULL al apuntador al inicio de la ista (enlace) del
miembro de la estructura newPtr->nextPtr */
previousPtr=NULL;
/* Inialice y asignale NULL al apuntador (enlace) previousPtr y
se utilza para almacenar las posiciones del nodo anterior al punto de
insercion */
currentPtr=*sPtr;
/* Inialice y asignale la direccionde *sPtr al apuntador
currentPtr (enlace), y se utilza para almacenar las posiciones del
nodo posterior al punto de insercion */
while(currentPtr !=NULL && value > currentPtr->data)
/*Mientras el apuntador
current no sea NULL y el
carácter a insertarse sea mayor a
currentPtr->data, ejecuta y
ORDENA */
{
previousPtr = currentPtr;
/* Asigna currentPtr al apuntador previousPtr */
currentPtr = currentPtr->nextPtr; /* Avance currentPtr al siguiente nodo de la
lista, esto lo posiciona en el punto de inserción */
}
if(previousPtr == NULL)
/* Si previousPtr es NULL, se inserta el
nuevo nodo como el 1er. nodo de la lista */
{
newPtr->nextPtr = *sPtr;
/* Lo que tengas en *sPtr, asígnaselo a
newPrt->nextPtr, *sPtr apunta NULL ahora
newPtr-> apunta a NULL, el nuevo enlace de
nodo apunta al anterior primer nodo*/
*sPtr = newPtr;
/* Asignale newPtr a *sPtr, *sPtr apunta al nuevo nodo */
}
else
/* Si previous no es NULL, el nuevo
____________________________________________________________________________________________________
ESTRUCTURA DE DATOS
ING. OSORNIO
71
LISTAS ENLAZADAS
UNIDAD IV
____________________________________________________________________________________________________
nodo se inserta en su lugar de la lista */
{
previousPtr->nextPtr = newPtr;
/* Asignale newPtr a previousPtr->nextPtr,
al
newPtr->nextPtr =currentPtr;
nodo anterior apunta al nuevo nodo */
/* Asignale currentPtr a NewPtr *nextPtr el
enlace del nuevo nodo apunta al nodo actual */
}
}
else
printf("%c no insertada memoria no disponible.\n\n", value);
}
/* Fin de if(newPtr !=NULL) */
/* memoria insuficiente */
/* Fin de la funcion de insertar */
/*Función para borrar un elemento (nodo) de la lista */
/* Funcion de borrar un nodo con carácter y enlace */
char deleted (LISTNODEPTR *sPtr, char value)
/* El char es porque regresa un caracter, recibe
los argumentos (dirección del apuntador al
principio de la lista) starPtr la asignara a *sPtry y
el item (carácter a borrarse) a value */
{
LISTNODEPTR previousPtr, currentPtr, tempPtr; /*Declaracion de las variables de estructura */
if (value == (*sPtr)->data)
/* Si el carácter a borrarse coincide con el primer carácter
del primer nodo de la lista (*sPtr)->data ejecuta lo
siguiente */
{
tempPtr = *sPtr;
*sPtr = (*sPtr)->nextPtr;
free(tempPtr);
return value;
}
else
{
previousPtr = *sPtr;
currentPtr = (*sPtr)->nextPtr;
/* Asigne *sPtr a tempPtr (trmpPtr sera utilizado
para liberar, usando free, la memoria no necesaria) */
/* Asigna (*sPtr)->nextPtr a *sPtr (*sPtr ahora
apunta al segundo nodo de la lista) */
/* free libera la memoria apuntada por tempPtr */
/* Regresa el caracter que fue borrado */
/* sie carcater a borrarse no coindice con el 1er, caracter */
/* Inicializa previousPtr con *sPtr */
/* Inicializa current->nextPtr con (*sPtr)->nextPtr */
while(currentPtr !=NULL && currentPtr->data != value) /* En tanto currentPtr no sea
NULL y el valor a borrarse nos
sea igual a currentPtr->data */
{
previousPtr = currentPtr;
/* Asigna currentPtr a previousPtr */
currentPtr = currentPtr->nextPtr;
/* Asigna currentPtr->nextPtr a currrentPtr, esto
localizara el caracter a borrarse, si esta contenido
dentro de la lista */
}
if(currentPtr != NULL)
{
/* Si currentePtr no sea NULL */
____________________________________________________________________________________________________
ESTRUCTURA DE DATOS
ING. OSORNIO
72
LISTAS ENLAZADAS
UNIDAD IV
____________________________________________________________________________________________________
tempPtr = currentPtr;
/* Asigna currentPtr a tempPtr */
previousPtr->nextPtr = currentPtr->nextPtr;
/*Asigna currentPtr->nextPtr a
previousPtr->nextPtr */
free(tempPtr);
/* Libera el nodo al cual apunta tempPtr */
return value;
/* Regresa el caracter que fue borrado de
la lista,
}
}
return '\0';
/*Si currentPtr es NULL, regresa el caracter NULL (‘\0’), para significar
que el carácter a borrarse no fue encontrado dentro de la lista */
}
/* función que determina si la lista contiene o no elementos es decir indica con un valor que
devuelve un 1 si la lista esta vacia */
int isEmpty(LISTNODEPTR sPtr)
/* Funcion isEmpty (lista vacia) regresa un entero
y recibe de argumento starPtr y lo asigna a sPtr */
{
return sPtr == NULL;
/* Regresa un cero si la pila no esta vacia*/
}
/* Funcion de imprimir */
void printList(LISTNODEPTR currentPtr)
/* La funcion imprimir lista recibe un apuntador
al inicio de la lista como un argumento y se refiere al
apuntador como currentPtr */
{
if (currentPtr == NULL)
printf(" La lista esta vacia \n\n");
else
{
printf(" La lista es: \n") ;
/* La funcion primero determina si la lista esta
vacia, si es
asi es printList imprime “ La lista esta vacia” */
/* De lo contrario imprime los datos de la lista*/
/* Imprime “La lista es: “ */
while(currentPtr != NULL)
/* Mientras currentPtr sea diferente a NULL */
{
printf("%c -->",currentPtr->data); /*current->data sera impreso por la funcion */
currentPtr = currentPtr->nextPtr; /* currentPtr->nextPtr sera asignado a
currentPtr */
}
printf("NULL\n\n");
/* Si currentPtr es NULL imprime NULL*/
}
}
____________________________________________________________________________________________________
ESTRUCTURA DE DATOS
ING. OSORNIO
73
Descargar