Circular Linked List: Výhody a nevýhody

Co je kruhový propojený seznam?

Kruhový propojený seznam je posloupnost uzlů uspořádaných tak, že každý uzel lze vyhledat sám k sobě. Zde je „uzel“ sebereferenční prvek s ukazateli na jeden nebo dva uzly v jeho bezprostřední blízkosti.

Níže je znázorněn kruhový propojený seznam se 3 uzly.

Kruhový propojený seznam

Zde můžete vidět, že každý uzel je zpětně dohledatelný. Výše uvedený příklad je kruhový jednotlivě propojený seznam.

Poznámka: Nejjednodušší kruhový propojený seznam je uzel, který sleduje pouze sebe, jak je znázorněno

Kruhový propojený seznam

Basic Operav kruhových propojených seznamech

Základní operace na kruhovém propojeném seznamu jsou:

  1. Vložení
  2. Vymazání a
  3. Traverz
  • Vkládání je proces umístění uzlu na určené místo v kruhovém propojeném seznamu.
  • Odstranění je proces odstranění existujícího uzlu z propojeného seznamu. Uzel lze identifikovat podle výskytu jeho hodnoty nebo podle jeho polohy.
  • Procházení kruhového propojeného seznamu je proces zobrazení obsahu celého propojeného seznamu a návrat zpět ke zdrojovému uzlu.

V další části porozumíte vkládání uzlu a typům vložení možného do kruhového seznamu s jediným odkazem.

Vložení Operavání

Zpočátku musíte vytvořit jeden uzel, který ukazuje na sebe, jak je znázorněno na tomto obrázku. Bez tohoto uzlu vytvoří vložení první uzel.

Vložení Operavání

Dále jsou dvě možnosti:

  • Vložení na aktuální pozici kruhového propojeného seznamu. To odpovídá vložení na začátek konce běžného spojovaného seznamu v jednotném čísle. V kruhovém propojeném seznamu jsou začátek a konec stejné.
  • Vložení za indexovaný uzel. Uzel by měl být identifikován indexovým číslem odpovídajícím jeho hodnotě prvku.

Pro vložení na začátek/konec kruhového propojeného seznamu, tedy na pozici, kde byl přidán vůbec první uzel,

  • Budete muset přerušit stávající vlastní propojení se stávajícím uzlem
  • Další ukazatel nového uzlu se propojí se stávajícím uzlem.
  • Další ukazatel posledního uzlu bude ukazovat na vložený uzel.

POZNÁMKA: Ukazatel, který je token master nebo začátek/konec kruhu, lze změnit. Stále se bude vracet do stejného uzlu při procházení, o kterém bude diskutováno dopředu.

Kroky v (a) i-iii jsou uvedeny níže:

Vložení Operavání

(Stávající uzel)

Vložení Operavání

KROK 1) Přerušte stávající odkaz

Vložení Operavání

KROK 2) Vytvořit dopředný odkaz (z nového uzlu na existující uzel)

Vložení Operavání

KROK 3) Vytvořte smyčkový odkaz na první uzel

Dále vyzkoušíte vložení za uzel.

Například vložme „VALUE2“ za uzel s „VALUE0“. Předpokládejme, že výchozím bodem je uzel s „VALUE0“.

  • Budete muset přerušit čáru mezi prvním a druhým uzlem a umístit uzel s „VALUE2“ mezi.
  • Další ukazatel prvního uzlu musí odkazovat na tento uzel a další ukazatel tohoto uzlu se musí propojovat s předchozím druhým uzlem.
  • Zbytek uspořádání zůstává nezměněn. Všechny uzly jsou zpětně dohledatelné.

POZNÁMKA: Protože existuje cyklické uspořádání, vkládání uzlu zahrnuje stejný postup pro jakýkoli uzel. Ukazatel, který dokončí cyklus, dokončí cyklus stejně jako jakýkoli jiný uzel.

Toto je zobrazeno níže:

Vložení Operavání

(Řekněme, že existují pouze dva uzly. Toto je triviální případ)

Vložení Operavání

KROK 1) Odstraňte vnitřní spoj mezi připojenými uzly

Vložení Operavání

KROK 2) Připojte uzel na levé straně k novému uzlu

Vložení Operavání

KROK 3) Připojte nový uzel k uzlu na pravé straně.

vymazání Operavání

Předpokládejme 3-uzlový kruhový propojený seznam. Níže jsou uvedeny případy smazání:

  • Odstranění aktuálního prvku
  • Smazání po prvku.

Smazání na začátku/konci:

  1. Přechod k prvnímu uzlu z posledního uzlu.
  2. Chcete-li odstranit od konce, měl by existovat pouze jeden krok procházení, od posledního uzlu k prvnímu uzlu.
  3. Odstraňte propojení mezi posledním uzlem a dalším uzlem.
  4. Propojte poslední uzel s dalším prvkem prvního uzlu.
  5. Uvolněte první uzel.

vymazání Operavání

(Stávající nastavení)

vymazání Operavání

KROK 1) Odstraňte kruhový článek

vymazání Operavání

KROK 2) Odstraňte spojení mezi prvním a dalším, propojte poslední uzel s uzlem následujícím po prvním

vymazání Operavání

KROK 3) Uvolněte / uvolněte první uzel

Smazání po uzlu:

  1. Přejděte do dalšího uzlu, který má být odstraněn.
  2. Přejděte k dalšímu uzlu a umístěte ukazatel na předchozí uzel.
  3. Připojte předchozí uzel k uzlu za aktuálním uzlem pomocí jeho dalšího ukazatele.
  4. Uvolněte aktuální (odpojený) uzel.

vymazání Operavání

KROK 1) Řekněme, že potřebujeme odstranit uzel s „VALUE1“.

vymazání Operavání

KROK 2) Odstraňte propojení mezi předchozím a aktuálním uzlem. Propojte jeho předchozí uzel s dalším uzlem, na který ukazuje aktuální uzel (s VALUE1).

vymazání Operavání

KROK 3) Uvolněte nebo uvolněte aktuální uzel.

Procházení kruhového propojeného seznamu

Chcete-li procházet kruhový propojený seznam, počínaje posledním ukazatelem, zkontrolujte, zda je samotný poslední ukazatel NULL. Pokud je tato podmínka nepravdivá, zkontrolujte, zda existuje pouze jeden prvek. Jinak procházejte pomocí dočasného ukazatele, dokud znovu nedosáhnete posledního ukazatele, nebo tolikrát, kolikrát je potřeba, jak je znázorněno na obrázku níže.

Procházení kruhového propojeného seznamu

Výhody kruhového propojeného seznamu

Některé z výhod kruhových propojených seznamů jsou:

  1. Žádný požadavek na přiřazení NULL v kódu. Kruhový seznam nikdy neukazuje na ukazatel NULL, pokud není plně uvolněn.
  2. Kruhové propojené seznamy jsou výhodné pro koncové operace, protože začátek a konec se shodují. Algorithms jako je plánování Round Robin může úhledně eliminovat procesy, které jsou ve frontě kruhovým způsobem, aniž by se setkaly s visícími nebo referenčními ukazateli NULL.
  3. Kruhový propojený seznam také provádí všechny běžné funkce jednoduše propojeného seznamu. Ve skutečnosti kruhový dvojitě propojené seznamy Popsaný níže může dokonce eliminovat potřebu procházení po celé délce k nalezení prvku. Tento prvek by byl nanejvýš přesně opačný než začátek a dokončil by jen polovinu propojeného seznamu.

Nevýhody kruhového propojeného seznamu

Nevýhody použití kruhového propojeného seznamu jsou níže:

  1. Kruhové seznamy jsou ve srovnání s jednotlivě propojené seznamy.
  2. RevJiný kruhový seznam je ve srovnání s jednoduchými nebo dvojitými seznamy složitý.
  3. Pokud se s ním nezachází opatrně, může se kód pohybovat v nekonečné smyčce.
  4. Je těžší najít konec seznamu a ovládání smyčky.
  5. Při vkládání na Start musíme projít celý seznam, abychom našli poslední uzel. (perspektiva implementace)

Jednotlivě propojený seznam jako kruhový propojený seznam

Doporučujeme vám pokusit se přečíst a implementovat níže uvedený kód. Představuje aritmetiku ukazatele spojenou s kruhovými propojenými seznamy.

#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()
{
...

Jednotlivě propojený seznam

Vysvětlení kódu:

  1. První dva řádky kódu jsou nezbytné zahrnuté hlavičkové soubory.
  2. Další část popisuje strukturu každého autoreferenčního uzlu. Obsahuje hodnotu a ukazatel stejného typu jako struktura.
  3. Každá struktura opakovaně odkazuje na objekty struktury stejného typu.
  4. Existují různé funkční prototypy pro:
    1. Přidání prvku do prázdného propojeného seznamu
    2. Vkládání na aktuálně ukázal pozice kruhového propojeného seznamu.
    3. Vkládání za konkrétní indexován hodnotu v propojeném seznamu.
    4. Odstranění/smazání po určitém indexován hodnotu v propojeném seznamu.
    5. Odstranění na aktuálně vytyčené pozici kruhového propojeného seznamu
  5. Poslední funkce vytiskne každý prvek kruhovým průchodem v libovolném stavu propojeného seznamu.
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)

Jednotlivě propojený seznam

Vysvětlení kódu:

  1. Pro kód addEmpty přidělte prázdný uzel pomocí funkce malloc.
  2. Pro tento uzel umístěte data do proměnné temp.
  3. Přiřaďte a propojte jedinou proměnnou s proměnnou temp
  4. Vraťte poslední prvek do kontextu main() / aplikace.
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;
…

Jednotlivě propojený seznam

Vysvětlení kódu

  1. Pokud neexistuje žádný prvek k vložení, měli byste se ujistit, že jste přidali do prázdného seznamu a vrátili ovládací prvek.
  2. Vytvořte dočasný prvek, který se umístí za aktuální prvek.
  3. Propojte ukazatele podle obrázku.
  4. Vraťte poslední ukazatel jako v předchozí funkci.
...
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");
...

Jednotlivě propojený seznam

Vysvětlení kódu:

  1. Pokud v seznamu není žádný prvek, ignorujte data, přidejte aktuální položku jako poslední položku v seznamu a vraťte kontrolu
  2. Pro každou iteraci ve smyčce do-while se ujistěte, že existuje předchozí ukazatel, který obsahuje výsledek posledního procházení.
  3. Teprve poté může dojít k dalšímu průchodu.
  4. Pokud jsou data nalezena nebo teplota dosáhne posledního ukazatele, do-while se ukončí. Další část kódu rozhodne, co je třeba s položkou udělat.
...
    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)
...

Jednotlivě propojený seznam

Vysvětlení kódu:

  1. Pokud byl projet celý seznam, ale položka nebyla nalezena, zobrazte zprávu „položka nenalezena“ a poté vraťte řízení volajícímu.
  2. Pokud je nalezen uzel a/nebo uzel ještě není posledním uzelem, vytvořte nový uzel.
  3. Odkaz předchozí uzel s novým uzlem. Propojte aktuální uzel s temp (proměnná traversal).
  4. To zajistí, že prvek bude umístěn za určitým uzlem v kruhovém propojeném seznamu. Vraťte se k volajícímu.
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)

Jednotlivě propojený seznam

Vysvětlení kódu

  1. Chcete-li odstranit pouze poslední (aktuální) uzel, zkontrolujte, zda je tento seznam prázdný. Pokud ano, nelze odstranit žádný prvek.
  2. Proměnná temp pouze prochází o jeden odkaz vpřed.
  3. Propojte poslední ukazatel s ukazatelem po prvním.
  4. Uvolněte ukazatel teploty. Uvolní nepřipojený poslední ukazatel.
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");
...

Jednotlivě propojený seznam

Vysvětlení kódu

  1. Stejně jako u předchozí funkce odstranění zkontrolujte, zda tam není žádný prvek. Pokud je to pravda, nelze odstranit žádný prvek.
  2. Pointers jsou přiřazeny konkrétní pozice k nalezení prvku, který má být odstraněn.
  3. Ukazatele jsou posunuty dopředu, jeden za druhým. (předchozí za teplotou)
  4. Proces pokračuje, dokud není nalezen prvek nebo dokud se další prvek nevrátí k poslednímu ukazateli.
    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;	

Jednotlivě propojený seznam

Vysvětlení programu

  1. Pokud byl prvek nalezen po procházení celého propojeného seznamu, zobrazí se chybová zpráva, že položka nebyla nalezena.
  2. Jinak se prvek odpojí a uvolní v krocích 3 a 4.
  3. Předchozí ukazatel je spojen s adresou označenou jako „další“ prvkem, který má být odstraněn (temp).
  4. Ukazatel teploty je proto uvolněn a uvolněn.
...
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;
    }
}

Jednotlivě propojený seznam

Vysvětlení kódu

  1. Nahlédnutí nebo procházení není možné, pokud je potřeba nula. Uživatel potřebuje alokovat nebo vložit uzel.
  2. Pokud existuje pouze jeden uzel, není třeba procházet, obsah uzlu lze vytisknout a smyčka while se neprovede.
  3. Pokud je více než jeden uzel, pak temp vytiskne všechny položky až do posledního prvku.
  4. V okamžiku dosažení posledního prvku se smyčka ukončí a funkce vrátí volání hlavní funkce.

Aplikace Circular Linked List

  • Implementace kruhového plánování v systémových procesech a kruhového plánování ve vysokorychlostní grafice.
  • Plánování token ringů v počítačových sítích.
  • Používá se v zobrazovacích jednotkách, jako jsou obchodní tabule, které vyžadují nepřetržité procházení dat.