Documentos de Académico
Documentos de Profesional
Documentos de Cultura
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.
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
3. 4.
{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
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
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
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; } }
/* 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.
01 // 02 // 03 // 04 // 05
ordena_listasimple.c
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;
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
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 }