Wie kehrt man eine einfach verknüpfte Liste mit nur zwei Zeigern um?
Lesezeit: 6 Minuten
Madhan
Ich frage mich, ob es eine Logik gibt, um eine einfach verknüpfte Liste mit nur zwei Zeigern umzukehren.
Das Folgende wird nämlich verwendet, um die einzelne verkettete Liste unter Verwendung von drei Zeigern umzukehren p, q, r:
struct node {
int data;
struct node *link;
};
void reverse() {
struct node *p = first,
*q = NULL,
*r;
while (p != NULL) {
r = q;
q = p;
p = p->link;
q->link = r;
}
first = q;
}
Gibt es eine andere Alternative, um die verknüpfte Liste umzukehren? Was wäre die beste Logik, um eine einfach verknüpfte Liste in Bezug auf die Zeitkomplexität umzukehren?
Nicht wirklich, das sind eher zwei Warteschlangen als zwei Zeiger.
– paxdiablo
26. November 2009 um 5:31 Uhr
Weil Sie hier sind, um zu helfen, und kein Wiederholungsspiel spielen?
– GManNickG
26. November 2009 um 5:52 Uhr
GMan: Das ist die Sache, ich bin mir nicht sicher, ob ich irgendjemandem helfe, nicht einmal ihm, wenn er es nicht durchziehen kann.
– Roger Pate
26. November 2009 um 6:00 Uhr
Sie helfen denen von uns, die die Fragen und Antworten lesen und etwas daraus ziehen. Ich fand es aufschlussreich.
– Andrew Coleson
26. November 2009 um 19:19 Uhr
paxdiablo
Ich hasse es, der Überbringer schlechter Nachrichten zu sein, aber ich glaube nicht, dass Ihre Drei-Zeiger-Lösung wirklich funktioniert. Als ich es im folgenden Testrahmen verwendete, wurde die Liste gemäß der folgenden Ausgabe auf einen Knoten reduziert:
==========
4
3
2
1
0
==========
4
==========
Sie erhalten keine bessere Zeitkomplexität als Ihre Lösung, da es O (n) ist und Sie jeden Knoten besuchen müssen, um die Zeiger zu ändern, außer Ihnen kann Machen Sie ganz einfach eine Lösung mit nur zwei zusätzlichen Zeigern, wie im folgenden Code gezeigt:
#include <stdio.h>
// The list element type and head.
struct node {
int data;
struct node *link;
};
static struct node *first = NULL;
// A reverse function which uses only two extra pointers.
void reverse() {
// curNode traverses the list, first is reset to empty list.
struct node *curNode = first;
first = NULL;
// Until no more in list, insert current before first and advance.
while (curNode != NULL) {
// Need to save next node since we're changing the current.
struct node *nxtNode = curNode->link;
// Insert at start of new list.
curNode->link = first;
first = curNode;
// Advance to next.
curNode = nxtNode;
}
}
// Code to dump the current list.
static void dumpNodes() {
struct node *curNode = first;
printf ("==========\n");
while (curNode != NULL) {
printf ("%d\n", curNode->data);
curNode = curNode->link;
}
}
// Test harness main program.
int main (void) {
int i;
struct node *newnode;
// Create list (using actually the same insert-before-first
// that is used in reverse function.
for (i = 0; i < 5; i++) {
newnode = malloc (sizeof (struct node));
newnode->data = i;
newnode->link = first;
first = newnode;
}
// Dump list, reverse it, then dump again.
dumpNodes();
reverse();
dumpNodes();
printf ("==========\n");
return 0;
}
was ich denke, ist das, wonach Sie gesucht haben. Es kann dies tatsächlich tun, sobald Sie es geladen haben first in den Zeiger, der die Liste durchläuft, können Sie wiederverwenden first nach Belieben.
Sehr elegant. Wiederverwendung der first Zeiger auf die verknüpfte Liste selbst ermöglicht es der Lösung, nur 2 zu verwenden extra Hinweise, sondern 3 gesamt Dafür sind noch Hinweise notwendig.
– Kevin Kibler
26. Februar 2010 um 21:23 Uhr
Dafür verwenden Sie zuerst, curNode und nxtNode, insgesamt drei Zeiger. Wie kommt es, dass dies eine Zwei-Zeiger-Lösung ist?
– Jasch
30. Oktober 2014 um 6:46 Uhr
@ Yash, lies nochmal, zwei extra Zeiger oben auf first. Genauso wie die Drei-Zeiger-Lösung des OP first, p, q und r.
– paxdiablo
30. Oktober 2014 um 13:03 Uhr
@paxdiablo oh! mein Fehler. Entschuldigung, ich habe die Frage falsch verstanden. Vielen Dank 🙂
– Jasch
30. Oktober 2014 um 14:58 Uhr
Hallo! Ich weiß, dass diese Frage alt ist, aber könnten Sie erklären, was in dieser Funktion passiert und warum sie funktioniert. 🙂 Vielen Dank!
// reverse.c
#include <stdio.h>
#include <assert.h>
typedef struct node Node;
struct node {
int data;
Node *next;
};
void spec_reverse();
Node *reverse(Node *head);
int main()
{
spec_reverse();
return 0;
}
void print(Node *head) {
while (head) {
printf("[%d]->", head->data);
head = head->next;
}
printf("NULL\n");
}
void spec_reverse() {
// Create a linked list.
// [0]->[1]->[2]->NULL
Node node2 = {2, NULL};
Node node1 = {1, &node2};
Node node0 = {0, &node1};
Node *head = &node0;
print(head);
head = reverse(head);
print(head);
assert(head == &node2);
assert(head->next == &node1);
assert(head->next->next == &node0);
printf("Passed!");
}
// Step 1:
//
// prev head next
// | | |
// v v v
// NULL [0]->[1]->[2]->NULL
//
// Step 2:
//
// prev head next
// | | |
// v v v
// NULL<-[0] [1]->[2]->NULL
//
Node *reverse(Node *head)
{
Node *prev = NULL;
Node *next;
while (head) {
next = head->next;
head->next = prev;
prev = head;
head = next;
}
return prev;
}
Danke für die tolle ASCII-Kunst zum Erklären 🙂
– Achedeuzot
26. September 2013 um 21:50 Uhr
Limitknacker
Robert Sedgewick, “Algorithmen in C“, Addison-Wesley, 3. Auflage, 1997, [Section 3.4]
Falls es sich nicht um eine zyklische Liste handelt, ist NULL die letzte Verknüpfung.
typedef struct node* link;
struct node{
int item;
link next;
};
/* you send the existing list to reverse() and returns the reversed one */
link reverse(link x){
link t, y = x, r = NULL;
while(y != NULL){
t = y->next;
y-> next = r;
r = y;
y = t;
}
return r;
}
Danke für die tolle ASCII-Kunst zum Erklären 🙂
– Achedeuzot
26. September 2013 um 21:50 Uhr
Gemeinschaft
Ja. Ich bin sicher, Sie können dies genauso tun, wie Sie zwei Nummern tauschen können, ohne eine dritte zu verwenden. Setzen Sie einfach die Zeiger auf int/long und führen Sie die XOR-Operation ein paar Mal aus. Dies ist einer dieser C-Tricks, die eine lustige Frage darstellen, aber keinen praktischen Wert haben.
Können Sie die O(n)-Komplexität reduzieren? Nein nicht wirklich. Verwenden Sie einfach eine doppelt verknüpfte Liste, wenn Sie glauben, dass Sie die umgekehrte Reihenfolge benötigen.
…und ein neues 64-Bit-Kompatibilitätsproblem entsteht, wenn Sie nicht aufpassen. Es ist auch unwahrscheinlich, dass Sie auf diese Weise Leistung erkaufen.
– Zum Archiv zurückgelassen
26. November 2009 um 5:26 Uhr
Dies wirkt sich nicht auf die Zeitkomplexität aus – das heißt, es wird die Lösung nicht machen besser als lineare Zeit. Ich meine, Sie könnten 4 oder 8 Byte Speicher sparen, aber das ändert nichts an der Gesamtkomplexität des Algorithmus.
– poundifdef
26. November 2009 um 5:28 Uhr
@rascher, die Zeitkomplexität war die zweite Teil der Frage. Der erste Teil hatte damit zu tun, die Anzahl der erforderlichen Zeiger zu reduzieren.
– paxdiablo
26. November 2009 um 5:56 Uhr
Ich denke, das Originalplakat suchte nach einem billigen C-Trick. Meiner Erfahrung nach – und ich habe es profiliert 🙂 – sind die typischen Vermeidungstricks tatsächlich langsamer als nur die Verwendung eines Vermittlers.
– Werden
26. November 2009 um 6:24 Uhr
Der Link ist kaputt, aber ich bin mir sicher, dass das Austauschen von 2 Zahlen mit XOR altmodisch ist 🙂
– Däne
13. November 2017 um 14:40 Uhr
14221700cookie-checkWie kehrt man eine einfach verknüpfte Liste mit nur zwei Zeigern um?yes
mögliches Duplikat: stackoverflow.com/questions/818443/…
– Kajako
26. November 2009 um 4:47 Uhr
Nicht wirklich, das sind eher zwei Warteschlangen als zwei Zeiger.
– paxdiablo
26. November 2009 um 5:31 Uhr
Weil Sie hier sind, um zu helfen, und kein Wiederholungsspiel spielen?
– GManNickG
26. November 2009 um 5:52 Uhr
GMan: Das ist die Sache, ich bin mir nicht sicher, ob ich irgendjemandem helfe, nicht einmal ihm, wenn er es nicht durchziehen kann.
– Roger Pate
26. November 2009 um 6:00 Uhr
Sie helfen denen von uns, die die Fragen und Antworten lesen und etwas daraus ziehen. Ich fand es aufschlussreich.
– Andrew Coleson
26. November 2009 um 19:19 Uhr