Reverse-Traversierung einfach verknüpfte Liste in C++
Kürzlich bin ich gebeten worden, diese Frage in einem interview. Alles was ich tun konnte, ist die traverse von 9 zu 1 aus einer verknüpften Liste, beginnend von 0 bis 9. Hier ist der code:
#include <iostream>
typedef struct node {
int data; //will store information
node *next; //the reference to the next node
};
node *head;
int printList(node *traverse) {
if (traverse->next == NULL) {
return -1;
}
traverse=traverse->next;
printList(traverse);
cout << traverse->data << endl;
return 0;
}
int main() {
node *temp = NULL;
node *begin = NULL;
for (int i = 0; i < 10; i++) {
temp = new node;
temp->data = i;
if (begin == NULL) {
begin = temp;
}
if (head != NULL) {
head->next = temp;
}
head = temp;
head->next = NULL;
}
head = begin;
printList(head);
return 0;
}
1) Wie kann ich drucken Sie 0(das erste element) mit der printList()
rekursive Funktion?
2) Wie kann ich ersetzen printList()
rekursive Funktion mit while-Schleife?
3) Wenn in einem interview gefragt, hat die main()
Funktion hat richtige Knoten, Initialisierung und insertation?
Mein Fehler. Entfernt Kommentar um Verwirrung zu vermeiden.
InformationsquelleAutor Sarp Kaya | 2013-07-03
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sind Sie vier mögliche Wege, dies zu erreichen, von denen jede Ihre eigenen Vorzüge.
Rekursion
Dies ist vielleicht die erste Antwort in den Sinn. Jedoch, der Prozess-stack-Größe ist begrenzt, so dass die Rekursion hat ein ziemlich niedriges limit. Eine große Liste provozieren einen stack-überlauf. Dies ist nicht ein sehr gutes design in C++.
Iteration
Natürlich, wenn Sie wollen, machen es die iterative Art und Weise, werden Sie brauchen, um Stapel der Knoten Zeiger selbst (auf der Prozess-heap) und nicht delegieren diese Aufgabe an die call-stack. Mit dieser Methode können Sie drucken viel größere Listen, und ist O(n) Berechnungen. Es ist jedoch O(n) Speicherverbrauch, aber Sie haben bereits eine Liste, die mit O(n) Speicher. Also das sollte kein Problem sein. Jedoch können Sie wirklich brauchen, um zu vermeiden, den Speicherverbrauch. Das bringt uns zur nächsten Idee.
Doppel-iteration
Dies mag eine dumme Lösung, da es O(n^2) Komplexität, aber das ist Rechen-Komplexität. Es hat O(1) Speicher-Komplexität und je nach dem aktuellen Kontext und dem genauen problem, kann es die Antwort sein, die Sie benötigen. Aber diese O(n^2) Komplexität ist viel zu bezahlen. Vor allem, wenn n so groß ist, dass Sie vermeiden wollte, ein weiteres O(n) - allocation. Das bringt uns zu der letzten Idee.
Hack der container
Du zuerst ändern Sie die container, dann die Iteration in Ihrer neuen Reihenfolge. Auf einer single-Link-Liste, können Sie einfach in umgekehrter Reihenfolge die links, dann rückwärts-Iteration, während die Umkehrung der links wieder. Das schöne daran ist, es bleibt O(n) in computing, und O(1) Speicher. Das problem ist, dass Sie ungültig wird der volle Behälter, während dies zu tun : Ihre bestens Betrieb nicht verlassen die Liste Konstante : dies ist nicht exception-sicher: wenn Sie Ihren Vorgang schlägt fehl, in der Mitte der iteration, die Liste ist nicht mehr gültig. Dies kann oder kann nicht ein Problem sein, je nach problem.
InformationsquelleAutor lip
Es gibt einen alten trick für das Durchlaufen der Liste in umgekehrter mit einer while-Schleife.
Gehen Sie die loop-in vorwärts-Richtung, aber wie Sie lassen jeder Knoten, den Sie reverse link, D. H., Sie erhalten den aktuellen Wert (der Zeiger auf den nächsten Knoten), aber dann es so einrichten, dass es enthält einen Zeiger auf den vorherigen Knoten. Wenn Sie erreichen das Ende der Liste haben Sie jetzt eine einfach-verkettete Liste, geht die entgegengesetzte Richtung-D. H., die folgenden Hinweise sollen Sie zurück an den Anfang der Liste.
So, dann gehen Sie zurück an den Anfang -, Druck-jeder Knoten ist Wert heraus, wie Sie gehen, und (wieder) die Umkehrung der links, so, wenn Sie fertig sind, wird die Liste so ist, wie es begann, mit links geht von Anfang bis Ende.
Beachten Sie jedoch, dass dies zu Problemen führen kann (für ein anschauliches Beispiel) multi-threaded code. Die gesamte Traversierung der Liste vom Anfang zum Ende und wieder zum Anfang behandelt werden muss, als eine einzelne, Atomare operation-wenn zwei threads versuchen zum Durchlaufen der Liste gleichzeitig, sehr schlimme Dinge passieren wird. Ebenfalls, so dass diese Ausnahme-ist sicher etwas schwierig, als gut.
IOW, diese sind nur selten effektive Lösungen für Reale Probleme (aber das gleiche gilt generell von verknüpften Listen im Allgemeinen). Sie sind jedoch wirksame Wege zu zeigen, ein interviewer, dass Sie spielen können, dumm verkettete Liste tricks.
Ich bezweifle, dass es original war bei mir, aber ich schrieb über trick, bevor Wikipedia Bestand. 🙂
Gerne gebe ich Ihnen Kredit für die XOR-Technik 😉
Wie gesagt, ich bin mir ziemlich sicher, dass es ursprünglich nicht von mir (und so hässlich wie es ist, ich würde wahrscheinlich lehnen alle wissen es, wenn es wirklich war mine).
Ich wurde gebeten, diese auf einem interview einmal, meine Antwort war warum würden Sie wollen, etwas zu tun, so zerbrechlich?
InformationsquelleAutor Jerry Coffin
Wenn Ihre Liste ist [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
1) Sie möchten, um die Ausgabe der Liste Umgekehrt, Ihre ListBox sollte dann so Aussehen:
2) ist Es nicht wirklich möglich mit einer while-Schleife, es sei denn, Sie tun wirklich hässliche Dinge wie die Verkettung jedes Knotens Daten an den Anfang des Ergebnisses Zeichenfolge, die Sie drucken möchten.
3) Ihre wichtigsten scheint sehr seltsam zu mir. Ich verstehe nicht, warum Ihr 'Kopf' variable global ist, warum nicht in der main selbst?
Nicht zuletzt, warum nicht mit std::list?
head
ist global, weil ich dachte, für weitere Funktionen erforderlich sein kann weltweit zugegriffen werden. Es ist kein großes Problem. Über std::list, denn dies ist eine interview-Frage, Sie bitten, Sie zu implementieren, eher als unter Verwendung der C++ STLGut, dann ist das eine C-Frage. Wenn ich jemals gefragt, diese Frage in einem interview, erwarte ich, dass die Antwort des Kandidaten "gut, verwenden Sie ein standard-Container", das ist eine gesunde Reaktion.
es ist möglich in einer while-Schleife, vorausgesetzt, Sie behalten alle Knoten Zeiger auf einen stack-like container. Und das ist genau das, was Ihre rekursive Methode tun, in der Tat, häufen sich die Knoten Zeiger auf die process stack... das hat eine begrenzte Größe, im Vergleich zu den Prozess-heap.
ja, dass ist es, was ich sagte, Sie können es tun mit hässlichen Dingen.. Und ja mit dem Haufen kann lassen Sie haben mehr Platz (brauchen wir wirklich?), aber heap-Zuweisungen, also ein system nennen, wie sbrk(2) für jedes element multiplizieren Sie einfach die Ausführungszeit von 100 (ich weiß es nicht, aber eine Menge).
Sie sollten versuchen, zu Profilieren. Ich kann nicht einmal eine 10% - Geschwindigkeit-bis auf die rekursive version. Zuweisen von Speicherplatz für den Zeiger ist nicht so teuer.
InformationsquelleAutor roptch
Bitte korrigieren Sie mich, wenn ich falsch bin.
Diese Lösung verwendet einen Iterativen Ansatz. Eine zusätzliche "zurück" - Zeiger wird verwendet, um den Knoten, der schließlich Folgen die Knoten in der umgekehrten Reihenfolge der Liste.
public static Knoten reverse(Knoten head){
}
InformationsquelleAutor Neelesh Salian
1) Ändern
zu
2)
3) scheint ok zu mir. Warum erklären Sie den Kopf außerhalb der main?
1) nehmen Sie dreamstate mehr detaillierte Antwort auf das, was ist im Grunde die gleiche 2) wahr. Mit einer while-Schleife müssen Sie einen Stapel (last in, first out), die Sie füllen beim Durchlaufen der verketteten Liste. Und dann haben Sie eine weitere Schleife, während der stack ist nicht leer und pop vom stack (was das ist, was Sie im Grunde tun, mit dem rekursive Aufrufe).
InformationsquelleAutor hanslovsky
Einer möglichen Lösung, die Sie nutzen könnten. Eine andere Möglichkeit,
aber Sie müssen den Fehler-check für über - /Unterlauf.
InformationsquelleAutor rayman