Què és la llista enllaçada circular?
El llista enllaçada circular és una llista enllaçada on tots els nodes estan connectats per formar un cercle. En una llista enllaçada circular, el primer node i l'últim node estan connectats entre si formant un cercle. No hi ha NULL al final.
Llista enllaçada circular
En general, hi ha dos tipus de llistes enllaçades circulars:
- Llista circular enllaçada individualment: En una llista circular enllaçada individualment, l'últim node de la llista conté un punter al primer node de la llista. Recorrem la llista circular enllaçada individualment fins a arribar al mateix node on vam començar. La llista circular enllaçada individualment no té principi ni final. No hi ha cap valor nul a la part següent de cap dels nodes.

Representació de la llista circular enllaçada individualment
- Llista circular doblement enllaçada: La llista circular doblement enllaçada té propietats tant de llista doblement enllaçada com de llista enllaçada circular en què dos elements consecutius estan enllaçats o connectats pel punter anterior i següent i l'últim node apunta al primer node pel punter següent i també el primer node apunta a l'últim node pel punter anterior.

Representació de llista circular doblement enllaçada
Nota: Utilitzarem la llista enllaçada circular individualment per representar el funcionament de la llista enllaçada circular.
Representació de la llista enllaçada circular:
Les llistes enllaçades circulars són similars a les llistes enllaçades simples amb l'excepció de connectar l'últim node al primer node.
Representació de nodes d'una llista enllaçada circular:
ordenació de seleccióC++
// Class Node, similar to the linked list class Node{ int value; // Points to the next node. Node next; }>
C struct Node { int data; struct Node *next; };>
Java public class Node { int data; Node next; public Node(int data) { this.data = data; this.next = null; } }>
C# public class Node { public int data; public Node next; public Node(int data) { this.data = data; this.next = null; } }>
Javascript class Node { constructor(data) { this.data = data; this.next = null; } }>
PHP class Node { public $data; public $next; function __construct($data) { $this->dades = $dades; $això->següent = nul; } }>>>Python 3Exemple de llista circular enllaçada individualment: 
Exemple de llista enllaçada circular
La llista enllaçada individualment circular anterior es pot representar com:
C++ // Initialize the Nodes. Node one = new Node(3); Node two = new Node(5); Node three = new Node(9); // Connect nodes one.next = two; two.next = three; three.next = one;>
C Node* one = createNode(3); Node* two = createNode(5); Node* three = createNode(9); // Connect nodes one->següent = dos; dos->següent = tres; tres->següent = un;>>>
Java Node one = new Node(3); Node two = new Node(5); Node three = new Node(9); // Connect nodes one.next = two; two.next = three; three.next = one;>
Javascript let one = new Node(3); let two = new Node(5); let three = new Node(9); // Connect nodes one.next = two; two.next = three; three.next = one;>
PHP $one = new Node(3); $two = new Node(5); $three = new Node(9); // Connect nodes $one->següent = $dos; $dos->següent = $tres; $tres->següent = $un;>>>Python 3 Explicació: En el programa anterior, un, dos i tres són els nodes amb valors 3, 5 i 9, respectivament, connectats de manera circular com: - Per al node 1: El punter següent emmagatzema l'adreça del node dos.
- Per al node dos: El següent emmagatzema l'adreça del node tres
- Per al node tres: El A continuació apunta al node 1.
Operacions a la llista enllaçada circular:
Podem fer algunes operacions a la llista enllaçada circular similars a la llista enllaçada individualment que són:
- Inserció
- Supressió
1. Inserció a la llista enllaçada circular:
Un node es pot afegir de tres maneres:
- Inserció al començament de la llista
- Inserció al final de la llista
- Inserció entre els nodes
1) Inserció al principi de la llista: Per inserir un node al principi de la llista, seguiu aquests passos:
- Creeu un node, digueu T.
- Feu T -> següent = darrer -> següent.
- últim -> següent = T.

Llista enllaçada circular abans de la inserció
I llavors,

Llista enllaçada circular després de la inserció
2) Inserció al final de la llista: Per inserir un node al final de la llista, seguiu aquests passos:
- Creeu un node, digueu T.
- Feu T -> següent = darrer -> següent;
- últim -> següent = T.
- darrer = T.
Abans de la inserció,

Llista enllaçada circular abans de la inserció del node al final
Després de la inserció,

Llista enllaçada circular després de la inserció del node al final
3) Inserció entre els nodes: Per inserir un node entre els dos nodes, seguiu aquests passos:
- Creeu un node, digueu T.
- Cerqueu el node després del qual cal inserir T, diguem que el node és P.
- Feu T -> següent = P -> següent;
- P -> següent = T.
Suposem que s'ha d'inserir 12 després que el node tingui el valor 10,

Llista enllaçada circular abans de la inserció
Després de la cerca i inserció,

Llista enllaçada circular després de la inserció
2. Supressió en una llista enllaçada circular:
1) Suprimeix el node només si és l'únic node de la llista enllaçada circular:
- Allibera la memòria del node
- L'últim valor hauria de ser NULL. Un node sempre apunta a un altre node, de manera que l'assignació de NULL no és necessària.
Qualsevol node es pot establir com a punt de partida.
Els nodes es recorren ràpidament des del primer fins a l'últim.
2) Supressió de l'últim node:
- Localitzeu el node abans de l'últim node (que sigui temporal)
- Mantingueu l'adreça del node al costat de l'últim node a temp
- Esborra l'últim record
- Posa la temperatura al final
3) Suprimeix qualsevol node de la llista enllaçada circular: Ens donarà un node i la nostra tasca és eliminar aquest node de la llista enllaçada circular.
Algorisme:
Cas 1 : La llista està buida.
- Si la llista està buida, simplement tornarem.
Cas 2 : La llista no està buida
- Si la llista no està buida, definim dos punters curr i anterior i inicialitzeu el punter curr amb el cap node.
- Travessa la llista utilitzant curr per trobar el node que s'ha d'esborrar i abans de passar a curr al següent node, cada cop establiu prev = curr.
- Si es troba el node, comproveu si és l'únic node de la llista. En cas afirmatiu, establiu head = NULL i free(curr).
- Si la llista té més d'un node, comproveu si és el primer node de la llista. Condició per comprovar-ho (curr == cap). En cas afirmatiu, moveu l'anterior fins que arribi a l'últim node. Després que prev arribi a l'últim node, configureu cap = cap -> següent i prev -> següent = cap. Suprimeix curr.
- Si curr no és el primer node, comprovem si és l'últim node de la llista. La condició per comprovar-ho és (curr -> next == head).
- Si curr és l'últim node. Establiu prev -> next = cap i suprimiu el node curr per free(curr).
- Si el node que s'ha d'esborrar no és ni el primer node ni l'últim node, llavors establiu prev -> next = curr -> next i suprimiu curr.
- Si el node no està present a la llista, retorneu el capçal i no feu res.
A continuació es mostra la implementació de l'enfocament anterior:
C++ // C++ program to delete a given key from // linked list. #include using namespace std; // Structure for a node class Node { public: int data; Node* next; }; // Function to insert a node at the // beginning of a Circular linked list void push(Node** head_ref, int data) { // Create a new node and make head // as next of it. Node* ptr1 = new Node(); ptr1->dades = dades; ptr1->següent = *head_ref; // Si la llista enllaçada no és NULL aleshores // estableix el següent de l'últim node si (*head_ref != NULL) { // Troba el node abans del cap i // actualitza el següent. Node* temp = *head_ref; while (temp->next != *head_ref) temp = temp->next; temp->next = ptr1; } else // Per al primer node ptr1->next = ptr1; *head_ref = ptr1; } // Funció per imprimir nodes en una // llista enllaçada circular void printList(Node* cap) { Node* temp = cap; if (cap != NULL) { do { cout<< temp->dades<< ' '; temp = temp->Pròxim; } mentre (temp!= cap); } cout<< endl; } // Function to delete a given node // from the list void deleteNode(Node** head, int key) { // If linked list is empty if (*head == NULL) return; // If the list contains only a // single node if ((*head)->dades == clau && (*head)->next == *head) { lliure(*cap); *cap = NULL; tornar; } Node *últim = *cap, *d; // Si el cap s'ha d'esborrar if ((*head)->data == key) { // Troba l'últim node de la llista mentre (últim->següent != *head) últim = últim->següent; // Apunta l'últim node al següent de // cap, és a dir, el segon node // de la llista last->next = (*head)->next; lliure(*cap); *cap = darrer->següent; tornar; } // O el node a suprimir // no es troba o el final de la llista // no s'arriba mentre (últim->següent != *cap && darrer->següent->dades != clau) { darrer = darrer ->següent; } // Si s'ha trobat el node que s'ha d'esborrar si (últim->següent->dades == clau) { d = últim->següent; darrer->següent = d->següent; lliure (d); } més cout<< 'Given node is not found in the list!!!
'; } // Driver code int main() { // Initialize lists as empty Node* head = NULL; // Created linked list will be // 2->5->7->8->10 empenta (&cap, 2); empenta(&cap, 5); empenta(&cap, 7); empenta (&cap, 8); push(&cap, 10); cout<< 'List Before Deletion: '; printList(head); deleteNode(&head, 7); cout << 'List After Deletion: '; printList(head); return 0; }>
C #include #include // Structure for a node struct Node { int data; struct Node* next; }; // Function to insert a node at the // beginning of a Circular linked list void push(struct Node** head_ref, int data) { // Create a new node and make head // as next of it. struct Node* ptr1 = (struct Node*)malloc(sizeof(struct Node)); ptr1->dades = dades; ptr1->següent = *head_ref; // Si la llista enllaçada no és NULL aleshores // estableix el següent de l'últim node si (*head_ref != NULL) { // Troba el node abans del cap i // actualitza el següent. struct Node* temp = *head_ref; while (temp->next != *head_ref) temp = temp->next; temp->següent = ptr1; } else // Per al primer node ptr1->next = ptr1; *head_ref = ptr1; } // Funció per imprimir nodes en una // llista enllaçada circular void printList(struct Node* head) { struct Node* temp = head; if (cap != NULL) { do { printf('%d ', temp->dades); temp = temp->següent; } mentre (temp!= cap); } printf('
'); } // Funció per eliminar un node determinat // de la llista void deleteNode(struct Node** head, int key) { // Si la llista enllaçada està buida si (*head == NULL) retorna; // Si la llista només conté // un sol node if ((*head)->data == clau && (*head)->next == *head) { free(*head); *cap = NULL; tornar; } struct Node *últim = *cap, *d; // Si el cap s'ha d'esborrar if ((*head)->data == key) { // Troba l'últim node de la llista mentre (últim->següent != *head) últim = últim->següent; // Apunta l'últim node al següent de // cap, és a dir, el segon node // de la llista last->next = (*head)->next; lliure(*cap); *cap = darrer->següent; tornar; } // O el node a suprimir // no es troba o el final de la llista // no s'arriba mentre (últim->següent != *cap && darrer->següent->dades != clau) { darrer = darrer ->següent; } // Si s'ha trobat el node que s'ha d'esborrar si (últim->següent->dades == clau) { d = últim->següent; darrer->següent = d->següent; lliure (d); } else printf('El node donat no es troba a la llista!!!
'); } // Codi del controlador int main() { // Inicialitzar llistes com a estructura buida Node* head = NULL; // La llista enllaçada creada serà // 2->5->7->8->10 push(&head, 2); empenta(&cap, 5); empenta (&cap, 7); empenta (&cap, 8); push(&cap, 10); printf('Llista abans de la supressió: '); printList(capçal); deleteNode(&head, 7); printf('Llista després de la supressió: '); printList(capçal); retorn 0; }>>>
Java
C# using System; // Structure for a node public class Node { public int data; public Node next; } // Class for Circular Linked List public class CircularLinkedList { // Function to insert a node at the // beginning of a Circular linked list public static void Push(ref Node head_ref, int data) { // Create a new node and make head // as next of it. Node ptr1 = new Node(); ptr1.data = data; ptr1.next = head_ref; // If linked list is not NULL then // set the next of last node if (head_ref != null) { // Find the node before head and // update next of it. Node temp = head_ref; while (temp.next != head_ref) temp = temp.next; temp.next = ptr1; } else // For the first node ptr1.next = ptr1; head_ref = ptr1; } // Function to print nodes in a given // circular linked list public static void PrintList(Node head) { Node temp = head; if (head != null) { do { Console.Write(temp.data + ' '); temp = temp.next; } while (temp != head); } Console.WriteLine(); } // Function to delete a given node // from the list public static void DeleteNode(ref Node head, int key) { // If linked list is empty if (head == null) return; // If the list contains only a // single node if (head.data == key && head.next == head) { head = null; return; } Node last = head, d; // If head is to be deleted if (head.data == key) { // Find the last node of the list while (last.next != head) last = last.next; // Point last node to the next of // head i.e. the second node // of the list last.next = head.next; head = last.next; return; } // Either the node to be deleted is // not found or the end of list // is not reached while (last.next != head && last.next.data != key) { last = last.next; } // If node to be deleted was found if (last.next.data == key) { d = last.next; last.next = d.next; } else Console.WriteLine( 'Given node is not found in the list!!!'); } // Driver code public static void Main() { // Initialize lists as empty Node head = null; // Created linked list will be // 2->5->7->8->10 Empènyer (cap de referència, 2); Empènyer (cap de referència, 5); Empènyer (cap de referència, 7); Empènyer (cap de referència, 8); Empènyer (cap de referència, 10); Console.Write('Llista abans de la supressió: '); PrintList (capçal); DeleteNode (cap de referència, 7); Console.Write('Llista després de la supressió: '); PrintList (capçal); } }>>>Javascript5->7->8->10 cap = empènyer (cap, 2); cap = empènyer (cap, 5); cap = empènyer (cap, 7); cap = empènyer (cap, 8); cap = empènyer (cap, 10); console.log('Llista abans de la supressió: '); printList(capçal); deleteNode(cap, 7); console.log('Llista després de la supressió: '); printList(capçal);>>> Python 35->7->8->10 cap = empènyer (cap, 2) cap = empènyer (cap, 5) cap = empènyer (cap, 7) cap = empènyer (cap, 8) cap = empènyer (cap, 10) print('Llista abans de la supressió: ') printList(head) deleteNode(head, 7) print('List After Deletion: ') printList(head)>
Sortida
List Before Deletion: 10 8 7 5 2 List After Deletion: 10 8 5 2>
Complexitat temporal: O(N), el pitjor dels casos es produeix quan l'element a suprimir és l'últim element i hem de moure'ns per tota la llista.
Espai auxiliar: O(1), com a espai addicional constant s'utilitza.
Avantatges de les llistes enllaçades circulars:
- Qualsevol node pot ser un punt de partida. Podem recórrer tota la llista començant des de qualsevol punt. Només hem d'aturar-nos quan es torni a visitar el primer node visitat.
- Útil per a la implementació d'una cua. A diferència això implementació, no necessitem mantenir dos punters per davant i darrere si fem servir una llista enllaçada circular. Podem mantenir un punter al darrer node inserit i el front sempre es pot obtenir com el següent de l'últim.
- Les llistes circulars són útils en aplicacions per recórrer la llista repetidament. Per exemple, quan s'executen diverses aplicacions en un ordinador, és habitual que el sistema operatiu posi les aplicacions que s'executen en una llista i després les recorre, donant a cadascuna una part de temps per executar-les i, a continuació, fer-les esperar mentre la CPU es dóna a una altra aplicació. És convenient que el sistema operatiu utilitzi una llista circular perquè, quan arribi al final de la llista, pugui passar al capdavant de la llista.
- Les llistes circulars doblement enllaçades s'utilitzen per a la implementació d'estructures de dades avançades com ara Munt de Fibonacci .
- Implementar una llista enllaçada circular pot ser relativament fàcil en comparació amb altres estructures de dades més complexes com ara arbres o gràfics.
Desavantatges de la llista enllaçada circular:
- En comparació amb les llistes enllaçades individualment, les llistes circulars són més complexes.
- Invertir una llista circular és més complicat que invertir una llista circular de manera individual o doble.
- És possible que el codi entri en un bucle infinit si no es gestiona amb cura.
- És més difícil trobar el final de la llista i controlar el bucle.
- Tot i que les llistes enllaçades circulars poden ser eficients en determinades aplicacions, el seu rendiment pot ser més lent que altres estructures de dades en determinats casos, com ara quan cal ordenar o cercar la llista.
- Les llistes enllaçades circulars no proporcionen accés directe a nodes individuals
Aplicacions de llistes enllaçades circulars:
- Els jocs multijugador utilitzen això per donar a cada jugador l'oportunitat de jugar.
- Es pot utilitzar una llista enllaçada circular per organitzar diverses aplicacions en execució en un sistema operatiu. Aquestes aplicacions són repetides pel sistema operatiu.
- Les llistes enllaçades circulars es poden utilitzar en problemes d'assignació de recursos.
- Les llistes enllaçades circulars s'utilitzen habitualment per implementar buffers circulars,
- Les llistes enllaçades circulars es poden utilitzar en simulació i jocs.
Per què llista enllaçada circular?
- Un node sempre apunta a un altre node, de manera que l'assignació NULL no és necessària.
- Qualsevol node es pot establir com a punt de partida.
- Els nodes es recorren ràpidament des del primer fins a l'últim.
Pròximes publicacions: Llista enllaçada circular | Set 2 (traversament) Llista enllaçada individualment circular | Inserció Si us plau, escriviu comentaris si trobeu algun error al codi/algoritme anterior o trobeu altres maneres de resoldre el mateix problema