逆转双向链表问题

Posted

技术标签:

【中文标题】逆转双向链表问题【英文标题】:Reversing a Doubly Linked List Issues 【发布时间】:2018-03-28 04:01:47 【问题描述】:

我正在尝试反转双向链接列表,但没有成功。反转后,列表显示为空。

这是我的实现:

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
typedef struct Item Item;
typedef struct DLL DLL;

struct Item 
    int value;
    Item* next;
    Item* prev;
;

struct DLL 
    Item* head;
    Item* tail;
    int size;
    void(*add)(DLL*, int);
    void(*addToTail)(DLL*, int);
;

void add(DLL* list, int val) 
    Item* new_item = (Item*) malloc(sizeof(Item));
    if (new_item == NULL) 
        exit(-1);
    
    new_item->value = val;
    new_item->next = list->head->next;
    list->head->next = new_item;
    new_item->prev = list->head;
    list->size++;


void addToTail(DLL* list, int val) 
    Item* new_item = (Item*) malloc(sizeof(Item));
    if (new_item == NULL) 
        exit(-1);
    
    new_item->value = val;
    new_item->prev = list->tail->prev;
    list->tail->prev = new_item;
    new_item->next = list->tail;
    list->size++;


Item* find(DLL* list, int val) 
    Item* iter = list->head->next;
    while (iter != list->tail) 
        if (iter->value == val) 
            return iter;
        
        iter = iter->next;
    
    return NULL;


void reverse(DLL* list) 
    Item* current = list->head;
    Item* temp = NULL;
    while (current != NULL) 
        temp = current->next;
        current->next = current->prev;
        current->prev = temp;
        current = current->prev;
    

    temp = list->head;
    list->head = list->tail;
    list->tail = temp;


void printList(DLL* list) 
    Item* iter = list->head->next;
    while (iter != list->tail) 
        printf("%d\n", iter->value);
        iter = iter->next;
    


DLL* initDLL() 
    DLL* list = (DLL*) malloc(sizeof(DLL));
    if (list == NULL) 
        exit(-1);
    

    // Creating head & tail
    list->head = (Item*) malloc(sizeof(Item));
    list->tail = (Item*) malloc(sizeof(Item));
    if (list->head == NULL || list->tail == NULL) 
        free(list);
        exit(-1);
    

    // Initializing head & tail values just for testing
    list->head->value = 100;
    list->tail->value = 200;

    list->head->prev = NULL;
    list->head->next = list->tail;
    list->tail->prev = list->head;
    list->tail->next = NULL;

    list->size = 0;
    list->add = add;
    list->addToTail = addToTail;

    return list;


int main() 
    DLL* my_list = initDLL();
    my_list->add(my_list, 1);
    my_list->add(my_list, 2);
    my_list->add(my_list, 3);

    printList(my_list);
    // Outputs:
    // 3
    // 2
    // 1

    reverse(my_list);

    printList(my_list);
    // Prints nothing since list->head->next == list->tail

我期待

3
2
1
1
2
3

但只得到

3
2
1

第一个 printList() 按预期工作,但第二个没有输出。

查看问题我发现在反转列表后,由于某种原因list-&gt;head-&gt;next 指向list-&gt;tail,即使列表中有 3 个元素。

我在网上搜索了示例,但偶然发现了不使用 DLL 结构的实现,例如我的结构,而只使用 Node 结构。

【问题讨论】:

我不明白为什么您需要实际反转 DLL。你可以有一个从尾部打印到头部的函数。 学习用的。 minimal reproducible example 的代码很多。 创建一个从头到尾遍历并显示列表的函数,这与双向链表相反 请阅读并理解the question on why not to cast the return value of malloc() and family in C。例如,在这段代码中,首选Item* new_item = malloc(sizeof *new_item); 【参考方案1】:

在你的添加函数中,你需要在设置new_item-&gt;next = list-&gt;head-&gt;next;之后将new_item-&gt;next-&gt;prev设置为new_item

void add(DLL* list, int val) 
    Item* new_item = malloc(sizeof *new_item);
    if (new_item == NULL) 
        exit(EXIT_FAILURE);
    
    new_item->value = val;
    new_item->next = list->head->next;
    new_item->next->prev = new_item;   // <--- This is missing in your code 
    list->head->next = new_item;
    new_item->prev = list->head;
    list->size++;

您的addToTail() 也存在类似问题。在那里你需要将new_item-&gt;prev-&gt;next 设置为new_item

【讨论】:

以上是关于逆转双向链表问题的主要内容,如果未能解决你的问题,请参考以下文章

链表-双向链表

数据结构(链表——双向链表的实现)

带头节点的双向链表

双向链表的原理与实现

数据结构之带头结点的循环双向链表详细图片+文字讲解

Python数据结构与算法(2.4)——双向链表