反向打印双向链表

时间:2016-09-18 04:18:33

标签: c

我有一个双向链表,我可以从上到下打印,现在我正在尝试从下到上打印它。

#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

这是输出:

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

我不知道为什么它不会反向打印完整列表。它只能在反向打印时打印一个项目。

直到“最后节点数据打印”消息的所有内容都是正确的。是的,它有点乱,我是C的新手,我需要清理我的评论等等。道歉。

有人可以帮忙吗?

3 个答案:

答案 0 :(得分:2)

将节点插入列表时,您忘记将prev字段设置为适当的值。修复很简单:将last初始化为NULL,然后在ptr->prev = last;

之后设置ptr = makeNode(info);

顺便说一下,temp未使用。

答案 1 :(得分:1)

在阅读阶段,您设置last->next,但您从未将prev成员设置为NULL以外的任何其他成员。

如果您修改printList()代码以使用prev转换说明符打印next%p成员,则可以看到此内容。

例如:

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");
    }
}

运行时,这会产生(对我来说,在我的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

如您所见,反向没有链接,因此在打印一个元素后反向打印停止 - 无论您指向哪个元素。

请注意,在编写C时,不应在点.或箭头->运算符周围使用空格。它们绑得非常紧密,不应该使用空格(因为它在语法上是合法的)。如果使用这种非正统的布局,则代码的可读性要低得多。

扫描代码中的修复很简单:

    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;
    }

我还在循环开始之前初始化last = NULL;;当你用它来设置前一个指针时,这是至关重要的。你以前可以省略它,虽然GCC抱怨可能会使用未初始化的&#39;使用我的默认编译选项。它实际上并没有被初始化,但编译器(GCC 6.2.0)是可以理解的。

通过此更改,输出为:

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

您还可以打印节点的地址;这样可以更容易地跟踪每个列表指针指向正确的位置:

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");
}
制造

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.

答案 2 :(得分:1)

您忘记链接到prev

else last -> next = ptr;

应该是

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