logo

Вступ до циклічного пов’язаного списку

Що таке циклічний пов’язаний список?

The циклічний пов'язаний список це пов’язаний список, де всі вузли з’єднані в коло. У кільцевому пов’язаному списку перший вузол і останній вузол з’єднані один з одним, утворюючи коло. У кінці немає NULL.

Круговий пов'язаний список



Зазвичай існує два типи циклічних пов’язаних списків:

  • Круговий однозв'язаний список: У кільцевому однозв’язаному списку останній вузол списку містить покажчик на перший вузол списку. Ми проходимо круговий однозв’язаний список, поки не досягнемо того самого вузла, з якого почали. Круговий однозв’язаний список не має ні початку, ні кінця. У наступній частині будь-якого з вузлів немає нульового значення.

Представлення кругового однозв'язного списку

панель інструментів швидкого доступу Word
  • Круговий двозв'язаний список: Циркулярний двозв’язаний список має властивості як двозв’язаного списку, так і циклічного зв’язаного списку, у якому два послідовні елементи пов’язані або з’єднані попереднім і наступним покажчиками, а останній вузол вказує на перший вузол за допомогою наступного покажчика, а також перший вузол вказує на останній вузол за попереднім покажчиком.

Представлення кільцевого двозв'язного списку



Примітка: Ми будемо використовувати циклічний пов’язаний список, щоб представити роботу циклічного зв’язаного списку.

Представлення циклічного пов’язаного списку:

Циркулярні пов’язані списки подібні до окремих зв’язаних списків, за винятком з’єднання останнього вузла з першим вузлом.

Представлення вузла циклічного пов’язаного списку:



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

Приклад циклічного однозв’язаного списку:

Приклад циклічного пов’язаного списку

Наведений вище циклічний однозв’язаний список можна представити у вигляді:

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->наступний = два; два->наступний = три; три->наступний = один;>
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->наступний = $два; $два->наступний = $три; $три->наступний = $один;>
Python3
# Initialize the Nodes. one = Node(3) two = Node(5) three = Node(9) # Connect nodes one.next = two two.next = three three.next = one>

Пояснення: У наведеній вище програмі один, два і три є вузлами зі значеннями 3, 5 і 9 відповідно, які з’єднані по колу як:

  • Для Node One: Покажчик Next зберігає адресу другого вузла.
  • Для другого вузла: Next зберігає адресу третього вузла
  • Для третього вузла: The Далі вказує на вузол один.

Операції в циклічному пов’язаному списку:

Ми можемо виконувати деякі операції над циклічним пов’язаним списком, подібним до однозв’язаного списку, а саме:

  1. Вставка
  2. Видалення

1. Вставка в циклічний зв'язаний список:

Вузол можна додати трьома способами:

  1. Вставка на початку списку
  2. Вставка в кінці списку
  3. Вставка між вузлами

1) Вставка на початку списку: Щоб вставити вузол на початку списку, виконайте такі дії:

  • Створіть вузол, скажіть T.
  • Зробіть T -> наступний = останній -> наступний.
  • останній -> наступний = T.

Круговий пов’язаний список перед вставкою

І потім,

Круговий пов’язаний список після вставки

2) Вставка в кінці списку: Щоб вставити вузол у кінець списку, виконайте такі дії:

  • Створіть вузол, скажіть T.
  • Зробити T -> наступний = останній -> наступний;
  • останній -> наступний = T.
  • останній = Т.

Перед введенням,

Круговий пов’язаний список перед вставкою вузла в кінці

рядок і стовпець

Після вставки,

Круговий пов’язаний список після вставки вузла в кінці

3) Вставка між вузлами: Щоб вставити вузол між двома вузлами, виконайте такі дії:

  • Створіть вузол, скажіть T.
  • Знайдіть вузол, після якого потрібно вставити T, скажіть, що вузол P.
  • Зробити T -> наступний = P -> наступний;
  • P -> наступний = T.

Припустимо, що 12 потрібно вставити після того, як вузол має значення 10,

Круговий пов’язаний список перед вставкою

Після пошуку та вставки,

Круговий пов’язаний список після вставки

2. Видалення в циклічному пов’язаному списку:

1) Видаліть вузол, лише якщо він є єдиним вузлом у циклічному пов’язаному списку:

перетворити рядок на jsonobject java
  • Звільніть пам'ять вузла
  • Останнє значення має бути NULL. Вузол завжди вказує на інший вузол, тому призначення NULL не потрібне.
    Початковою точкою може бути будь-який вузол.
    Вузли швидко проходять від першого до останнього.

2) Видалення останнього вузла:

  • Знайдіть вузол перед останнім вузлом (нехай він буде тимчасовим)
  • Зберігайте адресу вузла поруч із останнім вузлом у temp
  • Видалити останній спогад
  • В кінці поставте темп

3) Видаліть будь-який вузол із циклічного пов’язаного списку: Нам буде надано вузол, і наше завдання — видалити цей вузол із циклічного пов’язаного списку.

Алгоритм:
Випадок 1 : список порожній.

  • Якщо список порожній, ми просто повернемося.

Випадок 2 :Список не пустий

  • Якщо список не порожній, ми визначаємо два покажчики curr і поперед і ініціалізуйте покажчик curr з голова вузол.
  • Перейдіть по списку за допомогою curr щоб знайти вузол, який потрібно видалити, і перед переходом до curr до наступного вузла щоразу встановлюйте prev = curr.
  • Якщо вузол знайдено, перевірте, чи це єдиний вузол у списку. Якщо так, встановіть head = NULL і free(curr).
  • Якщо список містить більше одного вузла, перевірте, чи це перший вузол списку. Умова для перевірки ( curr == head). Якщо так, то рухайтеся prev до останнього вузла. Коли prev досягне останнього вузла, встановіть head = head -> next і prev -> next = head. Видалити поточний.
  • Якщо curr не є першим вузлом, ми перевіряємо, чи є він останнім вузлом у списку. Умовою перевірки є (curr -> next == head).
  • Якщо curr є останнім вузлом. Установіть prev -> next = head і видаліть вузол curr за допомогою free(curr).
  • Якщо вузол, який потрібно видалити, не є ні першим, ні останнім вузлом, тоді встановіть prev -> next = curr -> next і видаліть curr.
  • Якщо вузол відсутній у списку, поверніть голову та нічого не робіть.

Нижче наведено реалізацію вищезазначеного підходу:

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->дані = дані;  ptr1->next = *head_ref;  // Якщо пов’язаний список не NULL, тоді // встановіть наступний з останніх вузол if (*head_ref != NULL) { // Знайдіть вузол перед заголовком і // оновіть наступний за ним.  Node* temp = *head_ref;  while (temp->next != *head_ref) temp = temp->next;  temp->next = ptr1;  } else // Для першого вузла ptr1->next = ptr1;  *head_ref = ptr1; } // Функція для друку вузлів у заданому // циклічному пов’язаному списку void printList(Node* head) { Node* temp = head;  if (head != NULL) { do { cout<< temp->даних<< ' ';  temp = temp->наступний;  } while (temp != голова);  } 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 == key && (*head)->next == *head) { free(*head);  *head = NULL;  повернення;  } Вузол *останній = *голова, *d;  // Якщо заголовок потрібно видалити if ((*head)->data == ключ) { // Знайти останній вузол списку while (last->next != *head) last = last->next;  // Вказати останній вузол на наступний // заголовок, тобто другий вузол // списку last->next = (*head)->next;  вільний (*голова);  *head = останній->наступний;  повернення;  } // Або вузол, який потрібно видалити // не знайдено, або кінець списку // не досягнуто, поки (last->next != *head && last->next->data != key) { last = last -> наступний;  } // Якщо вузол, який потрібно видалити, знайдено if (last->next->data == ключ) { d = last->next;  останній->наступний = d->наступний;  вільний(d);  } else 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 поштовх (&голова, 2);  push(&head, 5);  push(&head, 7);  push(&head, 8);  push(&head, 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->дані = дані;  ptr1->next = *head_ref;  // Якщо пов’язаний список не NULL, тоді // встановіть наступний з останніх вузол if (*head_ref != NULL) { // Знайдіть вузол перед заголовком і // оновіть наступний за ним.  struct Node* temp = *head_ref;  while (temp->next != *head_ref) temp = temp->next;  temp->next = ptr1;  } else // Для першого вузла ptr1->next = ptr1;  *head_ref = ptr1; } // Функція для друку вузлів у заданому // циклічному пов’язаному списку void printList(struct Node* head) { struct Node* temp = head;  if (head != NULL) { do { printf('%d ', temp->data);  temp = temp->next;  } while (temp != голова);  } printf('
'); } // Функція для видалення заданого вузла // зі списку void deleteNode(struct Node** head, int key) { // Якщо пов’язаний список порожній if (*head == NULL) return;  // Якщо список містить лише // один вузол if ((*head)->data == ключ && (*head)->next == *head) { free(*head);  *head = NULL;  повернення;  } struct Node *last = *head, *d;  // Якщо заголовок потрібно видалити if ((*head)->data == ключ) { // Знайти останній вузол списку while (last->next != *head) last = last->next;  // Вказати останній вузол на наступний // заголовок, тобто другий вузол // списку last->next = (*head)->next;  вільний (*голова);  *head = останній->наступний;  повернення;  } // Або вузол, який потрібно видалити // не знайдено, або кінець списку // не досягнуто, поки (last->next != *head && last->next->data != key) { last = last -> наступний;  } // Якщо вузол, який потрібно видалити, знайдено if (last->next->data == ключ) { d = last->next;  останній->наступний = d->наступний;  вільний(d);  } else printf('Даний вузол не знайдено в списку!!!
'); } // Код драйвера int main() { // Ініціалізувати списки як порожні struct Node* head = NULL;  // Створений пов’язаний список буде // 2->5->7->8->10 push(&head, 2);  push(&head, 5);  push(&head, 7);  push(&head, 8);  push(&head, 10);  printf('Список перед видаленням: ');  printList(голова);  deleteNode(&head, 7);  printf('Список після видалення: ');  printList(голова);  повернути 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 Поштовх (референтна голова, 2);  Push(голова посилання, 5);  Поштовх (голова посилання, 7);  Push(голова посилання, 8);  Поштовх (голова посилання, 10);  Console.Write('Список перед видаленням: ');  PrintList(голова);  DeleteNode(ref head, 7);  Console.Write('Список після видалення: ');  PrintList(голова);  } }>
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 head = push(head, 2);  head = push(head, 5);  head = push(head, 7);  head = push(head, 8);  head = push(head, 10);  console.log('Список перед видаленням: ');  printList(голова);  deleteNode(голова, 7);  console.log('Список після видалення: ');  printList(голова);>
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 head = push(head, 2) head = push(head, 5) head = push(head, 7) head = push(head, 8) head = push(head, 10) print('Список перед видаленням: ') printList(head) deleteNode(head, 7) print('Список після видалення: ') printList(head)>

Вихід
List Before Deletion: 10 8 7 5 2 List After Deletion: 10 8 5 2>

Часова складність: O(N), найгірший випадок виникає, коли елемент, який потрібно видалити, є останнім і нам потрібно перейти по всьому списку.
Допоміжний простір: O(1), як константа використовується додатковий простір.

Переваги циклічних пов’язаних списків:

  • Відправною точкою може бути будь-який вузол. Ми можемо пройти весь список, починаючи з будь-якої точки. Нам просто потрібно зупинитися, коли перший відвіданий вузол відвідується знову.
  • Корисно для реалізації черги. На відміну від це реалізації, нам не потрібно підтримувати два покажчики для переднього та заднього, якщо ми використовуємо круговий пов’язаний список. Ми можемо підтримувати вказівник на останній вставлений вузол, і фронт завжди можна отримати як наступний перед останнім.
  • Циркулярні списки корисні в програмах для повторного проходження списку. Наприклад, коли на комп’ютері запущено декілька програм, зазвичай операційна система поміщає запущені програми до списку, а потім циклічно переглядає їх, даючи кожній із них певний час для виконання, а потім змушуючи їх чекати, поки ЦП передається іншій програмі. Операційній системі зручно використовувати циклічний список, щоб, коли вона досягає кінця списку, вона могла циклічно повертатися до початку списку.
  • Циркулярні двозв’язані списки використовуються для реалізації розширених структур даних, таких як Купа Фібоначчі .
  • Реалізація циклічного пов’язаного списку може бути відносно легкою порівняно з іншими складнішими структурами даних, такими як дерева чи графіки.

Недоліки циклічного пов'язаного списку:

  • Порівняно з однозв’язаними списками циклічні списки складніші.
  • Перевернути циклічний список складніше, ніж одиночне або подвійне звернення циклічного списку.
  • Код може потрапити в нескінченний цикл, якщо з ним поводитися необережно.
  • Важче знайти кінець списку та контролювати цикл.
  • Хоча кругові пов’язані списки можуть бути ефективними в певних програмах, їх продуктивність може бути повільнішою, ніж інші структури даних у деяких випадках, наприклад, коли список потрібно відсортувати або виконати пошук.
  • Кругові пов’язані списки не забезпечують прямий доступ до окремих вузлів

Застосування циклічних пов’язаних списків:

  • Багатокористувацькі ігри використовують це, щоб дати кожному гравцеві можливість зіграти.
  • Кільцевий пов’язаний список можна використовувати для організації кількох запущених програм в операційній системі. Ці програми повторюються ОС.
  • Циркулярні зв'язані списки можна використовувати в задачах розподілу ресурсів.
  • Циркулярні пов’язані списки зазвичай використовуються для реалізації циклічних буферів,
  • Кругові пов’язані списки можна використовувати в симуляції та іграх.

Чому циклічний пов’язаний список?

  • Вузол завжди вказує на інший вузол, тому призначення NULL не є необхідним.
  • Початковою точкою може бути будь-який вузол.
  • Вузли швидко проходять від першого до останнього.

Наступні публікації: Циркулярний зв'язаний список | Набір 2 (обхід) Круговий однозв'язаний список | Вставка Будь ласка, напишіть коментарі, якщо ви виявите будь-яку помилку в коді/алгоритмі вище, або знайдіть інші способи вирішення тієї ж проблеми