logo

Introduction à la liste chaînée circulaire

Qu'est-ce que la liste chaînée circulaire ?

Le liste chaînée circulaire est une liste chaînée où tous les nœuds sont connectés pour former un cercle. Dans une liste chaînée circulaire, le premier nœud et le dernier nœud sont connectés l’un à l’autre, ce qui forme un cercle. Il n'y a pas de NULL à la fin.

Liste chaînée circulaire



Il existe généralement deux types de listes chaînées circulaires :

  • Liste circulaire à chaînage unique : Dans une liste circulaire à chaînage unique, le dernier nœud de la liste contient un pointeur vers le premier nœud de la liste. Nous parcourons la liste circulaire à chaînage unique jusqu'à ce que nous atteignions le même nœud que celui où nous avons commencé. La liste circulaire à chaînage unique n’a ni début ni fin. Aucune valeur nulle n'est présente dans la partie suivante d'aucun des nœuds.

Représentation de la liste circulaire à chaînage unique

  • Liste circulaire doublement chaînée : La liste circulaire doublement chaînée a des propriétés à la fois de liste doublement chaînée et de liste chaînée circulaire dans lesquelles deux éléments consécutifs sont liés ou connectés par le pointeur précédent et suivant et le dernier nœud pointe vers le premier nœud par le pointeur suivant et également le premier nœud pointe vers le dernier nœud par le pointeur précédent.

Représentation d'une liste circulaire doublement chaînée



Note: Nous utiliserons la liste chaînée circulaire unique pour représenter le fonctionnement de la liste chaînée circulaire.

Représentation d'une liste chaînée circulaire :

Les listes chaînées circulaires sont similaires aux listes chaînées simples, à l'exception de la connexion du dernier nœud au premier nœud.

Représentation de nœud d'une liste chaînée circulaire :



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->données = $données ;  $this->suivant = null ;  } }>
Python3
# Class Node, similar to the linked list class Node: def __init__(self,data): self.data = data self.next = None>

Exemple de liste circulaire à chaînage unique :

Exemple de liste chaînée circulaire

La liste circulaire ci-dessus à lien unique peut être représentée comme :

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->suivant = deux ; deux->suivant = trois ; trois->suivant = un ;>
Java
// Define the Node class class Node {  int value;  Node next;  public Node(int value) {  this.value = value;  } } // 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 = 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->suivant = deux $ ; $deux->suivant = $trois ; $trois->suivant = $un ;>
Python3
# Initialize the Nodes. one = Node(3) two = Node(5) three = Node(9) # Connect nodes one.next = two two.next = three three.next = one>

Explication: Dans le programme ci-dessus, un, deux et trois sont les nœuds avec respectivement les valeurs 3, 5 et 9 qui sont connectés de manière circulaire comme :

  • Pour le nœud 1 : Le pointeur Next stocke l’adresse du nœud deux.
  • Pour le nœud deux : Le Next stocke l'adresse du nœud trois
  • Pour le nœud trois : Le Next pointe vers le nœud un.

Opérations sur la liste chaînée circulaire :

Nous pouvons effectuer certaines opérations sur la liste chaînée circulaire similaires à la liste chaînée unique qui sont :

  1. Insertion
  2. Effacement

1. Insertion dans la liste chaînée circulaire :

Un nœud peut être ajouté de trois manières :

  1. Insertion en début de liste
  2. Insertion en fin de liste
  3. Insertion entre les nœuds

1) Insertion en début de liste : Pour insérer un nœud au début de la liste, procédez comme suit :

  • Créez un nœud, disons T.
  • Faites T -> suivant = dernier -> suivant.
  • dernier -> suivant = T.

Liste chaînée circulaire avant insertion

liste de tableaux triée

Et puis,

Liste chaînée circulaire après insertion

2) Insertion en fin de liste : Pour insérer un nœud à la fin de la liste, procédez comme suit :

  • Créez un nœud, disons T.
  • Faire T -> suivant = dernier -> suivant ;
  • dernier -> suivant = T.
  • dernier = T.

Avant l'insertion,

Liste chaînée circulaire avant l'insertion du nœud à la fin

10 à la puissance 6

Après insertion,

Liste chaînée circulaire après insertion du nœud à la fin

3) Insertion entre les nœuds : Pour insérer un nœud entre les deux nœuds, procédez comme suit :

  • Créez un nœud, disons T.
  • Recherchez le nœud après lequel T doit être inséré, disons que ce nœud est P.
  • Faire T -> suivant = P -> suivant ;
  • P -> suivant = T.

Supposons que 12 doive être inséré après que le nœud ait la valeur 10,

Liste chaînée circulaire avant insertion

Après recherche et insertion,

Liste chaînée circulaire après insertion

2. Suppression dans une liste chaînée circulaire :

1) Supprimez le nœud uniquement s'il s'agit du seul nœud de la liste chaînée circulaire :

  • Libérer la mémoire du nœud
  • La dernière valeur doit être NULL. Un nœud pointe toujours vers un autre nœud, donc l'affectation NULL n'est pas nécessaire.
    N'importe quel nœud peut être défini comme point de départ.
    Les nœuds sont parcourus rapidement du premier au dernier.

2) Suppression du dernier nœud :

  • Localisez le nœud avant le dernier nœud (qu'il soit temporaire)
  • Conserver l'adresse du nœud à côté du dernier nœud en temp
  • Supprimer le dernier souvenir
  • Mettez la température à la fin

3) Supprimez n'importe quel nœud de la liste chaînée circulaire : Nous recevrons un nœud et notre tâche est de supprimer ce nœud de la liste chaînée circulaire.

Algorithme:
Cas 1 : La liste est vide.

  • Si la liste est vide, nous y reviendrons simplement.

Cas 2 :La liste n'est pas vide

  • Si la liste n'est pas vide alors on définit deux pointeurs courant et précédent et initialisez le pointeur courant avec le tête nœud.
  • Parcourez la liste en utilisant courant pour trouver le nœud à supprimer et avant de passer à curr vers le nœud suivant, définissez à chaque fois prev = curr.
  • Si le nœud est trouvé, vérifiez s'il s'agit du seul nœud de la liste. Si oui, définissez head = NULL et free(curr).
  • Si la liste comporte plusieurs nœuds, vérifiez s'il s'agit du premier nœud de la liste. Condition pour vérifier cela (curr == head). Si oui, déplacez prev jusqu'à ce qu'il atteigne le dernier nœud. Une fois que prev a atteint le dernier nœud, définissez head = head -> next et prev -> next = head. Supprimer le courant.
  • Si curr n'est pas le premier nœud, on vérifie si c'est le dernier nœud de la liste. La condition pour vérifier ceci est (curr -> next == head).
  • Si curr est le dernier nœud. Définissez prev -> next = head et supprimez le nœud curr par free(curr).
  • Si le nœud à supprimer n'est ni le premier nœud ni le dernier nœud, définissez prev -> next = curr -> next et supprimez curr.
  • Si le nœud n’est pas présent dans la liste, retournez head et ne faites rien.

Vous trouverez ci-dessous la mise en œuvre de l'approche ci-dessus :

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->données = données ;  ptr1->suivant = *head_ref;  // Si la liste chaînée n'est pas NULL alors // définit le prochain du dernier nœud if (*head_ref != NULL) { // Recherchez le nœud avant head et // mettez à jour le suivant.  Noeud* temp = *head_ref;  while (temp->next != *head_ref) temp = temp->next;  temp->suivant = ptr1;  } else // Pour le premier nœud ptr1->next = ptr1;  *head_ref = ptr1; } // Fonction pour imprimer les nœuds dans une // liste chaînée circulaire donnée void printList(Node* head) { Node* temp = head;  if (head != NULL) { do { cout<< temp->données<< ' ';  temp = temp->suivant;  } while (temp != tête);  } 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)->data == clé && (*head)->suivant == *head) { free(*head);  *tête = NULL ;  retour;  } Nœud *last = *head, *d;  // Si head doit être supprimé if ((*head)->data == key) { // Trouver le dernier nœud de la liste while (last->next != *head) last = last->next;  // Pointez le dernier nœud vers le prochain de // head, c'est-à-dire le deuxième nœud // de la liste last->next = (*head)->next;  libre(*tête);  *head = dernier->suivant ;  retour;  } // Soit le nœud à supprimer est // introuvable, soit la fin de la liste // n'est pas atteinte while (last->next != *head && last->next->data != key) { last = last ->suivant ;  } // Si le nœud à supprimer a été trouvé if (last->next->data == key) { d = last->next;  dernier->suivant = d->suivant ;  libéré);  } sinon 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 poussée(&tête, 2);  pousser(&tête, 5);  pousser(&tête, 7);  pousser(&tête, 8);  pousser(&tête, 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->données = données ;  ptr1->suivant = *head_ref;  // Si la liste chaînée n'est pas NULL alors // définit le prochain du dernier nœud if (*head_ref != NULL) { // Recherchez le nœud avant head et // mettez à jour le suivant.  struct Node* temp = *head_ref;  while (temp->next != *head_ref) temp = temp->next;  temp->suivant = ptr1;  } else // Pour le premier nœud ptr1->next = ptr1;  *head_ref = ptr1; } // Fonction pour imprimer les nœuds dans une // liste chaînée circulaire donnée void printList(struct Node* head) { struct Node* temp = head;  if (head != NULL) { do { printf('%d ', temp->data);  temp = temp->suivant ;  } while (temp != tête);  } printf('
'); } // Fonction pour supprimer un nœud donné // de la liste void deleteNode(struct Node** head, int key) { // Si la liste chaînée est vide if (*head == NULL) return;  // Si la liste ne contient // qu'un seul nœud if ((*head)->data == key && (*head)->next == *head) { free(*head);  *tête = NULL ;  retour;  } struct Noeud *last = *head, *d;  // Si head doit être supprimé if ((*head)->data == key) { // Trouver le dernier nœud de la liste while (last->next != *head) last = last->next;  // Pointez le dernier nœud vers le prochain de // head, c'est-à-dire le deuxième nœud // de la liste last->next = (*head)->next;  libre(*tête);  *head = dernier->suivant ;  retour;  } // Soit le nœud à supprimer est // introuvable, soit la fin de la liste // n'est pas atteinte while (last->next != *head && last->next->data != key) { last = last ->suivant ;  } // Si le nœud à supprimer a été trouvé if (last->next->data == key) { d = last->next;  dernier->suivant = d->suivant ;  libéré);  } else printf('Le nœud donné est introuvable dans la liste !!!
'); } // Code du pilote int main() { // Initialise les listes comme vides struct Node* head = NULL;  // La liste chaînée créée sera // 2->5->7->8->10 push(&head, 2);  pousser(&tête, 5);  pousser(&tête, 7);  pousser(&tête, 8);  pousser(&tête, 10);  printf('Liste avant suppression : ');  printList(tête);  deleteNode(&head, 7);  printf('Liste après suppression : ');  printList(tête);  renvoie 0 ; }>
Java
// Java program to delete a given key from // linked list. import java.io.*; import java.util.*; public class GFG {  /* structure for a node */  static class Node {  int data;  Node next;  };  /* Function to insert a node at the beginning of a Circular linked list */  static Node push(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  ptr1.next = ptr1; /*For the first node */  head_ref = ptr1;  return head_ref;  }  /* Function to print nodes in a given circular linked list */  static void printList(Node head)  {  Node temp = head;  if (head != null) {  do {  System.out.printf('%d ', temp.data);  temp = temp.next;  } while (temp != head);  }  System.out.printf('
');  }  /* Function to delete a given node from the list */  static Node deleteNode(Node head, int key)  {  if (head == null)  return null;  int flag = 0;  // Find the required node  Node curr = head, prev = new Node();  while (curr.data != key) {  if (curr.next == head) {  System.out.printf(  'Given node is not found in the list!!!
');  flag = 1;  break;  }  prev = curr;  curr = curr.next;  }  // Check if the element is not present in the list  if (flag == 1)  return head;  // Check if node is only node  if (curr == head && curr.next == head) {  head = null;  return head;  }  // If more than one node, check if  // it is first node  if (curr == head) {  prev = head;  while (prev.next != head)  prev = prev.next;  head = curr.next;  prev.next = head;  }  // check if node is last node  else if (curr.next == head) {  prev.next = head;  }  else {  prev.next = curr.next;  }  return head;  }  /* Driver code */  public static void main(String args[])  {  /* Initialize lists as empty */  Node head = null;  /* Created linked list will be 2.5.7.8.10 */  head = push(head, 2);  head = push(head, 5);  head = push(head, 7);  head = push(head, 8);  head = push(head, 10);  System.out.printf('List Before Deletion: ');  printList(head);  head = deleteNode(head, 7);  System.out.printf('List After Deletion: ');  printList(head);  } } // This code is contributed by Susobhan Akhuli>
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 Poussoir (réf tête, 2) ;  Pousser (réf tête, 5);  Pousser (réf tête, 7) ;  Pousser (réf tête, 8) ;  Pousser (réf tête, 10) ;  Console.Write('Liste avant suppression : ');  ImprimerListe(tête);  SupprimerNode(tête de référence, 7);  Console.Write('Liste après suppression : ');  ImprimerListe(tête);  } }>
Javascript
 // Javascript program to delete a given key from linked list.  // Structure for a node  class Node {  constructor() {  this.data;  this.next;  }  }  // Function to insert a node at the  // beginning of a Circular linked list  function push(head, data) {  // Create a new node and make head  // as next of it.  var ptr1 = new Node();  ptr1.data = data;  ptr1.next = head;  // If linked list is not NULL then  // set the next of last node  if (head != null) {  // Find the node before head and  // update next of it.  let temp = head;  while (temp.next != head) temp = temp.next;  temp.next = ptr1;  }  // For the first node  else ptr1.next = ptr1;  head = ptr1;  return head;  }  // Function to print nodes in a given  // circular linked list  function printList(head) {  let tempp = head;  if (head != null) {  do {  console.log(tempp.data);  tempp = tempp.next;  } while (tempp != head);  }  }  // Function to delete a given node  // from the list  function deleteNode(head, 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;  }  let last = head;  // 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;  d = null;  } else console.log('Given node is not found in the list!!!');  }  // Driver code  // Initialize lists as empty  head = null;  // Created linked list will be  // 2->5->7->8->10 tête = pousser(tête, 2);  tête = pousser(tête, 5);  tête = pousser(tête, 7);  tête = pousser(tête, 8);  tête = pousser (tête, 10);  console.log('Liste avant suppression : ');  printList(tête);  deleteNode(tête, 7);  console.log('Liste après suppression : ');  printList(tête);>
Python3
# Python program to delete a given key from linked list class Node: def __init__(self, data): self.data = data self.next = None # Function to insert a node at the # beginning of a Circular linked list def push(head, data): # Create a new node and make head as next of it. newP = Node(data) newP.next = head # If linked list is not NULL then # set the next of last node if head != None: # Find the node before head and # update next of it. temp = head while (temp.next != head): temp = temp.next temp.next = newP else: newP.next = newP head = newP return head # Function to print nodes in a given circular linked list def printList(head): if head == None: print('List is Empty') return temp = head.next print(head.data, end=' ') if (head != None): while (temp != head): print(temp.data, end=' ') temp = temp.next print() # Function to delete a given node # from the list def deleteNode(head, key): # If linked list is empty if (head == None): return # If the list contains only a # single node if (head.data == key and head.next == head): head = None return last = head # 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 and 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 d = None else: print('Given node is not found in the list!!!') # Driver code # Initialize lists as empty head = None # Created linked list will be # 2->5->7->8->10 tête = pousser(tête, 2) tête = pousser(tête, 5) tête = pousser(tête, 7) tête = pousser(tête, 8) tête = pousser(tête, 10) print('Liste avant suppression : ') printList(head) deleteNode(head, 7) print('Liste après suppression : ') printList(head)>

Sortir
List Before Deletion: 10 8 7 5 2 List After Deletion: 10 8 5 2>

Complexité temporelle : O(N), le pire des cas se produit lorsque l'élément à supprimer est le dernier élément et que nous devons parcourir toute la liste.
Espace auxiliaire : O(1), Comme espace supplémentaire constant est utilisé.

Avantages des listes circulaires liées :

  • N'importe quel nœud peut être un point de départ. Nous pouvons parcourir toute la liste en partant de n’importe quel point. Nous devons simplement nous arrêter lorsque le premier nœud visité est à nouveau visité.
  • Utile pour la mise en œuvre d'une file d'attente. Contrairement à ce implémentation, nous n’avons pas besoin de conserver deux pointeurs pour l’avant et l’arrière si nous utilisons une liste chaînée circulaire. Nous pouvons conserver un pointeur vers le dernier nœud inséré et le front peut toujours être obtenu comme avant-dernier.
  • Les listes circulaires sont utiles dans les applications pour parcourir la liste de manière répétée. Par exemple, lorsque plusieurs applications sont en cours d'exécution sur un PC, il est courant que le système d'exploitation place les applications en cours d'exécution sur une liste, puis les parcourt, en donnant à chacune d'elles une tranche de temps pour s'exécuter, puis en les faisant attendre. le CPU est confié à une autre application. Il est pratique pour le système d'exploitation d'utiliser une liste circulaire afin que lorsqu'il atteint la fin de la liste, il puisse revenir au début de la liste.
  • Les listes circulaires doublement liées sont utilisées pour la mise en œuvre de structures de données avancées telles que Tas de Fibonacci .
  • La mise en œuvre d'une liste chaînée circulaire peut être relativement simple par rapport à d'autres structures de données plus complexes comme des arbres ou des graphiques.

Inconvénients de la liste chaînée circulaire :

  • Par rapport aux listes à chaînage unique, les listes circulaires sont plus complexes.
  • Inverser une liste circulaire est plus compliqué que d’inverser une ou deux fois une liste circulaire.
  • Il est possible que le code entre dans une boucle infinie s’il n’est pas traité avec précaution.
  • Il est plus difficile de retrouver la fin de la liste et de contrôler la boucle.
  • Bien que les listes chaînées circulaires puissent être efficaces dans certaines applications, leurs performances peuvent être plus lentes que celles d'autres structures de données dans certains cas, par exemple lorsque la liste doit être triée ou recherchée.
  • Les listes chaînées circulaires ne fournissent pas d'accès direct aux nœuds individuels

Applications des listes chaînées circulaires :

  • Les jeux multijoueurs l'utilisent pour donner à chaque joueur une chance de jouer.
  • Une liste chaînée circulaire peut être utilisée pour organiser plusieurs applications en cours d’exécution sur un système d’exploitation. Ces applications sont itérées par le système d'exploitation.
  • Les listes chaînées circulaires peuvent être utilisées dans les problèmes d’allocation de ressources.
  • Les listes chaînées circulaires sont couramment utilisées pour implémenter des tampons circulaires,
  • Les listes chaînées circulaires peuvent être utilisées dans la simulation et les jeux.

Pourquoi une liste chaînée circulaire ?

  • Un nœud pointe toujours vers un autre nœud, donc l’affectation NULL n’est pas nécessaire.
  • N'importe quel nœud peut être défini comme point de départ.
  • Les nœuds sont parcourus rapidement du premier au dernier.

Articles suivants : Liste liée circulaire | Ensemble 2 (traversée) Liste circulaire à lien unique | Insertion Veuillez écrire des commentaires si vous trouvez un bug dans le code/algorithme ci-dessus, ou trouvez d'autres moyens de résoudre le même problème.