Lista enlazada circular: ventajas y desventajas

ยฟQuรฉ es una lista enlazada circular?

Una lista circular enlazada es una secuencia de nodos dispuestos de tal manera que cada nodo pueda volver a sรญ mismo. Aquรญ un "nodo" es un elemento autorreferencial con punteros a uno o dos nodos en su vecindad inmediata.

A continuaciรณn se muestra una representaciรณn de una lista enlazada circular con 3 nodos.

Lista enlazada circular

Aquรญ puede ver que cada nodo es rastreable hasta sรญ mismo. El ejemplo que se muestra arriba es una lista circular enlazada individualmente.

Nota: La lista circular enlazada mรกs simple es un nodo que rastrea solo hasta sรญ mismo, como se muestra.

Lista enlazada circular

Bรกsico Operaciones en listas circulares enlazadas

Las operaciones bรกsicas en una lista enlazada circular son:

  1. Inserciรณn
  2. Eliminaciรณn y
  3. Travesรญa
  • La inserciรณn es el proceso de colocar un nodo en una posiciรณn especรญfica en la lista circular enlazada.
  • La eliminaciรณn es el proceso de eliminar un nodo existente de la lista vinculada. El nodo puede identificarse por la apariciรณn de su valor o por su posiciรณn.
  • El recorrido de una lista enlazada circular es el proceso de mostrar el contenido completo de la lista enlazada y volver al nodo de origen.

En la siguiente secciรณn, comprenderรก la inserciรณn de un nodo y los tipos de inserciรณn posibles en una lista circular individualmente enlazada.

Inserciรณn Operadisrupciรณn

Inicialmente, necesitas crear un nodo que apunte a sรญ mismo como se muestra en esta imagen. Sin este nodo, la inserciรณn crea el primer nodo.

Inserciรณn Operadisrupciรณn

A continuaciรณn, existen dos posibilidades:

  • Inserciรณn en la posiciรณn actual de la lista circular enlazada. Esto corresponde a la inserciรณn al principio del final de una lista enlazada singular regular. En una lista circular enlazada, el principio y el final son iguales.
  • Inserciรณn despuรฉs de un nodo indexado. El nodo debe identificarse mediante un nรบmero de รญndice correspondiente al valor de su elemento.

Para insertar al principio/final de la lista circular enlazada, es decir, en la posiciรณn donde se agregรณ el primer nodo,

  • Tendrรกs que romper el autovรญnculo existente con el nodo existente.
  • El siguiente puntero del nuevo nodo se vincularรก al nodo existente.
  • El siguiente puntero del รบltimo nodo apuntarรก al nodo insertado.

NOTA: El puntero que es el token maestro o el principio/final del cรญrculo se puede cambiar. Aรบn asรญ regresarรก al mismo nodo en un recorrido, que se analiza mรกs adelante.

Los pasos en (a) i-iii se muestran a continuaciรณn:

Inserciรณn Operadisrupciรณn

(Nodo existente)

Inserciรณn Operadisrupciรณn

PASO 1) Romper el enlace existente

Inserciรณn Operadisrupciรณn

PASO 2) Crear un enlace directo (desde un nuevo nodo a un nodo existente)

Inserciรณn Operadisrupciรณn

PASO 3) Crear un enlace de bucle al primer nodo.

A continuaciรณn, intentarรก la inserciรณn despuรฉs de un nodo.

Por ejemplo, insertemos "VALOR2" despuรฉs del nodo con "VALOR0". Supongamos que el punto de partida es el nodo con โ€œVALOR0โ€.

  • Tendrรกs que romper la lรญnea entre el primer y segundo nodo y colocar el nodo con โ€œVALOR2โ€ en el medio.
  • El siguiente puntero del primer nodo debe vincularse a este nodo, y el siguiente puntero de este nodo debe vincularse al segundo nodo anterior.
  • El resto del acuerdo permanece sin cambios. Todos los nodos son rastreables hasta ellos mismos.

NOTA: Dado que existe una disposiciรณn cรญclica, insertar un nodo implica el mismo procedimiento para cualquier nodo. El puntero que completa un ciclo completa el ciclo como cualquier otro nodo.

Esto se muestra a continuaciรณn:

Inserciรณn Operadisrupciรณn

(Digamos que sรณlo hay dos nodos. Este es un caso trivial)

Inserciรณn Operadisrupciรณn

PASO 1) Retire el enlace interno entre los nodos conectados.

Inserciรณn Operadisrupciรณn

PASO 2) Conecte el nodo del lado izquierdo al nuevo nodo

Inserciรณn Operadisrupciรณn

PASO 3) Conecte el nuevo nodo al nodo del lado derecho.

Eliminacion Operadisrupciรณn

Supongamos una lista enlazada circular de 3 nodos. Los casos de eliminaciรณn se detallan a continuaciรณn:

  • Eliminar el elemento actual
  • Eliminaciรณn despuรฉs de un elemento.

Eliminaciรณn al principio/final:

  1. Atraviese hasta el primer nodo desde el รบltimo nodo.
  2. Para eliminar desde el final, debe haber solo un paso transversal, desde el รบltimo nodo hasta el primer nodo.
  3. Elimine el enlace entre el รบltimo nodo y el siguiente.
  4. Vincula el รบltimo nodo al siguiente elemento del primer nodo.
  5. Libera el primer nodo.

Eliminacion Operadisrupciรณn

(Configuraciรณn existente)

Eliminacion Operadisrupciรณn

PASO 1) Retire el enlace circular

Eliminacion Operadisrupciรณn

PASOS 2) Eliminar el vรญnculo entre el primero y el siguiente, vincular el รบltimo nodo al nodo siguiente al primero.

Eliminacion Operadisrupciรณn

PASO 3) Liberar/desasignar el primer nodo

Eliminaciรณn despuรฉs de un nodo:

  1. Recorra hasta que el siguiente nodo sea el nodo que se va a eliminar.
  2. Vaya al siguiente nodo y coloque un puntero en el nodo anterior.
  3. Conecte el nodo anterior al nodo posterior al nodo actual, utilizando su puntero siguiente.
  4. Libere el nodo actual (desvinculado).

Eliminacion Operadisrupciรณn

PASO 1) Digamos que necesitamos eliminar un nodo con "VALOR1".

Eliminacion Operadisrupciรณn

PASO 2) Elimine el vรญnculo entre el nodo anterior y el nodo actual. Vincula su nodo anterior con el siguiente nodo seรฑalado por el nodo actual (con VALOR1).

Eliminacion Operadisrupciรณn

PASO 3) Liberar o desasignar el nodo actual.

Recorrido de una lista enlazada circular

Para recorrer una lista enlazada circular, comenzando desde un รบltimo puntero, verifique si el รบltimo puntero es NULL. Si esta condiciรณn es falsa, verifique si solo hay un elemento. De lo contrario, recorra usando un puntero temporal hasta que se alcance nuevamente el รบltimo puntero, o tantas veces como sea necesario, como se muestra en el GIF a continuaciรณn.

Recorrido de una lista enlazada circular

Ventajas de la lista enlazada circular

Algunas de las ventajas de las listas enlazadas circulares son:

  1. No se requiere una asignaciรณn NULL en el cรณdigo. La lista circular nunca apunta a un puntero NULL a menos que se desasigne por completo.
  2. Las listas enlazadas circulares son ventajosas para las operaciones finales ya que el inicio y el final coinciden. Algorithms como la programaciรณn Round Robin puede eliminar claramente los procesos que estรกn en cola de forma circular sin encontrar punteros colgantes o de referencia NULL.
  3. La lista enlazada circular tambiรฉn realiza todas las funciones habituales de una lista enlazada individualmente. De hecho, circular listas doblemente enlazadas que se analiza a continuaciรณn puede incluso eliminar la necesidad de un recorrido completo para ubicar un elemento. Ese elemento, como mรกximo, solo estarรญa exactamente opuesto al inicio, completando solo la mitad de la lista vinculada.

Desventajas de la lista enlazada circular

Las desventajas de utilizar una lista enlazada circular se encuentran a continuaciรณn:

  1. Las listas circulares son complejas en comparaciรณn con listas enlazadas individualmente.
  2. RevEl uso de una lista circular es complejo en comparaciรณn con las listas simples o dobles.
  3. Si no se maneja con cuidado, el cรณdigo puede entrar en un bucle infinito.
  4. Es mรกs difรญcil encontrar el final de la lista y el control del bucle.
  5. Insertando al Inicio, tenemos que recorrer la lista completa para encontrar el รบltimo nodo. (Perspectiva de implementaciรณn)

Lista enlazada individualmente como lista enlazada circular

Le recomendamos que intente leer e implementar el cรณdigo siguiente. Presenta la aritmรฉtica de punteros asociada con listas circulares enlazadas.

#include<stdio.h>
#include<stdlib.h>

struct node
{
    int item;
    struct node *next;
};

struct node* addToEmpty(struct node*,int);
struct node *insertCurrent(struct node *, int);
struct node *insertAfter(struct node *, int, int);
struct node *removeAfter(struct node *, int);
struct node *removeCurrent(struct node *);

void peek(struct node *);

int main()
{
...

Lista individualmente vinculada

Explicaciรณn del cรณdigo:

  1. Las dos primeras lรญneas de cรณdigo son los archivos de encabezado necesarios incluidos.
  2. La siguiente secciรณn describe la estructura de cada nodo autorreferencial. Contiene un valor y un puntero del mismo tipo que la estructura.
  3. Cada estructura se vincula repetidamente con objetos de estructura del mismo tipo.
  4. Existen diferentes prototipos de funciones para:
    1. Agregar un elemento a una lista enlazada vacรญa
    2. Insertando en el actualmente apuntado Posiciรณn de una lista circular enlazada.
    3. Insertar despuรฉs de un particular indexado valor en la lista vinculada.
    4. Quitar/eliminar despuรฉs de un particular indexado valor en la lista vinculada.
    5. Eliminar en la posiciรณn actual de una lista enlazada circular
  5. La รบltima funciรณn imprime cada elemento a travรฉs de un recorrido circular en cualquier estado de la lista vinculada.
int main()
{
    struct node *last = NULL;
    last = insertCurrent(last,4);
    last = removeAfter(last, 4);
    peek(last);
    return 0;
}

struct node* addToEmpty(struct node*last, int data)
{
    struct node *temp = (struct node *)malloc(sizeof( struct node));
    temp->item = data;
    last = temp;
    last->next = last;
    return last;
}
    
struct node *insertCurrent(struct node *last, int data)

Lista individualmente vinculada

Explicaciรณn del cรณdigo:

  1. Para el cรณdigo addEmpty, asigne un nodo vacรญo usando la funciรณn malloc.
  2. Para este nodo, coloque los datos en la variable temporal.
  3. Asignar y vincular la รบnica variable a la variable temporal
  4. Devuelve el รบltimo elemento al contexto principal()/de la aplicaciรณn.
struct node *insertCurrent(struct node *last, int data)
{
    if(last == NULL)
    {
       return    addToEmpty(last, data);
    }
    struct node *temp = (struct node *)malloc(sizeof( struct node));
    temp -> item = data;
    temp->next = last->next;
    last->next = temp;
    return last;
}
struct node *insertAfter(struct node *last, int data, int item)
{
    struct node *temp = last->next, *prev = temp, *newnode =NULL;
โ€ฆ

Lista individualmente vinculada

Explicaciรณn del cรณdigo

  1. Si no hay ningรบn elemento para insertar, debe asegurarse de agregarlo a una lista vacรญa y devolver el control.
  2. Cree un elemento temporal para colocarlo despuรฉs del elemento actual.
  3. Vincule los punteros como se muestra.
  4. Devuelve el รบltimo puntero como en la funciรณn anterior.
...
struct node *insertAfter(struct node *last, int data, int item)
{
    struct node *temp = last->next, *prev = temp, *newnode =NULL;
    if (last == NULL)
    {
       return addToEmpty(last, item);
    }
    do
    {
        prev = temp;
        temp = temp->next;
    } while (temp->next != last && temp->item != data );


    if(temp->item != data)
    {
       printf("Element not found. Please try again");
...

Lista individualmente vinculada

Explicaciรณn del cรณdigo:

  1. Si no hay ningรบn elemento en la lista, ignore los datos, agregue el elemento actual como el รบltimo elemento de la lista y devuelva el control.
  2. Para cada iteraciรณn en el ciclo do- while, asegรบrese de que haya un puntero anterior que contenga el รบltimo resultado recorrido.
  3. Sรณlo entonces podrรก ocurrir el siguiente recorrido.
  4. Si se encuentran los datos, o si la temperatura llega al รบltimo puntero, el proceso do- while finaliza. La siguiente secciรณn de cรณdigo decide quรฉ se debe hacer con el artรญculo.
...
    if(temp->item != data)
    {
       printf("Element not found. Please try again");
       return last;
    }
    else
    {
   	 newnode = (struct node *)malloc(sizeof(struct node));
             newnode->item = item;
             prev->next = newnode;
             newnode->next = temp;
    }
    return last;
}

struct node *removeCurrent(struct node *last)
...

Lista individualmente vinculada

Explicaciรณn del cรณdigo:

  1. Si se ha recorrido toda la lista, pero aรบn no se encuentra el elemento, muestre un mensaje de "elemento no encontrado" y luego devuelva el control a la persona que llama.
  2. Si se encuentra un nodo y/o el nodo aรบn no es el รบltimo nodo, cree un nuevo nodo.
  3. Enlace el nodo anterior con el nuevo nodo. Vincula el nodo actual con temp (la variable transversal).
  4. Esto asegura que el elemento se coloque despuรฉs de un nodo particular en la lista circular enlazada. Regrese a la persona que llama.
struct node *removeCurrent(struct node *last)
{
    if(last == NULL)
    {
        printf("Element Not Found");
        return NULL;
    }
    struct node *temp = last->next;
    last->next = temp->next;
    free(temp);
    return last;
}

struct node *removeAfter(struct node *last, int data)

Lista individualmente vinculada

Explicaciรณn del cรณdigo

  1. Para eliminar solo el รบltimo nodo (actual), verifique si esta lista estรก vacรญa. Si es asรญ, no se podrรก eliminar ningรบn elemento.
  2. La variable temporal simplemente atraviesa un enlace hacia adelante.
  3. Vincula el รบltimo puntero al puntero despuรฉs del primero.
  4. Libere el puntero temporal. Desasigna el รบltimo puntero no vinculado.
struct node *removeAfter(struct node *last,int data)
{
    struct node *temp = NULL,*prev = NULL;
    if (last == NULL)
    {
   	 printf("Linked list empty. Cannot remove any element\n");
   	 return NULL;
    }
    temp = last->next;
    prev = temp;
    do
    {
        prev = temp;
        temp = temp->next;
    } while (temp->next != last && temp->item != data );

    if(temp->item != data)
    {
      printf("Element not found");
...

Lista individualmente vinculada

Explicaciรณn del cรณdigo

  1. Al igual que con la funciรณn de eliminaciรณn anterior, verifique si no hay ningรบn elemento. Si esto es cierto, entonces no se podrรก eliminar ningรบn elemento.
  2. Punteros Se asignan posiciones especรญficas para localizar el elemento a eliminar.
  3. Los punteros avanzan, uno detrรกs del otro. (anterior detrรกs de la temperatura)
  4. El proceso continรบa hasta que se encuentra un elemento, o el siguiente elemento retrocede hasta el รบltimo puntero.
    if(temp->item != data)
    {
        printf("Element not found");
        return last;
    }
    else
    {
        prev->next = temp->next;
        free(temp);
    }
    return last;
}

void peek(struct node * last)
{
    struct node *temp = last;
    if (last == NULL)
    {
   return;	

Lista individualmente vinculada

Explicaciรณn del programa

  1. Si el elemento se encuentra despuรฉs de recorrer toda la lista vinculada, se muestra un mensaje de error que dice que no se encontrรณ el elemento.
  2. De lo contrario, el elemento se desvincula y se libera en los pasos 3 y 4.
  3. El puntero anterior estรก vinculado a la direcciรณn seรฑalada como โ€œsiguienteโ€ por el elemento a eliminar (temp).
  4. Por lo tanto, el puntero temporal se desasigna y se libera.
...
void peek(struct node * last)
{
    struct node *temp = last;
    if (last == NULL)
    {
         return;    
    }
    if(last -> next == last)
    {
        printf("%d-", temp->item);
    }
    while (temp != last)
    {
       printf("%d-", temp->item);
       temp = temp->next;
    }
}

Lista individualmente vinculada

Explicaciรณn del cรณdigo

  1. El vistazo o el recorrido no es posible si no se necesitan ceros. El usuario necesita asignar o insertar un nodo.
  2. Si solo hay un nodo, no es necesario atravesarlo, el contenido del nodo se puede imprimir y el ciclo while no se ejecuta.
  3. Si hay mรกs de un nodo, la temperatura imprime todo el elemento hasta el รบltimo elemento.
  4. En el momento en que se alcanza el รบltimo elemento, el ciclo termina y la funciรณn devuelve la llamada a la funciรณn principal.

Aplicaciones de la Lista Enlazada Circular

  • Implementaciรณn de programaciรณn por turnos en procesos del sistema y programaciรณn circular en grรกficos de alta velocidad.
  • Programaciรณn de Token Rings en redes informรกticas.
  • Se utiliza en unidades de visualizaciรณn como tableros de tiendas que requieren un recorrido continuo de datos.

Resumir este post con: