TEMA+3.+Listas+Enlazadas



La lista enlazada es un TDA que nos permite almacenar datos de una forma organizada, al igual que los vectores pero, a diferencia de estos, esta estructura es dinámica, por lo que no tenemos que saber "a priori" los elementos que puede contener. En una lista enlazada, cada elemento apunta al siguiente excepto el último que no tiene sucesor y el valor del enlace es null. Por ello los elementos son registros que contienen el dato a almacenar y un enlace al siguiente elemento. Los elementos de una lista, suelen recibir también el nombre de nodos de la lista. code format="programlisting" struct lista { gint dato; lista *siguiente; }; code **Figura 1. Esquema de un nodo y una lista enlazada.** Para que esta estructura sea un TDA lista enlazada, debe tener unos operadores asociados que permitan la manipulación de los datos que contiene. Los operadores básicos de una lista enlazada son: Después de esta breve introducción, que sólo pretende servir como recordatorio, pasaremos a ver cómo es la estructura GSList que, junto con el conjunto de funciones que la acompañan, forman el TDA lista enlazada en GLib ™.
 * [[image:http://www.calcifer.org/documentos/librognome/images/callouts/1.png caption="1"]] || Representa el dato a almacenar. Puede ser de cualquier tipo; en este ejemplo se trata de una lista de enteros. ||
 * [[image:http://www.calcifer.org/documentos/librognome/images/callouts/2.png caption="2"]] || Es un puntero al siguiente elemento de la lista; con este puntero enlazamos con el sucesor, de forma que podamos construir la lista. ||
 * Insertar: inserta un nodo con dato x en la lista, pudiendo realizarse esta inserción al principio o final de la lista o bien en orden.
 * Eliminar: elimina un nodo de la lista, puede ser según la posición o por el dato.
 * Buscar: busca un elemento en la lista.
 * Localizar: obtiene la posición del nodo en la lista.
 * Vaciar: borra todos los elementos de la lista

GSList
La definición de la estructura GSList o, lo que es lo mismo, un nodo de la lista, está definido de la siguiente manera: code format="programlisting" struct GSList { gpointer data; GSList *next; }; code Las macros de conversión disponibles son las siguientes: Más adelante, en esta misma sección, se verán ejemplos del uso de estas macros. Las funciones que acompañan a la estructura GSList y que implementan los operadores básicos de las listas enlazadas, son las siguientes: **Tabla 6. Operadores de inserción en listas enlazadas.** Las funciones de inserción al principio de la lista,, y al final, , son sencillas de usar. Sólo hay que pasarles como parámetros la lista donde queremos añadir el dato así como el dato a insertar y la función devuelve una lista con el nuevo dato insertado. La función inserta el dato en la posición indicada. Su uso también es sencillo como puede verse en el siguiente ejemplo. **Ejemplo 14. Insertar un nuevo dato en una posición determinada.** code format="programlisting" /* obtiene el numero de nodos de la lista */ length = g_slist_length (list);
 * [[image:http://www.calcifer.org/documentos/librognome/images/callouts/1.png caption="1"]] || Representa el dato a almacenar. Se utiliza un puntero genérico por lo que puede almacenar un puntero a cualquier tipo de dato o bien almacenar un entero utilizando las macros de conversión de tipos. ||
 * [[image:http://www.calcifer.org/documentos/librognome/images/callouts/2.png caption="2"]] || Se trata de un puntero al siguiente elemento de la lista. ||
 * ~ Operador ||~ Funciones asociadas a GSList . ||
 * Insertar al principio. || GSList* g_slist_prepend (GSList *list, gpointer data) ||
 * Insertar al final. || GSList* g_slist_append (GSList *list, gpointer data) ||
 * Insertar en la posición indicada. || GSList* g_slist_insert (GSList *list, gpointer data, gint position) ||
 * Insertar en orden. || GSList* g_slist_insert_sorted (GSList *list, gpointer data, GCompareFunc func) ||

g_print ("\nEscribe el nº de indice donde se insertara el dato (el indice maximo es %d): ", length); scanf ("%d", &index);

/* inserta el valor en la posicion indicada */

if (index < length) { list = g_slist_insert (list, GINT_TO_POINTER (value), index); print_list (list); } code

En este ejemplo se utiliza la función para obtener el número de nodos que contiene la lista. A esta función hay que pasarle como parámetro la lista de la que se desea obtener el número de nodos y devuelve como resultado el número de nodos de ésta. guint * **g_slist_length** ( list );

GSList * list ; La función inserta los elementos a la lista de forma ordenada. Esta función utiliza el parámetro para insertar el dato en la posición correcta. es una función que se utiliza para comparar dos valores y saber así cual de ellos hay que insertar primero. En los dos ejemplos que hay a continuación, se puede observar una función de tipo y su uso para insertar datos en una lista en orden creciente. **Ejemplo 15. Parámetro para insertar en orden creciente.** code format="programlisting" gint compare_value1 (gconstpointer a, gconstpointer b) { gint *value1 = (gint *) a; gint *value2 = (gint *) b;

return value1 > value2; } code **Ejemplo 16. Insertar elementos en orden creciente.** code format="programlisting" gint values[] = {8, 14, 5, 12, 1, 27, 3, 13}; gint i; /* insertando valores en orden creciente */ for (i = 0; i < 8; i++) { list = g_slist_insert_sorted (list, GINT_TO_POINTER (values[i]),                                   compare_value1); } code **Tabla 7. Operadores de eliminación en listas enlazadas.** Las dos funciones expuestas para la eliminación de nodos, si bien tienen una definición prácticamente idéntica, el resultado obtenido es distinto. En el caso de, se eliminará el nodo que contenga el valor ////. Si hay varios nodos con el mismo valor, sólo se eliminará el primero. Si ningún nodo contiene ese valor, no se realiza ningún cambio en el GSList. En el caso de, se eliminan todos los nodos de la lista que contengan el valor //// y nos devuelve la nueva lista resultante de la eliminación de los nodos. **Ejemplo 17. Elimina un elemento de la lista.** code format="programlisting" if (list2 != NULL) { g_print ("\nEl dato %d sera eliminado de la lista.\n", list2->data);
 * ~ Operador ||~ Funciones asociadas a GSList . ||
 * Eliminar un nodo. || GSList* g_slist_remove (GSList *list, gconstpointer data) ||
 * Eliminar nodos según un patrón. || GSList* g_slist_remove_all (GSList *list, gconstpointer data) ||

/* eliminando un elemento de la lista */ g_slist_remove (list, list2->data); } code **Tabla 8. Operadores de búsqueda en listas enlazadas.** Todas estas funciones, a excepción de, devuelven un nodo de la lista o NULL si el elemento no existe. La función devuelve el valor del elemento según la posición que se le pasa como argumento en el parámetro //// o NULL si la posición que se le pasa está más allá del final de la lista. La función, es una macro que nos devuelve el siguiente nodo. Esta macro la podemos utilizar para recorrer la lista. **Ejemplo 18. Función que imprime una lista.** code format="programlisting" void print_list (GSList *list) {
 * ~ Operador ||~ Funciones asociadas a GSList. ||
 * Buscar un nodo según un valor. || GSList* g_slist_find (GSList *list, gconstpointer data) ||
 * Buscar un nodo según un criterio. || GSList* g_slist_find_custom (GSList *list, gconstpointer data, GCompareFunc func) ||
 * Localizar el índice de un nodo. || GSList* g_slist_index (GSList *list, gconstpointer data) ||
 * Localizar la posición de un nodo. || GSList* g_slist_position (GSList *list, GSList *llink) ||
 * Obtener el último nodo. || GSList* g_slist_last (GSList *list) ||
 * Obtener el siguiente nodo. || g_slist_next (slist) ||
 * Obtener un nodo por su posición. || GSList* g_slist_nth (GSList *list, guint n) ||
 * Obtener el dato de un nodo según su posición. || gpointer g_slist_nth_data (GSList *list, guint n) ||

gint i = 0;

while (list != NULL) { g_print ("Node %d content: %d.\n", i, list->data);

/* apunta al siguiente nodo de la lista */ list = g_slist_next (list); i++; } } code **Tabla 9. Operador para vaciar la lista.** La función libera la memoria de la lista que se le pasa como parámetro. Con estas funciones, quedan definidos los operadores básicos del TDA lista enlazada. GSList trae otras funciones además de los operadores básicos. Para más información sobre estas, está disponible el manual de referencia de GLib ™. 
 * ~ Operador ||~ Funciones asociadas a GSList . ||
 * Vacía la lista y libera la memoria usada. || void g_slist_free (GSList *list) ||

Introducción.
El TDA lista doblemente enlazada, al igual que la lista enlazada, es un TDA dinámico lineal pero, a diferencia de este, cada nodo de la lista doblemente enlazada contiene dos punteros, de forma que uno apunta al siguiente nodo y el otro al predecesor. Esta característica, permite que se pueda recorrer la lista en ambos sentidos, cosa que no es posible en las listas simples. La declaración del tipo lista doblemente enlazada de enteros es la siguiente: code format="programlisting" struct lista_doble { gint dato; lista_doble *siguiente; lista_doble *anterior; }; code Sobre este TDA se definen los mismos operadores básicos que en las listas simples.
 * [[image:http://www.calcifer.org/documentos/librognome/images/callouts/1.png caption="1"]] || Representa el dato a almacenar, que puede ser de cualquier tipo. En este ejemplo se trataría de una lista de enteros. ||
 * [[image:http://www.calcifer.org/documentos/librognome/images/callouts/2.png caption="2"]] || Se trata de un puntero al siguiente elemento de la lista. Con este puntero se enlaza con el sucesor, de forma que podamos construir la lista. ||
 * [[image:http://www.calcifer.org/documentos/librognome/images/callouts/3.png caption="3"]] || Es un puntero al elemento anterior de la lista. Este puntero enlaza con el elemento predecesor de la lista y permite recorrerla en sentido inverso. ||

GList
La definición de la estructura GList, que es un nodo de la lista doblemente enlazada, está definido de la siguiente manera: code format="programlisting" struct GList {       gpointer data; GList *next; GList *prev; }; code Las funciones que acompañan a la estructura GList, que implementan los operadores básicos de las listas enlazadas, son las siguientes: **Tabla 10. Operadores de inserción en listas doblemente enlazadas.** Como puede observarse en la definición de las funciones, su uso es el mismo que en las listas simples, al igual que las macros de conversión, por lo que todo lo explicado en esa sección es válido en el caso de las listas doblemente enlazadas. **Ejemplo 19. Insertar un nuevo dato en una posición determinada.** code format="programlisting" /* obtiene el numero de nodos de la lista */ length = g_list_length (list);
 * [[image:http://www.calcifer.org/documentos/librognome/images/callouts/1.png caption="1"]] || Representa el dato que se va a almacenar. Se utiliza un puntero genérico por lo que puede almacenar un puntero a cualquier tipo de dato o bien almacenar un entero utilizando las macros de conversión de tipos. ||
 * [[image:http://www.calcifer.org/documentos/librognome/images/callouts/2.png caption="2"]] || Se trata de un puntero al siguiente elemento de la lista. ||
 * [[image:http://www.calcifer.org/documentos/librognome/images/callouts/3.png caption="3"]] || Se trata de un puntero al elemento anterior de la lista. ||
 * ~ Operador ||~ Funciones asociadas a GList ||
 * Insertar al principio. || GList* g_list_prepend (GList *list, gpointer data) ||
 * Insertar al final. || GList* g_list_append (GList *list, gpointer data) ||
 * Insertar en la posición indicada. || GList* g_list_insert (GList *list, gpointer data, gint position) ||
 * Insertar en orden. || GList* g_list_insert_sorted (GList *list, gpointer data, GCompareFunc func) ||

g_print ("\nEscribe el numero de indice donde se insertara el dato (el indice maximo es %d): ", length); scanf ("%d", &index);

/* inserta el valor en la posicion indicada */

if (index < length) { list = g_list_insert (list, GINT_TO_POINTER (value), index); print_list (list); } code **Ejemplo 20. Insertar elementos en orden creciente.** code format="programlisting" gint values[] = {8, 14, 5, 12, 1, 27, 3, 13}; gint i;

for (i = 0; i < 8; i++) { list = g_list_insert_sorted (list, GINT_TO_POINTER (values[i]),                                   compare_value1); } code **Tabla 11. Operadores de eliminación en listas doblemente enlazadas.** **Ejemplo 21. Eliminar un elemento de la lista.** code format="programlisting" if (list2 != NULL) { g_print ("\nEl dato %d sera eliminado de la lista.\n", list2->data);
 * ~ Operador ||~ Funciones asociadas a GList ||
 * Eliminar un nodo. || GList* g_list_remove (GList *list, gconstpointer data) ||
 * Eliminar nodos según un patrón. || GList* g_list_remove_all (GList *list, gconstpointer data) ||

/* eliminando un elemento de la lista */ g_list_remove (list, list2->data); print_list (list); } code **Tabla 12. Operadores de búsqueda en listas doblemente enlazadas.** **Ejemplo 22. Busca un valor dado en la lista.** code format="programlisting" g_print ("\nEntra un valor entero a buscar: "); scanf ("%d", &value); g_print ("\n");
 * ~ Operador ||~ Funciones asociadas a GList . ||
 * Buscar un nodo según un valor. || GList* g_list_find (GList *list, gconstpointer data) ||
 * Buscar un nodo según un criterio. || GList* g_list_find_custom (GList *list, gconstpointer data, GCompareFunc func) ||
 * Localizar el índice de un nodo. || GList* g_list_index (GList *list, gconstpointer data) ||
 * Localizar la posición de un nodo. || GList* g_list_position (GList *list, GSList *llink) ||
 * Obtener el último nodo. || GList* g_list_last (GList *list) ||
 * Obtener el siguiente nodo. || g_list_next (list) ||
 * Obtener un nodo por su posición. || GList* g_list_nth (GList *list, guint n) ||
 * Obtener el dato de un nodo según su posición. || gpointer g_list_nth_data (GList *list, guint n) ||

/* buscando un elemento en la lista */ list2 = g_list_find (list, GINT_TO_POINTER (value));

if (list2 != NULL) { index = g_list_index (list, list2->data); g_print ("\nEl valor %d esta en el nodo %d.\n", list2->data, index); code **Tabla 13. Operador para vaciar la lista** Con estas funciones, quedan definidos los operadores básicos del TDA lista enlazada. Al igual que GSList, GList trae otras funciones además de los operadores básicos. Para más información sobre estas, está disponible el manual de referencia de GLib. 
 * ~ Operador ||~ Funciones asociadas a GList ||
 * Vacía la lista y libera la memoria usada. || void g_list_free (GList *list) ||

GQueue : pilas y colas.
Otra de las novedades que incorpora esta versión de GLib ™ es la estructura GQueue que, junto con las funciones que la acompañan, nos proporciona la posibilidad de implementar los TDA cola y pila estándar. GQueue utiliza estructuras GList para almacenar los elementos. La declaración de la estructura de datos es la siguiente. code format="programlisting" struct GQueue { GList *head; GList *tail; guint length; }; code
 * [[image:http://www.calcifer.org/documentos/librognome/images/callouts/1.png caption="1"]] || Es un puntero al primer elemento de la cola. ||
 * [[image:http://www.calcifer.org/documentos/librognome/images/callouts/2.png caption="2"]] || Es un puntero al último elemento de la cola. ||
 * [[image:http://www.calcifer.org/documentos/librognome/images/callouts/3.png caption="3"]] || Esta variable almacena el número de elementos de la cola. ||

Aunque para referirnos al TDA GQueue utilizamos el término cola, con esta misma estructura también tenemos la posibilidad de implementar el TDA pila, gracias a las funciones que lo acompañan.

MATERIAL ADICIONAL
Listas Enlazadas