Circulair gekoppelde lijst: voor- en nadelen
โก Slimme samenvatting
Circulaire gekoppelde lijsten rangschikken knooppunten zo dat het laatste knooppunt terugverwijst naar het eerste, waardoor een continue, NULL-vrije structuur ontstaat die geschikt is voor round-robin-planning, tokenringen en elke workflow die naadloze doorloop vereist.
Wat is een circulair gekoppelde lijst?
Een circulaire gekoppelde lijst is een reeks knooppunten die zo zijn gerangschikt dat elk knooppunt opnieuw kan worden benaderd.tracnaar zichzelf. Elk "knooppunt" is een zelfverwijzend element met verwijzingen naar een of twee knooppunten in de directe omgeving.
Hieronder ziet u een afbeelding van een cirkelvormige gekoppelde lijst met 3 knooppunten.
Hier zie je dat elk knooppunt opnieuw wordt geladen.tracin staat om zichzelf te koppelen. Het bovenstaande voorbeeld is een circulaire enkelvoudig gekoppelde lijst.
Opmerking: De eenvoudigste circulaire gekoppelde lijst bestaat uit รฉรฉn knooppunt waarvan de volgende aanwijzer traces keert terug naar zichzelf, zoals hieronder weergegeven.
Basic Operaties in circulaire gekoppelde lijsten
De drie basisbewerkingen op een circulaire gekoppelde lijst zijn:
- Invoeging
- Verwijdering en
- traversal
- Invoegen is het proces waarbij een knooppunt op een specifieke positie in de circulair gekoppelde lijst wordt geplaatst.
- Verwijderen is het proces waarbij een bestaand knooppunt uit de gekoppelde lijst wordt verwijderd. Het knooppunt kan worden geรฏdentificeerd door het voorkomen van zijn waarde of door zijn positie.
- Het doorlopen van een circulaire gekoppelde lijst is het proces waarbij de volledige inhoud van de gekoppelde lijst wordt weergegeven en opnieuw wordt geรฏnterpreteerd.tracterugkeren naar het bronknooppunt.
In het volgende gedeelte wordt uitgelegd hoe invoegen werkt en welke twee soorten invoegingen mogelijk zijn in een circulaire, enkelvoudig gekoppelde lijst.
Invoeging Operatie
Je maakt eerst een knooppunt aan waarvan de volgende pointer terugwijst naar zichzelf, zoals hieronder weergegeven. Zonder dit startknooppunt wordt de eerste invoeging het eerste knooppunt in de lijst.
Vervolgens zijn er twee mogelijkheden:
- Invoegen op de huidige positie in de circulaire gekoppelde lijst. Dit komt overeen met invoegen aan het begin of het einde van een gewone enkelvoudig gekoppelde lijst; in een circulaire gekoppelde lijst zijn het begin en het einde hetzelfde punt.
- Invoeging na een geรฏndexeerd knooppunt. Het knooppunt moet worden geรฏdentificeerd door een indexnummer dat overeenkomt met de elementwaarde ervan.
Om een โโelement aan het begin of einde van de circulaire gekoppelde lijst in te voegen โ dat wil zeggen, op de positie waar het allereerste knooppunt werd toegevoegd โ volg je de onderstaande stappen:
- U zult de bestaande zelfkoppeling met het bestaande knooppunt moeten verbreken
- De volgende aanwijzer van het nieuwe knooppunt zal linken naar het bestaande knooppunt.
- De volgende aanwijzer van het laatste knooppunt wijst naar het ingevoegde knooppunt.
LET OP: De aanwijzer die het begin of einde van de cirkel markeert, kan aan elk willekeurig knooppunt worden toegewezen. Een doorloop zal nog steeds naar hetzelfde knooppunt terugkeren, zoals later in dit artikel wordt besproken.
De stappen in (a) i-iii worden hieronder weergegeven:
(Bestaand knooppunt)
Stap 1) Verbreek de bestaande link
Stap 2) Maak een voorwaartse link (van een nieuw knooppunt naar een bestaand knooppunt)
Stap 3) Maak een luskoppeling naar het eerste knooppunt
Vervolgens probeert u invoeging na een knooppunt.
Voeg bijvoorbeeld โVALUE2โ in na het knooppunt met โVALUE0โ, ervan uitgaande dat het startpunt het knooppunt met โVALUE0โ is.
- Verbreek de verbinding tussen het eerste en tweede knooppunt en plaats het knooppunt met "VALUE2" ertussen.
- De 'next'-pointer van het eerste knooppunt verwijst naar het nieuwe knooppunt, en de 'next'-pointer van het nieuwe knooppunt verwijst naar wat voorheen het tweede knooppunt was.
- De rest van de opstelling blijft ongewijzigd. Alle knooppunten worden opnieuw ingesteld.tracin staat om voor zichzelf te zorgen.
LET OP: Omdat de structuur cyclisch is, is de procedure voor het invoegen van een knooppunt identiek, ongeacht de gekozen positie. De aanwijzer die de cyclus sluit, gedraagt โโzich als elke andere aanwijzer in de lijst.
Dit wordt hieronder weergegeven:
(Laten we zeggen dat er maar twee knooppunten zijn. Dit is een triviaal geval)
Stap 1) Verwijder de binnenste link tussen de verbonden knooppunten
Stap 2) Verbind het linkerknooppunt met het nieuwe knooppunt
Stap 3) Verbind het nieuwe knooppunt met het rechterknooppunt.
Recht op verwijdering Operatie
Stel dat we een circulaire gelinkte lijst met 3 knooppunten hebben. De twee verwijderingsgevallen zijn:
- Het huidige element verwijderen
- Verwijdering na een element.
Verwijdering aan het begin/einde:
- Ga vanaf het laatste knooppunt naar het eerste knooppunt.
- Verwijderen vanaf het einde vereist slechts รฉรฉn doorloopstap, van het laatste knooppunt naar het eerste knooppunt.
- Verwijder de link tussen het laatste knooppunt en het eerste knooppunt.
- Koppel het laatste knooppunt aan het volgende element van het eerste knooppunt.
- Maak het eerste knooppunt vrij.
(Bestaande opstelling)
Stap 1) Verwijder de circulaire link
Stap 2) Verwijder de link tussen de eerste en de volgende, koppel het laatste knooppunt aan het knooppunt dat volgt op de eerste
Stap 3) De eerste node vrijgeven/dealloceren
Verwijderen na een knooppunt:
- Doorloop de lus totdat het volgende knooppunt het knooppunt is dat verwijderd moet worden.
- Ga naar het volgende knooppunt en plaats een aanwijzer op het vorige knooppunt.
- Verbind het vorige knooppunt met het knooppunt na het huidige knooppunt, met behulp van de volgende aanwijzer.
- Maak het huidige (ontkoppelde) knooppunt vrij.
Stap 1) Laten we zeggen dat we een knooppunt met 'VALUE1' moeten verwijderen.
Stap 2) Verwijder de link tussen het vorige knooppunt en het huidige knooppunt en verbind het vorige knooppunt vervolgens rechtstreeks met het knooppunt waarnaar de volgende aanwijzer van het huidige knooppunt wijst (het knooppunt na VALUE1).
Stap 3) Maak het huidige knooppunt vrij of maak de toewijzing ervan ongedaan.
Doorkruising van een circulair gekoppelde lijst
Om een โโcirculaire gelinkte lijst te doorlopen vanaf een pointer naar het laatste element, controleer je eerst of die pointer NULL is. Als dat niet het geval is, controleer je of de lijst slechts รฉรฉn element bevat. Zo niet, doorloop je de lijst dan met een tijdelijke pointer totdat je de pointer naar het laatste element weer bereikt, zoals in de onderstaande animatie te zien is.
Voordelen van circulair gekoppelde lijst
Enkele voordelen van circulair gekoppelde lijsten zijn:
- Geen vereiste voor een NULL-toewijzing in de code. De cirkelvormige lijst verwijst nooit naar een NULL-aanwijzer, tenzij de toewijzing volledig is opgeheven.
- Circulaire gekoppelde lijsten zijn voordelig voor bewerkingen aan het einde van de lijst, omdat het begin en het einde samenvallen. Algorithms Bij round-robin-planning kunnen processen in de wachtrij soepel worden verwerkt, zonder dat er zwevende of NULL-pointers worden tegengekomen.
- Een circulaire gekoppelde lijst ondersteunt nog steeds alle reguliere bewerkingen van een enkelvoudig gekoppelde lijst. dubbel gekoppelde lijst Het kan zelfs de noodzaak wegnemen om de hele lijst te doorlopen om een โโelement te vinden โ in het ergste geval bevindt het doel zich tegenover de startpointer, waardoor er maximaal de helft van de lijst hoeft te worden doorlopen.
Nadelen van circulair gekoppelde lijst
De nadelen van het gebruik van een circulair gekoppelde lijst zijn hieronder:
- Cirkelvormige lijsten zijn complexer dan enkelvoudig gelinkte lijsten.
- RevHet omkeren van een circulaire lijst is complexer dan het omkeren van een enkelvoudig of dubbelvoudig gekoppelde lijst.
- Als de beรซindiging van een lus niet zorgvuldig wordt afgehandeld, kan de doorloopcode in een oneindige lus terechtkomen.
- Het is lastiger om het einde van de lijst te vinden en de juiste lusbesturingsvoorwaarden te schrijven.
- Het invoegen aan het begin vereist (vanuit implementatieperspectief) het doorlopen van de hele lijst om het laatste knooppunt te bereiken.
Enkelvoudig gekoppelde lijst als circulair gekoppelde lijst
U wordt aangemoedigd de onderstaande C-code te lezen en te implementeren. Deze code illustreert de pointer-rekenkunde die hoort bij een circulaire enkelvoudig gekoppelde lijst.
#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() { ...
Toelichting code:
- De eerste twee regels code zijn de noodzakelijke meegeleverde headerbestanden.
- In het volgende gedeelte wordt de structuur van elk zelfverwijzend knooppunt gedefinieerd. Het bevat een waarde en een aanwijzer van hetzelfde type als de structuur.
- Elke structuurinstantie is gekoppeld aan andere structuurobjecten van hetzelfde type.
- Er zijn verschillende functieprototypes voor:
- Een element toevoegen aan een lege gekoppelde lijst
- Invoegen bij de momenteel gericht positie van een circulair gekoppelde lijst.
- Invoegen na een bepaalde geรฏndexeerd waarde in de gekoppelde lijst.
- Verwijderen/verwijderen na een bepaalde geรฏndexeerd waarde in de gekoppelde lijst.
- Verwijderen op de momenteel aangewezen positie van een cirkelvormig gekoppelde lijst
- De laatste functie drukt elk element af via een cirkelvormige doorgang in elke status van de gekoppelde lijst.
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)
Toelichting code:
- Voor de addToEmpty-code moet je een lege node toewijzen met behulp van de malloc()-functie.
- Plaats de binnenkomende gegevens in het tijdelijke knooppunt.
- Wijs het tijdelijke knooppunt als laatste toe en stel de volgende aanwijzer ervan in op zichzelf, zodat het enkele knooppunt weer naar zichzelf wijst.
- Geef de laatste pointer terug naar de main() / applicatiecontext.
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; …
Uitleg van code
- Als de lijst leeg is, geef dan de controle door aan addToEmpty() en geef de controle terug.
- Maak een tijdelijk knooppunt aan dat na het huidige knooppunt wordt geplaatst.
- Verbind de aanwijzers zoals weergegeven in het bovenstaande diagram.
- Retourneer de laatste pointer die overeenkomt met het patroon dat in de vorige functie is gebruikt.
... 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"); ...
Toelichting code:
- Als de lijst leeg is, negeer dan de zoekterm, voeg het huidige item toe als enige element in de lijst en geef de controle terug.
- In elke iteratie van de do-while-lus bevat een pointer naar de vorige waarde het laatst doorlopen resultaat.
- Pas dan vindt de volgende doorloopstap plaats.
- De do-while-lus eindigt wanneer de doelgegevens zijn gevonden of wanneer temp de laatste pointer weer bereikt. Het volgende codeblok bepaalt wat er met het gevonden item moet gebeuren.
...
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)
...
Toelichting code:
- Als de hele lijst is doorlopen maar het item niet is gevonden, toon dan de melding "Element niet gevonden" en geef de controle terug aan de aanroeper.
- Als het doelknooppunt is gevonden, wijs dan een nieuw knooppunt toe voor de in te voegen waarde.
- Link De pointer van het vorige knooppunt naar het nieuwe knooppunt koppelen, en de pointer van het nieuwe knooppunt naar 'next' verbinden met 'temp' (de traverseringsvariabele).
- Hierdoor wordt het nieuwe element direct na het doelknooppunt in de circulaire gekoppelde lijst geplaatst. De controle keert vervolgens terug naar de aanroeper.
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)
Uitleg van code
- Om het laatste (huidige) knooppunt te verwijderen, moet je eerst controleren of de lijst leeg is. Zo ja, dan kan er geen element worden verwijderd.
- De tijdelijke variabele schuift รฉรฉn schakel verder.
- Verbind de laatste aanwijzer met het knooppunt na het eerste knooppunt.
- Maak de tijdelijke pointer vrij om het niet-gekoppelde knooppunt te dealloceren.
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"); ...
Uitleg van code
- Net als bij de vorige verwijderingsfunctie, controleer eerst of de lijst leeg is. Zo ja, dan kan er geen element worden verwijderd.
- Twee pointers krijgen specifieke posities toegewezen om het te verwijderen element te lokaliseren.
- De aanwijzers worden รฉรฉn voor รฉรฉn vooruitgeschoven (vorige trails temp).
- De doorloop gaat door totdat het doelelement is gevonden of de volgende aanwijzer het laatste knooppunt weer bereikt.
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;
Uitleg programma
- Als de volledige gekoppelde lijst wordt doorlopen zonder het doel te vinden, wordt de melding "Element niet gevonden" weergegeven.
- Anders wordt het element in stap 3 en 4 ontkoppeld en vrijgegeven.
- De vorige pointer is gekoppeld aan het knooppunt waarnaar de volgende pointer van temp wijst (het knooppunt na het knooppunt dat wordt verwijderd).
- De tijdelijke aanwijzer wordt vervolgens vrijgegeven.
... 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; } }
Uitleg van code
- De peek-traversal is niet mogelijk als er nul knooppunten zijn; de gebruiker moet eerst een knooppunt toewijzen of invoegen.
- Als er maar รฉรฉn knooppunt is, is er geen doorloop nodig โ de inhoud van het knooppunt wordt direct afgedrukt en de while-lus wordt niet uitgevoerd.
- Als er meer dan รฉรฉn knooppunt is, print temp elk item tot en met het laatste element.
- Zodra het laatste element is bereikt, eindigt de lus en geeft de functie de controle terug aan main().
Toepassingen van de Circular Linked List
- Implementatie van round-robin planning in systeemprocessen en circulaire planning in high-speed graphics.
- Token-ring planning in computernetwerken.
- Gebruikt in weergave-eenheden zoals digitale winkelborden die een continue gegevensstroom vereisen.





























