Sluttnoden til en koblet liste som har en løkke vil referere til en annen node i samme liste i stedet for null.Hvis det er en node i en koblet liste som gjentatte ganger kan nås ved å følge neste peker, sies listen å ha en syklus.
Vanligvis refererer den koblede listens siste node til en nullhenvisning for å betegne listens konklusjon. Imidlertid, i en koblet liste med en loop, refererer sluttnoden til listen til en startnode, en intern node eller seg selv. Derfor må vi under slike omstendigheter identifisere og avslutte sløyfen ved å sette den neste nodens referanse til null. Deteksjonsdelen av løkken i en lenket liste er forklart i denne artikkelen.
I C ++ er det mange måter å finne løkker i en lenket liste:
Hash-tabellbasert tilnærming: Denne tilnærmingen lagrer adressene til besøkte noder i et hasjbord. En sløyfe i den koblede listen eksisterer hvis en node allerede er til stede i hasjbordet når den blir besøkt igjen.
Floyds syklus tilnærming: Algoritmen “Tortoise and Hare”. Den raskere pekeren vil til slutt overhale den langsommere pekeren hvis det er en sløyfe i den koblede listen, og avslører eksistensen av løkken.
Rekursiv metode: Denne metoden går gjennom den koblede listen ved å ringe seg om og om igjen. Den koblede listen inneholder en sløyfe hvis den gjeldende noden tidligere har blitt besøkt.
Stackbasert tilnærming: Denne tilnærmingen lagrer adressene til besøkte noder i en stabel. En sløyfe i den koblede listen er til stede hvis en node allerede er der i stabelen når den blir besøkt igjen.
La oss forklare hver tilnærming i detalj for å forstå konseptet.
Tilnærming 1: Hashset tilnærming
Å bruke hashing er den mest enkle metoden. Her går vi gjennom listen en etter en mens vi holder et hasjbord med nodeadressene. Derfor eksisterer en sløyfe hvis vi noen gang kjører over neste adresse til den gjeldende noden som allerede er inneholdt i hasjbordet. Ellers er det ingen sløyfe i den koblede listen hvis vi støter på null (i.e., nå slutten av den koblede listen).
Det vil være ganske enkelt å implementere denne strategien.
Mens vi krysser den koblede listen, bruker vi en uordnede_hashmap og fortsetter å legge til noder til den.
Når vi først kommer over en node som allerede er vist på kartet, vil vi vite at vi har kommet til Loops begynnelse.
Ved å gjøre dette, begynner sluttsløyfeknuten i stedet for å referere til sløyfens innledende node, å peke på null.
Hashing -metodens gjennomsnittlige tid og romkompleksitet er O (n). Leseren skal alltid være klar over at implementeringen av den innebygde hashingdatastrukturen i programmeringsspråket vil avgjøre den totale tidskompleksiteten i tilfelle en kollisjon i hashing.
C ++ programimplementering for metoden ovenfor (Hashset):
#inkludere
ved hjelp av navneområdet STD;
struct node
int verdi;
struct node* Neste;
;
Node* newNode (int -verdi)
Node* tempnode = ny node;
tempnode-> verdi = verdi;
tempnode-> neste = null;
return tempnode;
// identifisere og eliminere potensielle løkker
// i en koblet liste med denne funksjonen.
void FunctionHashMap (Node* HeadNode)
// opprettet et uordnede_map for å implementere hash -kart
uordnede_maphash_map;
// peker til lastnode
Node* lastNode = null;
mens (headnode != Null)
// Hvis en node mangler fra kartet, kan du legge den til.
if (hash_map.finn (headnode) == hash_map.slutt())
hash_map [headnode] ++;
lastNode = headnode;
headnode = headnode-> neste;
// Hvis en syklus er til stede, sett den endelige nodens neste peker til NULL.
annet
lastNode-> neste = null;
gå i stykker;
// Vis koblet liste
void display (node* headnode)
mens (headnode != Null)
coutheadnode = headnode-> neste;
cout << endl;
/* Hovedfunksjon*/
int main ()
Node* headnode = newNode (48);
headnode-> next = headnode;
headnode-> next = newNode (18);
headnode-> next-> next = newNode (13);
headnode-> next-> next-> next = newNode (2);
headnode-> next-> next-> next-> next = newNode (8);
/ * Lag en sløyfe i LinkedList */
headnode-> next-> next-> next-> next-> next = headnode-> next-> next;
funksjonHashMap (headnode);
printf ("Linked List Without Loop \ n");
display (headnode);
retur 0;
Produksjon:
Koblet liste uten loop
48 18 13 2 8
Kodenes trinn-for-trinn-forklaring er gitt nedenfor:
Tilnærming 2: Floyds syklus
Floyds syklusdeteksjonsalgoritme, ofte kjent som skilpadden og Hare -algoritmen, gir grunnlaget for denne metoden for å lokalisere sykluser i en lenket liste. Den "langsomme" pekeren og den "raske" pekeren, som krysser listen i forskjellige hastigheter, er de to pekerne som brukes i denne teknikken. Den raske pekeren avanserer to trinn, mens den langsomme pekeren fremmer ett trinn hver iterasjon. En syklus i den koblede listen eksisterer hvis de to punktene noen gang kommer ansikt til ansikt.
1. Med den koblede listenes hodeknute, initialiserer vi to tips som heter Fast and Slow.
2. Nå kjører vi en løkke for å bevege oss gjennom den koblede listen. Den raske pekeren skal flyttes to steder foran den langsomme pekeren på hver iterasjons trinn.
3. Det vil ikke være en sløyfe i den koblede listen hvis den raske pekeren når slutten av listen (FastPointer == null eller FastPointer-> neste == null). Hvis ikke, vil de raske og sakte pekerne til slutt møtes, noe som betyr at den koblede listen har en loop.
C ++ programimplementering for metoden ovenfor (Floyds syklus):
#inkludere
ved hjelp av navneområdet STD;
/ * Linkeliste node */
struct node
int -data;
struct node* Neste;
;
/* Funksjon for å fjerne sløyfe. */
void Deleteloop (struct Node*, struct Node*);
/* Denne funksjonen lokaliserer og eliminerer listeløkker. Det gir 1
Hvis det var en sløyfe i listen; ellers returnerer det 0. */
int detectandDeleteloop (struct node* list)
Struct Node *SlowPtr = liste, *FastPtr = liste;
// iterere for å sjekke om løkken er der.
while (slowPtr && fastPtr && fastPtr-> neste)
SlowPtr = SlowPtr-> Neste;
FastPtr = FastPtr-> Neste-> Neste;
/* Hvis SlowPtr og FastPtr møtes på et tidspunkt der
er en sløyfe */
if (slowPtr == fastPtr)
Deleteloop (SlowPtr, liste);
/* Retur 1 for å indikere at en sløyfe er blitt oppdaget. */
retur 1;
/* Retur 0 for å indikere at ingen sløyfe er blitt oppdaget.*/
retur 0;
/* Funksjon for å slette loop fra koblet liste.
Loopnode peker på en av sløyfeknuter og headnode peker
til startnoden på den koblede listen */
void Deleteloop (struct Node* loopnode, struct node* headnode)
struct node* ptr1 = loopnode;
struct node* ptr2 = loopnode;
// tell hvor mange noder som er i løkken.
usignert int k = 1, i;
mens (ptr1-> neste != ptr2)
ptr1 = ptr1-> neste;
K ++;
// fikse en peker til headnode
ptr1 = headnode;
// og den andre pekeren til K -noder etter headnode
ptr2 = headnode;
for (i = 0; i < k; i++)
ptr2 = ptr2-> neste;
/* Når begge punktene flyttes samtidig,
De vil kollidere ved sløyfens begynnende node. */
mens (PTR2 != ptr1)
ptr1 = ptr1-> neste;
ptr2 = ptr2-> neste;
// få nodens siste peker.
mens (ptr2-> neste != PTR1)
ptr2 = ptr2-> neste;
/* For å lukke sløyfen, sett den påfølgende
Node til sløyfens avsluttende node. */
ptr2-> neste = null;
/ * Funksjon for å vise koblet liste */
void displayLinkedList (struct node* node)
// Vis den koblede listen etter sletting av sløyfen
mens (node != Null)
cout node = node-> neste;
struct node* newnode (int tast)
struktur node* temp = ny node ();
temp-> data = nøkkel;
temp-> neste = null;
Retur Temp;
// Hovedkode
int main ()
struct node* headnode = newNode (48);
headnode-> next = newNode (18);
headnode-> next-> next = newNode (13);
headnode-> next-> next-> next = newNode (2);
headnode-> next-> next-> next-> next = newNode (8);
/ * Lag en sløyfe */
headnode-> next-> next-> next-> next-> next = headnode-> next-> next;
// Vis sløyfen i koblet liste
// displayLinkedList (headnode);
detectandDeleteloop (headnode);
cout << "Linked List after no loop \n";
displayLinkedList (headnode);
retur 0;
Produksjon:
Koblet liste etter ingen sløyfe
48 18 13 2 8
Forklaring:
Tilnærming 3: rekursjon
Rekursjon er en teknikk for å løse problemer ved å dele dem inn i mindre, enklere underproblemer. Rekursjon kan brukes til å krysse en enkelt koblet liste i tilfelle at en sløyfe blir funnet ved kontinuerlig å kjøre en funksjon for neste node i listen til listenes slutt er nådd.
I en enkelt koblet liste er det grunnleggende prinsippet bak ved bruk Den noden. Metoden vil iterere over den fulle koblede listen fordi den kalles rekursivt.
Listen inneholder en sløyfe hvis en node som tidligere er blitt merket som besøkt, blir møtt av funksjonen; I dette tilfellet kan funksjonen komme tilbake. Metoden kan returnere falsk hvis den når slutten av listen uten å løpe over en besøkt node, noe som indikerer at det ikke er noen sløyfe.
Selv om denne teknikken for å bruke rekursjon for å finne en sløyfe i en enkelt koblet liste er enkel å bruke og forstå, er det kanskje ikke den mest effektive når det gjelder tid og romkompleksitet.
C ++ programimplementering for metoden ovenfor (rekursjon):
#inkludere
ved hjelp av navneområdet STD;
struct node
int -data;
Node* Neste;
Bool besøkte;
;
// Linked List Loop Detection Function
bool detectlooplinkedlist (node* headnode)
if (headnode == null)
return falsk; // Hvis den koblede listen er tom, er den grunnleggende saken
// det er en sløyfe hvis den nåværende noden har
// allerede blitt besøkt.
if (headnode-> besøkt)
return True;
// Legg til et besøksmerke til den nåværende noden.
headnode-> besøkte = true;
// å ringe koden for den påfølgende noden gjentatte ganger
returdetektloplinkedlist (headnode-> neste);
int main ()
Node* headnode = new node ();
Node* SecondNode = new Node ();
Node* ThirdNode = New Node ();
headnode-> data = 1;
headnode-> next = SecondNode;
headnode-> besøkte = falsk;
SecondNode-> Data = 2;
SecondNode-> Next = ThirdNode;
SecondNode-> Besøkt = falsk;
ThirdNode-> Data = 3;
ThirdNode-> neste = null; // Ingen sløyfe
ThirdNode-> Besøkt = falsk;
if (detectLooplinkedList (headnode))
cout << "Loop detected in linked list" << endl;
annet
cout << "No loop detected in linked list" << endl;
// lage en løkke
ThirdNode-> Neste = SecondNode;
if (detectLooplinkedList (headnode))
cout << "Loop detected in linked list" << endl;
annet
cout << "No loop detected in linked list" << endl;
retur 0;
Produksjon:
Ingen sløyfe oppdaget i koblet liste
Loop oppdaget i koblet liste
Forklaring:
Tilnærming 4: Bruke stabel
Løkker i en lenket liste finner du ved hjelp av en stabel og metoden “Dybde-First Search” (DFS). Det grunnleggende konseptet er å iterere gjennom den koblede listen, skyve hver node på stabelen hvis den ikke allerede er besøkt. En sløyfe gjenkjennes hvis en node som allerede er på bunken, oppstår igjen.
Her er en kort beskrivelse av prosedyren:
C ++ programimplementering for metoden ovenfor (stabel)
#inkludere
#inkludere
ved hjelp av navneområdet STD;
struct node
int -data;
Node* Neste;
;
// Funksjon for å oppdage sløyfe i en koblet liste
bool detectlooplinkedlist (node* headnode)
stablestable;
Node* tempnode = headnode;
mens (tempnode != Null)
// Hvis det øverste elementet i stabelen stemmer overens
// Den gjeldende noden og stabelen er ikke tom
hvis (!stable.tom () && stabel.topp () == tempnode)
return True;
stable.push (tempnode);
tempnode = tempnode-> neste;
return falsk;
int main ()
Node* headnode = new node ();
Node* SecondNode = new Node ();
Node* ThirdNode = New Node ();
headnode-> data = 1;
headnode-> next = SecondNode;
SecondNode-> Data = 2;
SecondNode-> Next = ThirdNode;
ThirdNode-> Data = 3;
ThirdNode-> neste = null; // Ingen sløyfe
if (detectLooplinkedList (headnode))
cout << "Loop detected in linked list" << endl;
annet
cout << "No loop detected in linked list" << endl;
// lage en løkke
ThirdNode-> Neste = SecondNode;
if (detectLooplinkedList (headnode))
cout << "Loop detected in linked list" << endl;
annet
cout << "No loop detected in linked list" << endl;
Produksjon:
Ingen sløyfe oppdaget i koblet liste
Loop oppdaget i koblet liste
Forklaring:
Dette programmet bruker en stabel for å finne ut om en enkelt koblet liste har en loop.
2. Standard navneområdet er inkludert i den andre linjen, slik at vi får tilgang til input/output stream -bibliotekets funksjoner uten å måtte prefiksere dem med “STD ::.”
3. Følgende linje definerer strukturnoden, som består av to medlemmer: et heltall kalt “data” og en peker til en annen node kalt “Neste.”
4. Hodet til den koblede listen er en inngang for metoden detektloplinkedlist (), som er definert på neste linje. Funksjonen produserer en boolsk verdi som indikerer om det ble funnet en sløyfe eller ikke.
5. En bunke med nodekonkurranser kalt “Stack” og en peker til en node som heter “Tempnode” som initialiseres med verdien av headnode er begge opprettet inne i funksjonen.
6. Så, så lenge tempnode ikke er en nullpeker, legger vi inn en stund loop.
(a) Det øverste elementet i stabelen må samsvare med den nåværende noden for at vi skal bestemme at den ikke er tom. Vi returnerer sant hvis dette er tilfelle fordi en sløyfe er funnet.
(b) Hvis den nevnte tilstanden er falsk, skyves den gjeldende nodepekeren på bunken, og tempnode er satt til følgende node i den koblede listen.
7. Vi returnerer usant etter stundsløyfen fordi ingen sløyfe ble observert.
8. Vi bygger tre nodeobjekter og initialiserer dem i hovedfunksjonen (). Siden det ikke er noen sløyfe i det første eksemplet, setter vi "neste" pekere i hver node ordentlig.
Konklusjon:
Avslutningsvis avhenger den beste metoden for å oppdage løkker i en koblet liste av den spesifikke brukssaken og begrensningene i problemet. Hash-tabell og Floyds sykkelfinningsalgoritme er effektive metoder, og de er mye brukt i praksis. Stabel og rekursjon er mindre effektive metoder, men de er mer intuitive.