2016-09-18 4 views
0

Ich habe eine doppelt verknüpfte Liste, die ich von oben nach unten drucken kann, und jetzt versuche ich, sie von unten nach oben zu drucken.eine doppelt verkettete Liste in umgekehrter Reihenfolge drucken

#include <stdio.h> 
#include <stdlib.h> 
#include <stddef.h> 

//defines the struct UserData 
typedef struct 
{ 
    int importance; 
    char taskName[80]; 
}UserData, *UserDataPtr; 

//Defines a node 
typedef struct node { 
    UserData Data; 
    struct node *next; 
    struct node *prev; 
    } Node, *NodePtr; 

NodePtr makeNode(UserData); 

//Declare function printList 
void printList(NodePtr); 

void printListRev(NodePtr); 

int main() 
{ 
    UserData info; 
    NodePtr top, ptr, last, temp; 



    top = NULL; 

    FILE *filein=fopen("Data.txt", "r"); 
    if (filein == NULL) { 
     printf("Error opening file, exiting program.\n"); 
     exit(0); 
    } 

    while(fscanf(filein, "%d%s",&info.importance, info.taskName)==2) 
     { 
      ptr=makeNode(info); 
      if (top == NULL) top = ptr; 
      else last -> next = ptr; 
      last = ptr; 
     }//end while loop 

    printList(top); 


    printListRev(last); 
    }//end Main 


//printList is a function that prints each node as long as it isn't NULL. Once it reaches NULL it terminates, signifying the end of the list. 
void printList(NodePtr ptr) { 
    while (ptr != NULL) { //as long as there's a node 
      printf("%d %s\n", ptr -> Data.importance, ptr -> Data.taskName); 
      ptr = ptr -> next; //go on to the next node 

     } 
    if (ptr == NULL) { 

     printf("Last node data printed moving forward.\n"); 
    } 

    } //end printList 


void printListRev(NodePtr ptr) { 
    while(ptr != NULL){ 
     printf("%d %s\n", ptr -> Data.importance, ptr -> Data.taskName); 
     ptr = ptr -> prev; 


     } 
    }//end printListRev 

//Define function makeNode. Allocates storage for node, stores integer given to it, and returns a pointer to the new node. Also sets next field to NULL 
NodePtr makeNode(UserData info) { 
    NodePtr ptr = (NodePtr) malloc(sizeof (Node)); 
    ptr -> Data = info; 
    ptr -> next = NULL; 
    ptr -> prev = NULL; 
    return ptr; 
} //End makeNode 

Dies ist die Ausgabe:

1 task1 
2 task2A 
3 task3A 
2 task2B 
4 task4A 
4 task4B 
3 task3B 
Last node data printed moving forward. 
3 task3B 

Und ich habe keine Ahnung, warum es nicht die vollständige Liste in umgekehrter Reihenfolge gedruckt werden. Es druckt nur einen Artikel, wenn rückwärts gedruckt wird.

Alles bis zur Meldung "Letzte Node Daten gedruckt" ist korrekt. Und ja, es ist ein bisschen chaotisch, ich bin neu in C und ich muss meine Kommentare und so aufräumen. Entschuldigung.

Kann jemand helfen?

+0

Hinweis sein sollte, dass der Punkt '.' Pfeil und' -> 'Betreiber binden sehr eng und sollte nie mit Leerzeichen um sie geschrieben werden. (Ja, es ist syntaktisch gültig; Sie könnten sie in eine separate Zeile von der Struktur/Zeiger und Member-Namen setzen und es würde kompilieren. Es ist eine Frage der normalen oder konventionellen Präsentation - wie C und C++ geschrieben werden.) –

+2

Während In der Lesephase legen Sie 'last-> next 'fest, aber Sie setzen niemals' prev' member auf etwas anderes als NULL. Sie sollten die Adressen (die 'next'- und' prev'-Mitglieder) mit dem '% p'-Format drucken, während Sie die Liste vorwärts drucken; Sie werden viel zu viele Nullzeiger in den "nächsten" Werten sehen. –

Antwort

1

Während der Lesephase haben Sie last->next festgelegt, aber Sie haben nie prev Mitglied auf etwas anderes als NULL festgelegt.

Sie können das sehen, wenn Sie den printList() Code revidieren zu den prev und next Mitglieder drucken - mit der %p Konvertierungsspezifizierer.

Zum Beispiel:

void printList(NodePtr ptr) 
{ 
    while (ptr != NULL) 
    { 
     printf("%d %s (N = %p, P = %p)\n", ptr->Data.importance, ptr->Data.taskName, 
       (void *)ptr->next, (void *)ptr->prev); 
     ptr = ptr->next; 
    } 
    if (ptr == NULL) 
    { 
     printf("Last node data printed moving forward.\n"); 
    } 
} 

Wenn er gestartet wird, erzeugt dies (für mich, auf meinem Mac):

1 task1 (N = 0x7ff6a94032e0, P = 0x0) 
2 task2A (N = 0x7ff6a9403370, P = 0x0) 
3 task3A (N = 0x7ff6a94033e0, P = 0x0) 
2 task2B (N = 0x7ff6a9403450, P = 0x0) 
4 task4A (N = 0x7ff6a94034c0, P = 0x0) 
4 task4B (N = 0x7ff6a9403530, P = 0x0) 
3 task3B (N = 0x0, P = 0x0) 
Last node data printed moving forward. 
3 task3B 

Wie Sie sehen können, gibt es keine Verknüpfung in der umgekehrten Richtung, so Der umgekehrte Druck stoppt nach dem Drucken eines Elements - egal, auf welches Element Sie zeigen.

Beachten Sie, dass Sie beim Schreiben von C keine Leerzeichen um die Punktoperatoren . oder -> verwenden sollten. Sie binden extrem eng, und Leerraum sollte nicht verwendet werden (für alle ist es syntaktisch legitim). Ihr Code ist viel weniger lesbar, wenn Sie ein solches unorthodoxes Layout verwenden.

Das Update in dem Scan-Code ist einfach:

while (fscanf(filein, "%d%s", &info.importance, info.taskName) == 2) 
    { 
     ptr = makeNode(info); 
     if (top == NULL) 
      top = ptr; 
     else 
      last->next = ptr; 
     ptr->prev = last; 
     last = ptr; 
    } 

ich auch last = NULL; vor Beginn der Schleife initialisiert; das ist wichtig, wenn Sie es verwenden, um den vorherigen Zeiger festzulegen. Du konntest es vorher weglassen, obwohl GCC über "kann nicht verwendet werden" mit meinen Standardzusammenstellungswahlen jammerte. Es wurde tatsächlich nicht uninitialisiert verwendet, aber der Compiler (GCC 6.2.0) war verständlicherweise betroffen.

Mit dieser Änderung ist der Ausgang:

1 task1 (N = 0x7fa4b1602a10, P = 0x0) 
2 task2A (N = 0x7fa4b1602aa0, P = 0x7fa4b16029a0) 
3 task3A (N = 0x7fa4b1602b10, P = 0x7fa4b1602a10) 
2 task2B (N = 0x7fa4b1602b80, P = 0x7fa4b1602aa0) 
4 task4A (N = 0x7fa4b1602bf0, P = 0x7fa4b1602b10) 
4 task4B (N = 0x7fa4b1602c60, P = 0x7fa4b1602b80) 
3 task3B (N = 0x0, P = 0x7fa4b1602bf0) 
Last node data printed moving forward. 
3 task3B 
4 task4B 
4 task4A 
2 task2B 
3 task3A 
2 task2A 
1 task1 

Sie auch die Adresse des Knotens drucken konnten; das wäre es leichter zu verfolgen, dass jeder der Listenzeiger wird an den richtigen Ort zeigt:

void printList(NodePtr ptr) 
{ 
    while (ptr != NULL) 
    { 
     printf("%d %s (C = %p, N = %p, P = %p)\n", ptr->Data.importance, ptr->Data.taskName, 
       (void *)ptr, (void *)ptr->next, (void *)ptr->prev); 
     ptr = ptr->next; 
    } 
    printf("Last node data printed moving forward.\n"); 
} 

void printListRev(NodePtr ptr) 
{ 
    while (ptr != NULL) 
    { 
     printf("%d %s (C = %p, N = %p, P = %p)\n", ptr->Data.importance, ptr->Data.taskName, 
       (void *)ptr, (void *)ptr->next, (void *)ptr->prev); 
     ptr = ptr->prev; 
    } 
    printf("Last node data printed moving backward.\n"); 
} 

Herstellung:

1 task1 (C = 0x7fd301c03270, N = 0x7fd301c032e0, P = 0x0) 
2 task2A (C = 0x7fd301c032e0, N = 0x7fd301c03370, P = 0x7fd301c03270) 
3 task3A (C = 0x7fd301c03370, N = 0x7fd301c033e0, P = 0x7fd301c032e0) 
2 task2B (C = 0x7fd301c033e0, N = 0x7fd301c03450, P = 0x7fd301c03370) 
4 task4A (C = 0x7fd301c03450, N = 0x7fd301c034c0, P = 0x7fd301c033e0) 
4 task4B (C = 0x7fd301c034c0, N = 0x7fd301c03530, P = 0x7fd301c03450) 
3 task3B (C = 0x7fd301c03530, N = 0x0, P = 0x7fd301c034c0) 
Last node data printed moving forward. 
3 task3B (C = 0x7fd301c03530, N = 0x0, P = 0x7fd301c034c0) 
4 task4B (C = 0x7fd301c034c0, N = 0x7fd301c03530, P = 0x7fd301c03450) 
4 task4A (C = 0x7fd301c03450, N = 0x7fd301c034c0, P = 0x7fd301c033e0) 
2 task2B (C = 0x7fd301c033e0, N = 0x7fd301c03450, P = 0x7fd301c03370) 
3 task3A (C = 0x7fd301c03370, N = 0x7fd301c033e0, P = 0x7fd301c032e0) 
2 task2A (C = 0x7fd301c032e0, N = 0x7fd301c03370, P = 0x7fd301c03270) 
1 task1 (C = 0x7fd301c03270, N = 0x7fd301c032e0, P = 0x0) 
Last node data printed moving backward. 
+1

Ihre Hilfe und gründliche Erklärungen werden sehr geschätzt. Ich wählte dies als Antwort, weil es funktionierte und aufgrund Ihrer Erklärung. Ich beeilte mich, die Korrekturen zu machen und habe nicht gesehen, was Sie über das Initialisieren von zuletzt auf NULL gesagt haben, und ich habe am Ende auch etwas funky ausgegeben, aber nach der Initialisierung von NULL funktionierte es genau so, wie Sie es beschrieben haben. Ich hoffe, ich kann genug Erfahrung sammeln, um anderen so viel wie du zu helfen! –

2

Wenn Knoten in die Liste einfügen, können Sie die prev Feld zu setzen vergessen zu angemessenem Wert.Die Lösung ist einfach: Initialisieren last-NULL, stellen Sie dann ptr->prev = last; nach der Zeile ptr = makeNode(info);

By the way, temp ungenutzt ist.

+1

Ganz richtig, und Ihre Lösung hat funktioniert. Ich gab @ Jonathan die Antwort für seine Erklärung, aber danke für deine Antwort! Vielen Dank für das Hinweis auf die unbenutzte "Temp", aber ich habe vergessen, es nach dem Versuch etwas vorher zu löschen (erfolglos lol!) –

+0

Eigentlich habe ich es nicht bemerkt, der Compiler tat =)) –

+0

Haha !! Mach weiter, nimm den Kredit, alles ist gut! –

1

Sie haben vergessen, Link zu prev zu machen.

else last -> next = ptr;

else { 
    ptr->prev = last; 
    last -> next = ptr; 
} 
+0

'letzte' Initialisierung ist nicht erforderlich. (Obwohl es eine gute Gewohnheit ist) – BLUEPIXY

Verwandte Themen