Der Endknoten einer verknüpften Liste mit einer Schleife bezieht sich eher auf einen anderen Knoten in derselben Liste als auf den Null.Wenn sich in einer verknüpften Liste einen Knoten befindet, auf den durch den nächsten Zeiger wiederholt zugegriffen werden kann, soll die Liste einen Zyklus haben.
In der Regel bezieht sich der letzte Knoten der verknüpften Liste auf einen Null -Verweis, um die Schlussfolgerung der Liste zu bezeichnen. In einer verknüpften Liste mit einer Schleife bezieht sich der Endknoten der Liste jedoch auf einen Startknoten, einen internen Knoten oder sich selbst. Unter solchen Umständen müssen wir daher die Schleife identifizieren und beenden, indem wir den Hinweis des nächsten Knotens auf NULL festlegen. Der Erkennungsanteil der Schleife in einer verknüpften Liste wird in diesem Artikel erläutert.
In C ++ gibt es zahlreiche Möglichkeiten, Schleifen in einer verknüpften Liste zu finden:
Hash-Tabellenansatz: Dieser Ansatz speichert die Adressen besuchter Knoten in einer Hash -Tabelle. Eine Schleife in der verknüpften Liste gibt es, wenn ein Knoten bereits in der Hash -Tabelle vorhanden ist, wenn er erneut besucht wird.
Floyds Zyklusansatz: Der Algorithmus „Tortoise and Hase“, allgemein bekannt als Floyds Zyklus-Finding-Algorithmus: Diese Technik verwendet zwei Zeiger, die sich langsamer bewegt als der andere und der andere sich schneller bewegt. Der schnellere Zeiger überholt letztendlich den langsameren Zeiger, wenn in der verlinkten Liste eine Schleife vorhanden ist und die Existenz der Schleife enthüllt.
Rekursive Methode: Diese Methode durchläuft die verknüpfte Liste, indem er sich immer und immer wieder anruft. Die verknüpfte Liste enthält eine Schleife, wenn der aktuelle Knoten zuvor besucht wurde.
Stackbasierter Ansatz: Dieser Ansatz speichert die Adressen besuchter Knoten in einem Stapel. Eine Schleife in der verlinkten Liste ist vorhanden, wenn ein Knoten bereits im Stapel vorhanden ist, wenn er erneut besucht wird.
Lassen Sie uns jeden Ansatz im Detail erläutern, um das Konzept zu verstehen.
Ansatz 1: Hashset -Ansatz
Die Verwendung von Hashing ist die einfachste Methode. Hier gehen wir die Liste einzeln durch, während wir eine Hash -Tabelle mit den Knotenadressen behalten. Daher existiert eine Schleife, wenn wir jemals die nächste Adresse des aktuellen Knotens begeben haben, der bereits in der Hash -Tabelle enthalten ist. Andernfalls gibt es in der verlinkten Liste keine Schleife, wenn wir auf NULL begegnen (ich.e., Erreichen Sie das Ende der verlinkten Liste).
Es wird ziemlich einfach sein, diese Strategie umzusetzen.
Während des Durchquerens der verknüpften Liste werden wir eine nicht ordnungsgemäße_hashmap verwenden und weiterhin Knoten dazu hinzufügen.
Wenn wir jetzt auf einen Knoten gestoßen sind, der bereits auf der Karte angezeigt wird, werden wir wissen, dass wir am Anfang der Schleife angekommen sind.
Auf diese.
Die durchschnittliche Zeit und die Raumkomplexität der Hashing -Methode sind O (N). Der Leser sollte immer bekannt sein.
C ++ -Programmimplementierung für die obige Methode (Hashset):
#enthalten
Verwenden von Namespace STD;
Strukturknoten
int Wert;
Strukturknoten* Weiter;
;
Knoten* NewNode (int -Wert)
Node* tempnode = neuer Knoten;
tempnode-> value = value;
tempnode-> next = null;
Tempnode zurückgeben;
// potenzielle Schleifen identifizieren und beseitigen
// in einer verknüpften Liste mit dieser Funktion.
void FunctionHasMap (Knoten* Headnode)
// Erstellte eine nicht ordnungsgemäße MAP, um die Hash -Karte zu implementieren
Under Ordered_mapHash_map;
// Zeiger auf Nachnode
Node* lastnode = null;
während (Headnode != Null)
// Wenn in der Karte ein Knoten fehlt, fügen Sie ihn hinzu.
if (hash_map.Finden Sie (Headnode) == Hash_Map.Ende())
Hash_map [Headnode] ++;
Nachnode = headnode;
headnode = headnode-> Weiter;
// Wenn ein Zyklus vorhanden ist, setzen Sie den nächsten Zeiger des letzten Knotens auf NULL.
anders
LastNode-> next = null;
brechen;
// Die verknüpfte Liste anzeigen
Hohlraumanzeige (Knoten* Headnode)
während (Headnode != Null)
Coutheadnode = headnode-> Weiter;
Cout << endl;
/* Hauptfunktion*/
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);
/ * Erstellen Sie eine Schleife in LinkedList */
Headnode-> Weiter-> Weiter-> Weiter-> Weiter-> Next = Headnode-> Weiter-> Weiter;
FunctionHasMap (Headnode);
printf ("verknüpfte Liste ohne Schleife \ n");
Anzeige (Headnode);
Rückkehr 0;
Ausgang:
Verlinkte Liste ohne Schleife
48 18 13 2 8
Die Schritt-für-Schritt-Erklärung des Code wird unten angegeben:
Ansatz 2: Floyds Zyklus
Der Floyd -Zykluserkennungsalgorithmus, der häufig als Schildkröte und Hare -Algorithmus bekannt ist. Der „langsame“ Zeiger und der „schnelle“ Zeiger, der die Liste mit verschiedenen Geschwindigkeiten durchquert, sind die beiden in dieser Technik verwendeten Zeiger. Der schnelle Zeiger steigt zwei Schritte vor, während der langsame Zeiger bei jeder Iteration einen Schritt voranschreitet. Ein Zyklus in der verknüpften Liste gibt es, wenn die beiden Punkte jemals gegenüberstehen.
1. Mit dem Kopfknoten der verknüpften Liste der Linksliste haben wir zwei Zeiger, die schnell und langsam bezeichnet werden.
2. Jetzt führen wir eine Schleife aus, um die verknüpfte Liste durchzusetzen. Der schnelle Zeiger sollte zwei Stellen vor dem langsamen Zeiger bei den Schritt jeder Iteration bewegt werden.
3. In der verknüpften Liste wird keine Schleife vorhanden, wenn der schnelle Zeiger das Ende der Liste erreicht (FastPointer == NULL oder FASTPOINGER-> NEXT == NULL). Wenn nicht, treffen sich die schnellen und langsamen Zeiger irgendwann, was bedeutet, dass die verknüpfte Liste eine Schleife hat.
C ++ - Programmimplementierung für die obige Methode (Floyds Zyklus):
#enthalten
Verwenden von Namespace STD;
/ * Linklistenknoten *//
Strukturknoten
int Daten;
Strukturknoten* Weiter;
;
/* Funktion zum Entfernen der Schleife. */
Hohlraum Deleteloop (Struct Node*, Struct Node*);
/* Diese Funktion lokalisiert und beseitigt Listenschleifen. Es ergibt 1
Wenn es in der Liste eine Schleife gab; sonst gibt es 0 zurück. */
int detectandDeleteloop (Struct Node* -Liste)
struct node *Slowptr = list, *fastptr = list;
// iterieren, um zu überprüfen, ob die Schleife vorhanden ist.
while (Slowptr && fastptr && fastptr-> Weiter)
Slowptr = Slowptr-> Weiter;
fastptr = fastptr-> Weiter-> Weiter;
/* Wenn sich Slowptr und Fastptr irgendwann treffen, dann gibt es dort
ist eine Schleife */
if (Slowptr == Fastptr)
DeletEloop (Slowptr, Liste);
/* Rückkehr 1, um anzuzeigen, dass eine Schleife entdeckt wurde. */
Rückkehr 1;
/* Kehren Sie 0 zurück, um anzuzeigen, dass keine Schleife entdeckt wurde.*/
Rückkehr 0;
/* Funktion zum Löschen der Schleife aus der verknüpften Liste.
Loopnode zeigt auf einen der Schleifenknoten und Headnode zeigt
zum Startknoten der verknüpften Liste */
Hohlraum Deleteloop (Struct Node* Loopnode, Struct Node* Headnode)
struct node* ptr1 = Loopnode;
struct node* ptr2 = Loopnode;
// Zählen Sie, wie viele Knoten sich in der Schleife befinden.
nicht signiert int k = 1, i;
während (PTR1-> Weiter != ptr2)
PTR1 = PTR1-> Weiter;
K ++;
// einen Zeiger auf Headnode reparieren
ptr1 = headnode;
// und der andere Zeiger auf K -Knoten nach Headnode
ptr2 = headnode;
für (i = 0; i < k; i++)
PTR2 = PTR2-> Weiter;
/* Wenn beide Punkte gleichzeitig bewegt werden,
Sie werden am Anfangsknoten der Schleife kollidieren. */
while (ptr2 != ptr1)
PTR1 = PTR1-> Weiter;
PTR2 = PTR2-> Weiter;
// Erhalten Sie den letzten Zeiger des Knotens.
während (PTR2-> Weiter != ptr1)
PTR2 = PTR2-> Weiter;
/* Um die Schleife zu schließen, setzen Sie die nachfolgende
Knoten zum Schlaufe -Schließknoten. */
ptr2-> next = null;
/ * Funktion zur Anzeige der verknüpften Liste *//
void displaylinkedList (Struct Node* Knoten)
// Zeigen Sie die verknüpfte Liste nach dem Löschen der Schleife an
während (Knoten != Null)
Cout node = node-> Weiter;
Struct Node* NewNode (intschlüssel)
struct node* temp = new node ();
temp-> data = key;
temp-> next = null;
Temperatur zurückgeben;
// Haupt code
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);
/ * Erstellen Sie eine Schleife *////
Headnode-> Weiter-> Weiter-> Weiter-> Weiter-> Next = Headnode-> Weiter-> Weiter;
// Zeigen Sie die Schleife in verknüpfter Liste an
// DisplayLinkedList (Headnode);
DETECTANDDELTELOOP (HEADNODE);
Cout << "Linked List after no loop \n";
DisplayLinkedList (Headnode);
Rückkehr 0;
Ausgang:
Verlinkte Liste nach keiner Schleife
48 18 13 2 8
Erläuterung:
Ansatz 3: Rekursion
Rekursion ist eine Technik zur Lösung von Problemen, indem sie in kleinere, einfachere Unterprobleme aufgeteilt werden. Rekursion kann verwendet werden, um eine einzig verknüpfte Liste zu durchqueren, falls eine Schleife durch kontinuierlich eine Funktion für den nächsten Knoten in der Liste erfolgt, bis das Ende der Liste erreicht ist.
In einer einzig verknüpften Liste besteht das grundlegende Prinzip hinter der Verwendung von Rekursion, um eine Schleife zu finden dieser Knoten. Die Methode wird die vollständige verknüpfte Liste durchführen, da sie rekursiv bezeichnet wird.
Die Liste enthält eine Schleife, wenn ein Knoten, der zuvor als Besuch gekennzeichnet wurde, von der Funktion auftritt. In diesem Fall kann die Funktion wahr zurückkehren. Die Methode kann False zurückgeben, wenn sie das Ende der Liste erreicht, ohne über einen besuchten Knoten zu laufen, was darauf hinweist, dass es keine Schleife gibt.
Obwohl diese Technik zur Verwendung von Rekursion zum Finden einer Schleife in einer einzigen verknüpften Liste einfach zu verwenden und zu verstehen ist, ist sie in Bezug auf Zeit und Raumkomplexität möglicherweise nicht die effektivste.
C ++ -Programmimplementierung für die obige Methode (Rekursion):
#enthalten
Verwenden von Namespace STD;
Strukturknoten
int Daten;
Knoten* Weiter;
bool besucht;
;
// verknüpfte Listenschleife Erkennungsfunktion
bool detectlooplinkedList (Knoten* Headnode)
if (headnode == null)
falsch zurückgeben; // Wenn die verknüpfte Liste leer ist, der Grundfall
// Es gibt eine Schleife, wenn der aktuelle Knoten hat
// bereits besucht worden.
if (headnode-> besucht)
zurückkehren;
// Fügen Sie dem aktuellen Knoten eine Besuchsmarke hinzu.
Headnode-> besucht = true;
// den Code für den nachfolgenden Knoten wiederholt aufrufen
retektieren detectlooplinkedList (headnode-> Weiter);
int main ()
Node* headnode = new node ();
Node* SecondNode = new node ();
Node* dritterNode = new node ();
Headnode-> Data = 1;
Headnode-> next = SecondNode;
Headnode-> besucht = false;
SecondNode-> Data = 2;
SecondNode-> next = dritterNode;
SecondNode-> besucht = false;
ThirdNode-> Data = 3;
Thirdnode-> next = null; // keine Schleife
ThirdNode-> besucht = false;
if (detectlooplinkedList (headnode))
Cout << "Loop detected in linked list" << endl;
anders
Cout << "No loop detected in linked list" << endl;
// Erstellen einer Schleife
ThirdNode-> Next = SecondNode;
if (detectlooplinkedList (headnode))
Cout << "Loop detected in linked list" << endl;
anders
Cout << "No loop detected in linked list" << endl;
Rückkehr 0;
Ausgang:
Keine Schleife in der verknüpften Liste erkannt
Schleife in verknüpfter Liste erkannt
Erläuterung:
Ansatz 4: Verwenden Sie Stack
Schleifen in einer verknüpften Liste finden Sie unter Verwendung eines Stapels und der DFS-Methode „Tiefen-First-Suche“ (DFS). Das grundlegende Konzept besteht darin, die verknüpfte Liste durchzusetzen und jeden Knoten auf den Stapel zu drücken, wenn er noch nicht besucht wurde. Eine Schleife wird erkannt, ob ein Knoten, der sich bereits auf dem Stapel befindet.
Hier finden Sie eine kurze Beschreibung des Verfahrens:
C ++ - Programmimplementierung für die obige Methode (Stack)
#enthalten
#enthalten
Verwenden von Namespace STD;
Strukturknoten
int Daten;
Knoten* Weiter;
;
// Funktion zum Erkennen der Schleife in einer verknüpften Liste
bool detectlooplinkedList (Knoten* Headnode)
StapelStapel;
Node* tempnode = headnode;
while (tempnode != Null)
// Wenn das obere Element des Stapels entspricht
// Der aktuelle Knoten und der Stapel sind nicht leer
Wenn (!Stapel.leere () && stack.top () == tempnode)
zurückkehren;
Stapel.Push (tempnode);
tempnode = tempnode-> Weiter;
falsch zurückgeben;
int main ()
Node* headnode = new node ();
Node* SecondNode = new node ();
Node* dritterNode = new node ();
Headnode-> Data = 1;
Headnode-> next = SecondNode;
SecondNode-> Data = 2;
SecondNode-> next = dritterNode;
ThirdNode-> Data = 3;
Thirdnode-> next = null; // keine Schleife
if (detectlooplinkedList (headnode))
Cout << "Loop detected in linked list" << endl;
anders
Cout << "No loop detected in linked list" << endl;
// Erstellen einer Schleife
ThirdNode-> Next = SecondNode;
if (detectlooplinkedList (headnode))
Cout << "Loop detected in linked list" << endl;
anders
Cout << "No loop detected in linked list" << endl;
Ausgang:
Keine Schleife in der verknüpften Liste erkannt
Schleife in verknüpfter Liste erkannt
Erläuterung:
In diesem Programm wird ein Stack verwendet, um herauszufinden, ob eine einzig verknüpfte Liste eine Schleife hat.
2. Der Standard -Namespace ist in der zweiten Zeile enthalten, sodass wir auf die Funktionen der Eingabe-/Ausgabestreambibliothek zugreifen können, ohne sie mit „std ::.”
3. Die folgende Zeile definiert den Strukturknoten, der aus zwei Mitgliedern besteht: eine Ganzzahl namens "Daten" und einen Zeiger auf einen anderen Knoten namens "Next".”
4. Der Kopf der verknüpften Liste ist eine Eingabe für die Methode DECTECTLOOPLINKEDLIST (), die in der nächsten Zeile definiert ist. Die Funktion erzeugt einen booleschen Wert, der angibt, ob eine Schleife gefunden wurde oder nicht.
5. Ein Stapel Knotenzeiger namens "Stack" und ein Zeiger auf einen Knoten mit dem Namen "Tempnode", der mit dem Wert des Headnode initialisiert wird, werden beide in der Funktion erstellt.
6. Dann, solange Tempnode kein Nullzeiger ist, geben wir eine Weile Schleife ein.
(a) Das obere Element des Stapels muss mit dem aktuellen Knoten übereinstimmen, damit wir feststellen, dass er nicht leer ist. Wir geben wahr, wenn dies der Fall ist, weil eine Schleife gefunden wurde.
(b) Wenn die oben erwähnte Bedingung falsch ist, wird der aktuelle Knotenzeiger auf den Stapel gedrückt und Tempnode wird in der verlinkten Liste auf den folgenden Knoten gesetzt.
7. Wir kehren nach der während der Zeitschleife falsch zurück, weil keine Schleife beobachtet wurde.
8. Wir erstellen drei Knotenobjekte und initialisieren sie in der main () -Funktion. Da es im ersten Beispiel keine Schleife gibt, setzen wir die "nächsten" Zeiger jedes Knotens richtig.
Abschluss:
Zusammenfassend hängt die beste Methode zum Erkennen von Schleifen in einer verknüpften Liste vom spezifischen Anwendungsfall und den Einschränkungen des Problems ab. Hash-Tabelle und Floyds Zyklus-Findungsalgorithmus sind effiziente Methoden und sie werden in der Praxis häufig verwendet. Stack und Rekursion sind weniger effiziente Methoden, aber intuitiverer.