Está en la página 1de 19

Listas ligadas

En las secciones anteriores se contemplaron diferentes estructuras estticas en dnde la manipulacin de datos es a travs de posiciones localizadas secuencialmente. Para de clarar estas estructuras se deba definir un tamao determinado el cual no poda modificarse posteriormente. Esto puede ser un problema en el caso de que:

no sepamos de antemano el tamao requerido para nuestra aplicacin hay una gran cantidad de operaciones y manipulaciones de los datos dentro de las estructuras

En estos casos es generalmente m&a acute;s conveniente utilizar estructuras dinmicas, es decir, las cuales pueden aumentar o disminuir de tamao de acuerdo a los requerimientos especficos del procedimiento. As se resuelve el problema de no saber el tama&ntild e;o exacto desde un principio y las manipulaciones de datos se pueden hacer de una manera mas rpida y eficiente. Una lista ligada es entonces un grupo de datos organizados secuencialmente, pero a diferencia de los arreglos, la organizacin no esta dada implcitamente por su posicin en el arreglo. En una lista ligada cada elemento es un nodo que contiene el dato y adems una liga al siguiente dato. Estas ligas son simplemente variables que contienen la(s) direccin(es) de los datos contiguos o relacionados. Para manejar una lista es necesario contar con un apuntador al primer elemento de la lista "head" . Las ventajas de las listas ligadas son que:

Permiten que sus tamaos cambien durante la ejecucin del programa Proveen una major flexibilidad en el manejo de los datos.

Este principio de listas ligadas se puede aplicar a cualquiera de los conceptos de estructura de datos vistos anteriormente: arreglos, colas y pilas . Es decir, las operaciones de altas, bajas y cambios, as como bsquedas y ordenamientos se tendrn que adaptar en la cuestin del manejo de localidades nicamente.

Listas ligadas sencillas

Una lista ligada sencilla es un grupo de datos en dnde cada dato contiene adems un apuntador hacia el siguiente dato en la lista, es decir, una liga hacia el siguiente dato.

Los siguientes algoritmos fueron tomados de "Estructuras de Datos", Cair Guardati, 2a. Ed., McGraw Hill, 2002.
Algoritmo 5.1 CREAINICIO(P) {Este algoritmo crea una lista, agregando cada nuevo nodo al inicio de la misma} { P y Q son variables de tipo puntero. P apuntar al inicio de la lista} 1. 2. 3. 4. CREA (P) {Crea el primer nodo de la lista} Leer P->INFORMACIN Hacer P->LIGA=NIL Repetir CREA (Q) Leer Q->INFORMACIN Hacer Q->LIGA= P y P = Q Hasta (que ya no haya informacin)

5.

Algoritmo 5.2 CREAFINAL(P) {Este algoritmo crea una lista, agregando cada nuevo nodo al final de la misma} {P y Q son variables de tipo puntero. P apuntar al inicio de la lista} 1. 2. 3. 4. CREA (P) {Crea el primer nodo de la lista} Leer P->INFORMACIN Hacer P->LIGA=NIL y T=P Repetir CREA (Q) Leer Q->INFORMACIN Hacer Q->LIGA=NIL, T->LIGA=Q y T=Q Hasta (que ya no haya informacin)

5.

Para poder dar de alta un dato en una lista ligada sencilla es necesario recorrer la lista nodo por nodo hasta encontrar la posicin adecuada. Se crea un nuevo nodo, se inserta el dato y se actualizan las ligas del nodo nuevo y del anterior para intercalar el nuevo nodo en la lista.

Algoritmo 5.3 RECORREITERATIVO(P) {Este algoritmo recorre una lista cuyo primer nodo est apuntado por P} {Q es una variable de tipo puntero} 1. 2. 3. Hacer Q = P Repetir mientras Q =! NIL Escribir Q->INFORMACUN Hacer Q=Q->LIGA {Apunta al siguiente nodo de la lista} {Fin del ciclo del paso 2}

Algoritmo 5.4 RECORRECURSIVO(P) {Este algoritmo recorre una lista recursivamente. nodo a visitar} 1. P es el apuntador al

Si P =! NIL entonces Escribir P->INFORMACIN Llamar a RECORRECURSIVO con P->LIGA {Llamada recursiva con el apuntador al siguiente nodo de {Fin del condicional del paso 1}

la lista} 2.

Algoritmo 5.6 INSERTAFINAL(P) {Este algoritmo inserta un nodo al final de la lista. P es el apuntador al primer nodo de la lista, y DATO es la informacin que se almacenar en el nuevo nodo} {Q y T son variables de tipo puntero} 1. 2. 3. 4. 5. Hacer T= P Repetir mientras T ->Liga =! NIL {Recorre la lista hasta llegar al ltimo elemento} Hacer T=T->LIGA {Fin del ciclo del paso 2} CREA (Q) Hacer Q->INFORMACIN =DATO, Q->LIGA =NIL y T ->LIGA =Q

Algoritmo 5.7 INSERTANTES ( P, DATO, REF ) {Este algoritmo inserta un nodo dado como referencia, REF. P es el apuntador al primer nodo de la lista, y DATO es la informacin que se almacenar en el nuevo nodo} {Q, X y T son variables de tipo puntero, BAND es una variable de tipo booleano} 1. 2. VERDADERO) Hacer Q= P y BAND= VERDADERO Repetir mientras (Q->INFORMACIN =! REF) y (BAND = 2.1 Si Q -> LIGA =! NIL Entonces Hacer T= Q y Q= Q-> LIGA Si no Hacer BAND = FALSO 2.2 {Fin del condicional del paso 2.1} {Fin del ciclo del paso 2} Si BAND = VERDADERO entonces CREA(X) Hacer X->INFORMACIN = DATO 4.1 Si P = Q {Es el primer nodo} Entonces Hacer X ->LIGA = P y P = X Si no Hacer T ->LIGA =X y X ->LIGA = Q 4.2 {Fin del condicional del paso 4.1} {Fin del condicional del paso 4}

3. 4.

5.

Algoritmo 5.9 ELIMINAPRIMERO(P) {Este algoritmo borra el primer elemento de una lista. al primer nodo de la lista} {Q es una variable de tipo puntero} 1. 2. nodo} Entonces Hacer P= Q-> LIGA {Redefine el puntero al inicio} Si no Hacer P = NIL {Fin del condicional del paso2} QUITA(Q) P es el apuntador

Hacer Q = P Si Q -> LIGA =! NIL {Verifica si la lista tiene slo un

3. 4.

Algoritmo 5.10 ELIMINALTIMO(P)

{Este algoritmo borra el ltimo elemento de una lista. al primer nodo de la lista} {Q y T son variables de tipo puntero} 1. elemento}

P es el apuntador

Si P -> LIGA = NIL {Verifica si la lista tiene slo un Entonces QUITA(P) Hacer P = NIL Si no Hacer Q = P 1.1 Repetir mientras ( Q->LIGA =! NIL) Hacer T=Q y Q = Q -> LIGA 1.2 {Fin del ciclo del paso 1.1} Hacer T -> LIGA = NIL QUITA(Q) {Fin del condicional del paso 1}

2.

Algoritmo 5.11 ELIMINAX( P, X ) {Este algoritmo elimina un nodo con informacin X de una lista. P es el apuntador al primer nodo de la lista} {Q y T son variables de tipo puntero. BAND es una variable de tipo booleano} 1. 2. VERDADERO) Hacer Q = P y BAND= VERDADERO Repetir mientras (Q->INFORMACIN =! X) y 2.1 (BAND =

3. 4.

Si Q ->LIGA =! NIL Entonces Hacer T = Q y Q = Q -> LIGA Si no Hacer BAND = FALSO 2.2 {Fin del condicional del paso 2.1} {Fin del ciclo del paso 2} Si BAND = FALSO Entonces Escribir El elemento no fue encontrado Si no 4.1 SI P = Q {Verifica si el elemento a eliminar es Entonces Hacer P = Q->LIGA Si no Hacer T -> LIGA=Q-> LIGA 4.2 {Fin del condicional del paso 4.1} QUITA(Q) {Fin del condicional del paso 4}

el primero}

5.

Algoritmo 5.15 BUSCARRECURSIVO(P,X) {Este algoritmo busca recursivamente al elemento con informacin X en una lista que se encuentra desordenada. P es el apuntador del nodo a visitar} 1. Si ( P =! NIL) Entonces 1.1 Si ( P ->INFORMACIN = X ) Entonces Escribir El elemento se encuentra en la Si no 1.2 lista 2. {Fin del condicional del paso 1} Llamar a BUSCARRECURSIVO con P -> LIGA y X {Fin del condicional del paso 1.1} Si no Escribir El elemento no se encuentra en la

lista

Listas ligadas circulares


Una lista ligada circular es una lista en la cual el ltimo nodo es ligado al primer elemento de la lista. La ventaja de este tipo de estructura es que siempre se puede llegar a cualquier nodo siguiendo las ligas. La desventaja e s que si no se tiene cuidado una bsqueda puede resultar en un ciclo infinito. Esto se puede evitar al determinar a un nodo como nodo-cabeza o nodo inicial.

Listas ligadas dobles


Hasta ahora se han manejado listas que se recorren en una sla direccin. En alguna aplicaciones es prctico o hasta indispensable poder recorrer una lista en ambas direcciones. Para estos casos se tienen las listas doblemente ligadas. Esta propiedad implica que que cada nodo debe tener dos apuntadores, uno al nodo predecesor y otro al nodo sucesor.

Funciones bsicas para listas simplemente ligadas en C


agosto 9, 2011
En este post voy a poner un archivo de cabecera que hice para poder crear programas que utilicen listas simplemente ligadas, contiene las funciones bsicas y est diseado para manejar enteros, pero es muy fcil hacer la implementacin de un archivo de cabecera que acepte otro tipo de datos (char, etc.). La estructura bsica es la siguiente

1 typedef struct nodo_s 2{ 3 int dato; 4 struct nodo_s *siguiente; 5 } nodo_t;

Implement una funcin para crear un nodo con el valor que contendr el campo llamado dato, una funcin para insertar un nodo, para eliminar un nodo, para saber si la lista est vaca y una funcin que muestra todos los nodos de la lista.

001 // Archivo listasimple_int.h 002 003 #include <stdio.h> 004 #include <stdlib.h> 005 006 typedef struct nodo_s 007 { 008 int dato; 009 struct nodo_s *siguiente;

010 } nodo_t; 011 012 typedef nodo_t *ptrNodo; 013 typedef nodo_t *ptrLista; 014 015 /* 016 Crea un nuevo nodo y en el campo dato almacena el valor que recibe como parmetro

017 regresa el nodo recien creado 018 */ 019 ptrNodo crea_nodo(int valor) 020 { 021 ptrNodo nuevo_nodo = (ptrNodo)malloc(sizeof(nodo_t)); 022 if (nuevo_nodo != NULL) 023 024 025 026 027 028 return nuevo_nodo; 029 } 030 031 /* } { nuevo_nodo->dato = valor; nuevo_nodo->siguiente = NULL;

032

Agrega a la lista que recibe como parmetro, un nodo enseguida del nodo que recibe como parmetro Si el nodo que recibe como parmetro es NULL, significa que se desea insertar el nodo al inicio de la lista

033

034 */ 035 void inserta_despues(ptrLista *lista, ptrNodo nodo, int valor) 036 { 037 ptrNodo nuevo_nodo = crea_nodo(valor); 038 039 if (nodo != NULL) 040 041 042 043 044 045 */ nuevo_nodo->siguiente = nodo->siguiente; /* El apuntador "siguiente" del nodo que recibe como parmetro va a apuntar al nodo recien creado con esto, el nodo recien creado se ha insertado adelante del nodo que se recibe como parmetro */ nodo->siguiente = nuevo_nodo; } { /* El apuntador nuevo_nodo->siguiente va a apuntar a la misma direccin a donde apunta el apuntador "siguiente" del nodo que recibe como parmetro

046 047 048 049

050 else 051 052 { // Si la lista no est vaca, hace que el apuntador "siguiente" del nuevo nodo apunte al primer elemento de la lista

053 054 055 056 057 058 } 059 060 /* 061 }

if (*lista != NULL) nuevo_nodo->siguiente = *lista; // Hace que la lista apunte hacia el nuevo nodo para que sea el primer nodo de la lista *lista = nuevo_nodo;

Elimina el nodo que se encuentra enseguida del nodo que recibe como parmetro Si el nodo que recibe como parmetro es NULL, y la lista no est vaca, significa que se desea borrar el primer nodo de la lista

062 063

064 */ 065 int elimina_despues(ptrLista *lista, ptrNodo nodo) 066 { 067 int x=0; 068 ptrNodo borrar_nodo = NULL; 069 070 if (nodo != NULL) 071 072 073 074 { if (nodo->siguiente != NULL) { /* El apuntador borrar_nodo va a apuntar a la misma direccin

a donde apunta 075 076 077 078 079 080 081 082 083 } } */ nodo->siguiente = borrar_nodo->siguiente; el apuntador "siguiente" del nodo que recibe como parmetro */ borrar_nodo = nodo->siguiente; /* El apuntador "siguiente" del nodo que recibe como parmetro va a apuntar al nodo que est a continuacin del que se va a borrar

084 else 085 086 { // Si la lista no est vacia, significa que quiere borrar el primer nodo de la lista if (*lista != NULL) { borrar_nodo = *lista; *lista = borrar_nodo->siguiente; } }

087 088 089 090 091 092 093 094 095

/* Si el apuntador "siguiente" del nodo que recibe como parmetro apunta a NULL, significa que el apuntador que se recibi como parmetro es el ltimo de la lista, por lo

tanto, no hay nodo siguiente 096 Otro caso por el cual borrar_nodo puede ser null, es que la lista est vaca, y tambin es imposible hacer la eliminacin de un nodo

097 */ 098 if (borrar_nodo != NULL) 099 100 101 102 } { x=borrar_nodo->dato; free(borrar_nodo);

103 else 104 105 106 return x; 107 } 108 109 /* 110 111 112 */ 113 int lista_vacia(ptrLista *lista) 114 { 115 return (*lista == NULL ? 1:0); 116 } Regresa 1 si no hay nodos en la lista ligada y cero en caso contrario *lista es el apuntador que apunta a la lista ligada printf("Borrado prohibido\n");

117 118 /* 119 120 */ 121 void nodos_lista(ptrNodo nodo) 122 { 123 if (nodo == NULL) 124 125 else 126 127 128 129 130 131 132 133 134 135 136 } } } printf("\n"); { while (nodo != NULL) { printf("%d",nodo->dato); nodo = nodo->siguiente; if (nodo != NULL) printf(" -> "); printf("La lista est vacia\n"); Muestra los datos de los nodos

A continuacin muestro un programa muy sencillo para que sirva de ejemplo de cmo utilizar este archivo de cabecera, el programa pide al usuario que vaya insertando nmeros enteros y los va insertando en orden en una lista simplemente ligada; cuando el usuario no quiera introducir ms nmeros, debe introducir el nmero cero. Despus, el programa da opcin a borrar un nmero de la lista.

ver fuente imprimir?

01 // 02 // 03 // 04 // 05

ordena_listasimple.c

Hecho por Salomn Rincn Torres <rtmex@yahoo.com>

06 #include <stdio.h> 07 #include "listasimple_int.h" 08 09 int main() 10 { 11 int numero=0, insertado=0, encontrado=0; 12 ptrLista lista = NULL; 13 ptrNodo nodo = NULL; 14 15 do 16 17 18 { insertado = 0; printf("Este programa recibe nmeros y los va insertando en orden ascendente en una lista simplemente ligada\n"); printf("Vaya introduciendo los nmeros (introduzca cero para salir del programa)\n"); scanf("%d", &numero);

19 20

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 else { inserta_despues(&lista, nodo, numero); else while (nodo != NULL && insertado == 0) { if (numero > nodo->dato) { if (nodo->siguiente != NULL) { if (numero > nodo->siguiente->dato) nodo = nodo->siguiente; else { nodo = lista; if (numero <= nodo->dato) // Inserta el nmero al inicio de la lista inserta_despues(&lista, NULL, numero); if (numero!=0) { if (lista_vacia(&lista) == 1) inserta_despues(&lista, NULL, numero);

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 } } } /* if */ } /* while */ } /* else */ }

insertado = 1;

} /* if */ else { inserta_despues(&lista, nodo, numero); insertado = 1;

printf("\n\nLos elementos en la lista son los siguientes;\n\n"); // Muestra los elementos que estn en la lista nodos_lista(lista); } /* if */

60 while (numero!=0); 61 62 printf("\n\nLa lista qued con los siguientes elementos:\n\n"); 63 // Muestra los elementos que estn en la lista 64 nodos_lista(lista); 65 66 if (lista_vacia(&lista) != 1)

67 68 69 70 71 72

{ printf("\nDato a borrar\n"); scanf("%d", &numero);

nodo = lista; if (nodo != NULL) // Verifica si el nmero que se desea borrar es el primero de la lista if (nodo->dato == numero) elimina_despues(&lista, NULL); else { while (nodo != NULL && encontrado == 0) { if (nodo->siguiente != NULL) { if (nodo->siguiente->dato==numero) encontrado = 1; } if (encontrado == 0) nodo = nodo->siguiente; } if (encontrado == 1) elimina_despues(&lista, nodo);

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

90 91 92 93 94 95 }

printf("\n\nLa lista final qued con los siguientes elementos:\n\n"); // Muestra los elementos que estn en la lista nodos_lista(lista);

96 return 0; 97 }

También podría gustarte