Skip to content

反转链表

约 663 字大约 2 分钟

2025-07-03

链表是基础且常用数据结构,反转链表极其适合新手用于理解指针、地址、结构体等概念。递归方式的链表反转代码简介,适合新手练习递归思路及写法。

链表结构及其方法的简单实现

链表的结构及其简单,但仍需注意细节,譬如分配新内存空间时需要if (n == NULL)以检测是否分配成功(这也是编写其他C语言程序时一重要良好习惯)。

typedef struct node {
    int value;
    struct node* next;
} Node;

Node* create_list(int value) {
    Node* n = malloc(sizeof(Node));
    if (n == NULL) perror("allocation error");

    n->next = NULL;
    n->value = value;
    return n;
}

Node* push_back(Node* root, int value) {
    Node* n = malloc(sizeof(Node));
    if (n == NULL) perror("allocation error");

    Node* p;
    for (p = root; p->next != NULL; p = p->next);
    n->next = NULL;
    n->value = value;
    p->next = n;
    return p;
}

void delete_list(Node* root) {
    Node* p = root;
    while (p != NULL) {
        Node* temp = p;
        p = p->next;
        free(temp);
    }
}

反转链表的两种方式

使用循环

  • 反转链表最基础的写法。

通过根节点地址寻找到最后一个节点,从前往后依次反转。prev变量用以存储上一个节点的地址,cur变量用于存储当前节点地址。在每个循环中,创建一个临时变量temp以临时存储下一个节点的地址,将当前节点的next指针指向前一个节点以完成反转,再将prevcur变量分别迭代当前节点和下一个节点。当cur迭代至NULL时循环终止,最后返回的prev即为新的根节点。

Node* reverse_list(Node* root) {
    Node* cur = root;
    Node* prev = NULL;
    while (cur != NULL) {
        Node* temp = cur->next;
        cur->next = prev;
        prev = cur;
        cur = temp;
    }
    return prev;
}

使用递归

  • 十分简短但需要一定理解

递归程序通常比循环程序更加简短,但会带来一定程度上阅读者理解的困难。

对于递归程序,首先要写好停止条件,不然会陷入循环无法终止。反转链表的递归终止条件即为cur == NULL。每一次递归中,我们需要给函数传入当前节点的地址以及上一个节点的地址(否则无从获取),创建临时变量temp存储当前节点地址,将当前节点下一个节点的地址改为上一个节点的地址。随后对原来下一个节点调用递归函数。最后终止时返回的prev即为新的根节点地址。

Node* reverse_list_recursively(Node* cur, Node* prev) {
    if (cur == NULL) return prev;

    Node* temp = cur->next;
    cur->next = prev;
    return reverse_list_recursively(temp, cur);
}