简体   繁体   English

反转链表列表

[英]Reversing a linked list list

I was trying to reverse a linked list but I kept comming across an issue.我试图反转一个链表,但我一直遇到一个问题。 I finally figured out was wrong and fixed it, however I do not understand why my last approach doesn't work.我终于发现错误并修复了它,但是我不明白为什么我最后的方法不起作用。 The code below is the one that successfully reverses a linked list.下面的代码是成功反转链表的代码。

void reverse_list(list** head)
{
    list* currNode = *head;
    list* prevNode = NULL;
    list* tmpNode;

    while(1)
    {
        tmpNode = currNode->next;
        currNode->next = prevNode;
        if(tmpNode == NULL)
        {
            *head = currNode;
            break;
        }
        prevNode = currNode;
        currNode = tmpNode;
    }

}

However, the code below does not work.但是,下面的代码不起作用。 Both use double pointers, but in this one I dereferenced head twice to get to the actual object and assigned it with *currNode.两者都使用双指针,但在这一个中,我两次取消引用 head 以获取实际的 object 并将其分配给 *currNode。 When I run this code, It ends up going into an infinite loop and its missing the last item.当我运行此代码时,它最终进入无限循环并且缺少最后一项。 For example, if the items were 1,2,3,4,5, then the reverse would be 5,4,3,2, and it keeps printing the same list.例如,如果项目是 1、2、3、4、5,那么反过来就是 5、4、3、2,它会一直打印相同的列表。 I don't understand why this approach isn't working since I'm accessing the actual object (by derefrening twice) and assigning it with a new object (*currNode).我不明白为什么这种方法不起作用,因为我正在访问实际的 object(通过取消引用两次)并为其分配新的 object (*currNode)。

void reverse_list(list** head)
{
    list* currNode = *head;
    list* prevNode = NULL;
    list* tmpNode;

    while(1)
    {
        tmpNode = currNode->next;
        currNode->next = prevNode;
        if(tmpNode == NULL)
        {
            **head = *currNode;
            break;
        }
        prevNode = currNode;
        currNode = tmpNode;
    }

}

The code below has the same issue as the one above.下面的代码与上面的代码有相同的问题。 I followed the same approach as with the above code only this one uses a single pointer.我采用了与上述代码相同的方法,只是这个代码使用了一个指针。

void reverse_list(list* head)
{
    list* currNode = head;
    list* prevNode = NULL;
    list* tmpNode;

    while(1)
    {
        tmpNode = currNode->next;
        currNode->next = prevNode;
        if(tmpNode == NULL)
        {
            *head = *currNode;
            break;
        }
        prevNode = currNode;
        currNode = tmpNode;
    }

}

Any help to understand this would greatly be appreciated.任何有助于理解这一点的帮助将不胜感激。 Thank you!谢谢!

Different levels of indirection.不同级别的间接。

Given list** head , *head is the value pointed to by head , a pointer to a Node , a list * .给定list** head*headhead指向的值,一个指向Node的指针,一个list * We dereference one more time and **head dereferences to list * and then to list .我们再取消引用一次, **head取消引用list * ,然后再引用list We're all out of pointers and and are accessing the object at the end of the line.我们都没有指针,并且正在访问该行末尾的 object。 So所以

**head = *currNode;

dereferences both pointers all the way back to the objects.取消引用两个指针,一直返回到对象。 This is assigning values to objects, not addresses to pointers to objects.这是为对象赋值,而不是为指向对象的指针赋值。 Rather than changing the linkage of the list by updating pointers, whatever list head ultimately pointed at has been changed to match currNode , breaking the integrity of the list.不是通过更新指针来更改列表的链接,而是更改了最终指向的任何list head以匹配currNode ,从而破坏了列表的完整性。

*head = currNode;

only derefences head one level closer to the object. Here we are operating on pointers and changing linkage.仅取消引用 head 更接近 object 一级。这里我们对指针进行操作并更改链接。

In the final example we have在最后一个例子中,我们有

*head = *currNode;

and this is similar to the first failed attempt.这类似于第一次失败的尝试。 It is assigning values rather than changing the pointers.它正在分配值而不是更改指针。

For starters all the three functions in general can invoke undefined behavior when they are called for empty lists due to these lines对于初学者来说,由于这些行,当为空列表调用它们时,通常所有三个函数都可以调用未定义的行为

list* currNode = head;
//...
tmpNode = currNode->next;

because there is used a null pointer to access memory.因为使用了 null 指针来访问 memory。

In the second function in this if statement在此 if 语句中的第二个 function

    if(tmpNode == NULL)
    {
        **head = *currNode;
        break;
    }

the original first node is overwritten by the last node原来的第一个节点被最后一个节点覆盖

**head = *currNode;

So after exiting the function you will have that the original pointer head still points to the originally first node that was overwritten by the last node of the list.所以退出 function 后,原来的指针头仍然指向原来的第一个节点,被链表的最后一个节点覆盖。 So as a result one actual data will be lost and there will be a memory leak.因此,一个实际数据将丢失,并且将出现 memory 泄漏。

As for the third function then it is enough to point to that the function accepts the pointer to the head node by value.至于第三个function则指向function按值接受指向头节点的指针就够了。

void reverse_list(list* head)

That is the function deals with a copy of the value of the original variable head.即 function 处理原始变量 head 值的副本。 Changing the copy will not influence on the original pointer.更改副本不会影响原始指针。 The original pointer will still point to the first node.原始指针仍将指向第一个节点。

The function can look simpler the following way function 可以通过以下方式看起来更简单

void reverse( list **head )
{
    list *current = *head;
    *head = NULL;
        
    while ( current != NULL )
    {
        struct Node *tmp = current;
        current = current->next;
        tmp->next = *head;
        *head = tmp;
    }
}

Here is a demonstrative program.这是一个演示程序。

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

typedef struct Node
{
    int data;
    struct Node *next;
} list;

int push_front( list **head, int data )
{
    list *new_node = malloc( sizeof( list ) );
    int success = new_node != NULL;
    
    if ( success )
    {
        new_node->data = data;
        new_node->next = *head;
        *head = new_node;
    }
    
    return success;
}

void display( const list *head )
{
    for ( ; head != NULL; head = head->next )
    {
        printf( "%d -> ", head->data );
    }
    
    puts( "null" );
}

void reverse( list **head )
{
    list *current = *head;
    *head = NULL;
        
    while ( current != NULL )
    {
        list *tmp = current;
        current = current->next;
        tmp->next = *head;
        *head = tmp;
    }
}

int main(void) 
{
    const int N = 10;
    
    list *head = NULL;
    
    display( head );
    
    reverse( &head );
    
    display( head );
    
    putchar( '\n' );
    
    for ( int i = 0; i < N; i++ )
    {
        push_front( &head, i );
    }
    
    display( head );
    
    reverse( &head );
    
    display( head );
    
    return 0;
}

The program output is程序 output 是

null
null

9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0 -> null
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM