Tema 3 - Listas
TAD Lista
Una lista es por definición un conjunto de cero o más elementos.
Los elementos están ordenados de forma lineal, no por su contenido, sino simplemente por la posición que ocupan relativos unos a otros.
Por lo tanto, la lista está formada por nodos
idénticos. Cada nodo está formado por dos elementos, la información del propio nodo y un puntero que apunta al siguiente. Además, el inicio de la lista está delimitado por un puntero Lista
, y finaliza con el último nodo que apunta a NULL
.
Operaciones
Siguiendo los pasos para la especificación de un TAD, definimos las operaciones del mismo clasificándolas en: constructoras, generadoras, modificadoras, observadoras y destructoras.
Generadoras
Objetivo: Crear una lista vacía y la inicializa
Salida: Una lista vacía
Poscondición: La lista sin datos// SPDX-FileCopyrightText: 2024 Eliana Reigada // // SPDX-License-Identifier: GPL-3.0-only void createEmptyList(tList *lista) { lista->indice = LNULL; }Objetivo: Si la posición es nula, añade un elemento al final de la lista. En caso contrario, el elemento quedará insertado justo antes del que actualmente ocupa la posición indicada.
Entrada:
- Item: Contenido del elemento a insertar
- Position: Posición de referencia para la inserción
- List: Lista donde vamos a insertar
Salida: List: Lista con el elemento Item insertado y verdadero si se ha podido insertar, falso en caso contrario
Precondición: Position es una posición válida de la lista o es una posición nula
Postcondición: Las posiciones de los elementos de la lista posteriores a la del elemento insertado pueden haber variado// SPDX-FileCopyrightText: 2023 Fernando Álvarez // // SPDX-License-Identifier: GPL-3.0-only bool insertItem(tItemL item, tPosL pos, tList *lista) { tPosL posAux; if (!createNode(&posAux)) { return false; } else { posAux->data = item; posAux->next = LNULL; //por si acaso } if (isEmptyList(*lista)) { *lista = posAux; } else if (pos == LNULL) { last(*lista)->next = posAux; } else if (pos == *lista) { posAux->next = pos; *lista = posAux; } else { posAux->next = pos->next; pos->next = posAux; posAux->data = pos->data; pos->data = item; } return true; }
Modificadores
Objetivo: Copia una lista en otra
Entrada: List_1: Lista que vamos a copiar
Salida: List_2: Copia de la lista original y verdadero si se ha podido copiar, falso en caso contrario
Precondición: La lista origen está inicializada// SPDX-FileCopyrightText: 2024 Eliana Reigada // // SPDX-License-Identifier: GPL-3.0-only bool copyList(tlist listaDest, tList *listaOrig) { tPosl p, q, r; bool ret = true; createEmptyList(listaOrig); if (!isEmptyList(listaDest)) { p = listaDest; while ((p != LNULL) && createNode(&r)) { r->data = p->data; r->next = LNULL; if (p == listaDest) { *listaOrig = r; q = r; } else { q->next = r; q = r; } p = p->next; } if (p != LNULL) { deleteList(listaOrig); ret = false; } } return ret; }Objetivo: Modifica el contenido de un elemento de la lista
Entrada:
- Item: Nuevo contenido a asignar al elemento en Position
- Position: Posición del elemento que queremos modificar
- List: Lista a modificar
Salida: List: Lista con el contenido del elemento modificado
Precondición: Position es una posición válida de la lista// SPDX-FileCopyrightText: 2024 Eliana Reigada // // SPDX-License-Identifier: GPL-3.0-only void updateItem(tItem item, tPosL pos, tList *lista) { pos->data = item; }
Destructoras
Objetivo: Elimina de la lista un elemento con cierta posición
Entrada: Position: Posición del elemento a eliminar List: Lista a modificar Salida: List: Lista sin el elemento correspondiente a Position
Precondición: Position es una posición válida de la lista
Postcondición: Las posiciones de los elementos de la lista posteriores a la de la posición eliminada pueden haber variado// SPDX-FileCopyrightText: 2024 Eliana Reigada // // SPDX-License-Identifier: GPL-3.0-only void deleteAtPosition(tPosL pos, tList *lista) { tPosl posAux; if (pos == *lista) *lista = (*lista)->next; else { for (posAux = *lista; posAux->next != pos; posAux = posAux->next); posAux->next = pos->next; } free(pos); }Objetivo: Elimina todos los elementos de la lista
Entrada: List: Lista a borrar
Salida: Lista vacía// SPDX-FileCopyrightText: 2024 Eliana Reigada // // SPDX-License-Identifier: GPL-3.0-only void deleteList(tList *lista) { tPosL posAux; while (*lista != LNULL) { while (posAux->next != NULL) posAux = posAux->next; free(posAux); } }
Observadoras
Objetivo: Busca el primer elemento con cierto contenido en la lista
Entrada:
- Item: Contenido del elemento buscado
- List: Lista donde realizar la búsqueda
Salida: Position: Posición del elemento encontrado o nulo si no se encuentra// SPDX-FileCopyrightText: 2024 Eliana Reigada // // SPDX-License-Identifier: GPL-3.0-only tPosL findItem(tItem item, tList lista) { tPosL posAux; for (posAux = lista; (posAux != LNULL) && (posAux->data != item); posAux = posAux->next); return posAux; }Objetivo: Determina si la lista está vacía
Entrada: List: Lista a comprobar
Salida: Verdadero si la lista está vacía, falso en caso contrario// SPDX-FileCopyrightText: 2024 Eliana Reigada // // SPDX-License-Identifier: GPL-3.0-only bool isEmptyList(tLIst lista) { return lista == LNULL; }Objetivo: Recupera el contenido de un elemento de la lista
Entrada: Position: Posición del elemento buscado
List: Lista donde realizar la búsqueda
Salida: Item: Contenido del elemento que está en Position
Precondición: Position es una posición válida en la lista// SPDX-FileCopyrightText: 2024 Eliana Reigada // // SPDX-License-Identifier: GPL-3.0-only tItem getItem(tPosL pos, tList lista) { return pos->data; }Objetivo: Devuelve la posición del primer elemento de la lista
Entrada: List: Lista a manipular
Salida: Position: Posición del primer elemento
Precondición: La lista no está vacía// SPDX-FileCopyrightText: 2024 Eliana Reigada // // SPDX-License-Identifier: GPL-3.0-only tPosL first(tList lista) { return lista; }Objetivo: Devuelve la posición del último elemento de la lista
Entrada: List: Lista a manipular
Salida: Position: Posición del último elemento
Precondición: La lista no está vacía// SPDX-FileCopyrightText: 2024 Eliana Reigada // // SPDX-License-Identifier: GPL-3.0-only tPosL last(tList lista) { tPosL posAux; for (posAux = lista; posAux->next != LNULL; posAux->next); return posAux; }Objetivo: Devuelve la posición del elemento anterior al actual
Entrada: Position: Posición del elemento actual
List: Lista a manipular
Salida: Posición del elemento anterior o nulo si es el primero
Precondición: Position es una posición válida de la lista// SPDX-FileCopyrightText: 2024 Eliana Reigada // // SPDX-License-Identifier: GPL-3.0-only tPosL previous(tPosL pos, tList L) { tPosL posAux; for (posAux = L; posAux->next != pos; posAux = posAux->next); return posAux; }Objetivo: Devuelve la posición del elemento siguiente al actual
Entrada:
- Position: Posición del elemento actual
- List: Lista a manipular
Salida: Position: Posición del elemento siguiente o nulo si es el último
Precondición: Position es una posición válida de la lista// SPDX-FileCopyrightText: 2024 Eliana Reigada // // SPDX-License-Identifier: GPL-3.0-only tPosL next(tPosL pos, tList lista) { return pos->next; }
TAD Lista ordenada
Los elementos están ordenados de forma lineal por su contenido.
En caso de ordenación alfabética:
Operación a cambiar
Las operaciones del TAD lista ordenada es idéntico al TAD anterior, la única a modificar es la operación de inserción:
Objetivo: Inserta un elemento en la lista según el criterio de ordenación sobre el campo Item
Entrada:
- Item: Contenido del elemento a insertar
- List: Lista donde vamos a insertar
Salida: List: Lista con el elemento Item insertado en la posición correspondiente según su contenido y verdadero si se ha podido insertar, falso en caso contrario
Precondición: La lista está inicializada
Postcondición: Las posiciones de los elementos de la lista posteriores a la del elemento insertado pueden haber variado// SPDX-FileCopyrightText: 2023 Fernando Álvarez // // SPDX-License-Identifier: GPL-3.0-only bool insertItem(tItemL item, tList *lista) { tPosL q,p; if (!createNode(&q)) { return false; } else { q->data = item; q->next = LNULL; //por si acaso } if (isEmptyList(*lista)) { *lista = q; } else if(item < (*lista)->data){ q->next = *lista; *lista = q; } else{ p = findPosition(*lista,item); q->next = p->next; p->next = q; } return true; }
Comparación entre TADs
Estática | Simple Enlace | Doble Enlace | |
---|---|---|---|
Necesidad de memoria | Mucha | Menos en promedio | Menos en promedio (+ que simple enlace) |
Memoria contigua | ✅ | ❌ | ❌ |
Acceso directo | ✅ | ❌ | ❌ |
Ampliable | ❌ | ✅ | ✅ |
Operaciones más costosas | insertItem, deleteAtPosition (excepto al final) | insertItem (final), deleteAtPosition (final), previous, last, deleteList, copyList | insertItem (final), last, deleteList, copyList |
Seguridad | ⚔️😡🛡️ | 😴🛡️ | 😴🛡️ |
Archivo de Cabecera TAD
Multilistas
En problemas de programación reales hacen falta soluciones complejas. Es habitual combinar múltiples TAD simples para construir un TAD complejo.
En este caso el TAD multilistas es un ejemplo de combinación de TADs, en este caso, listas.
TAD Multilistas
La multilista consiste, en crear sublistas enlazadas a los nodos de una lista principal.
A una lista de usuarios podríamos enlazar, por ejemplo, una playlist para cada uno.
TAD Multiordenadas
Esta lista multiordenada consta de dos punteros, uno apunta al primer nodo ordenada por nombre, y el otro al primer DNI.
Los están enlazados entre ellos doblemente. Marcando el nodo anterior y siguiente, en dos categorías: Nombre y **DNI **.