【算法】反转链表的四种方法(C语言)


206. 反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

img

输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]

示例 2:

img

输入:head = [1,2] 输出:[2,1]

示例 3:

输入:head = [] 输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

方法一 原地反转

本题链表不带头结点

原地反转需要两个指针,以防pre指针操作后指向上一节点而丢失指向下一节点的指针
在这里插入图片描述

pre->next = cur->next:1.连:第一步先将pre所在节点和cur->next所在节点连接起来,将当前节点 cur 从链表中移除,并把链表连接起来。
在这里插入图片描述
cur->next = head:2.掉:将cur的next指向head,将cur插入到head的前面,以便将其放置到链表的前面,成为新的头节点。 在这里插入图片描述

head = cur;:3.接:更新head,使其指向当前的cur
在这里插入图片描述

cur = pre->next:4.移:更新cur,移动到下一个待反转的节点
在这里插入图片描述

struct ListNode* reverseList(struct ListNode* head) {
    if (head == NULL) {
        return head;
    }
    struct ListNode* cur = head->next; 
    struct ListNode* pre = head; 
    while (cur) {
        pre->next = cur->next; 
        cur->next = head; 
        head = cur;   
        cur = pre->next; 
    }
    return head; 
}

方法二 迭代

temp保存cur的下一个节点,以防止反转时丢失链表信息。
在这里插入图片描述

cur->next = pre;cur的下一个指针指向pre,实现反转。
在这里插入图片描述

更新pre为当前的cur,为下一次迭代做准备。
更新cur为保存的下一个节点temp,继续迭代。
在这里插入图片描述
通过不断改变指针的指向将链表进行反转。pre充当新链表的头节点,当curNULL循环停止,返回pre

struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode* pre = NULL;
    struct ListNode* cur = head;
    while (cur != NULL) {
        struct ListNode* temp = cur->next;
        cur->next = pre;
        pre = cur;
        cur = temp;
    }
    return pre;
}

方法三 递归

我们可以通过迭代的方法来得到递归方法
观察reverse函数:
函数声明中pre指针指向的为NULL,cur指针指向的为head,正如递归中声明并初始化的precur指针
递归结束条件为curNULL,返回pre
同样temp保存cur的下一个节点,以防止反转时丢失链表信息。
然后进行反转cur->next = pre;
pre 为当前已反转部分的头节点,cur为当前待反转的节点。
然后调用递归,将cur作为新的pre传入下一层,将temp作为新的cur传入下一层。
实现了链表的递归反转

struct ListNode* reverse(struct ListNode* pre, struct ListNode* cur) {
    if (!cur){
        return pre;
    }
    struct ListNode* temp = cur->next;
    cur->next = pre;
    //将cur作为pre传入下一层
    //将temp作为cur传入下一层,改变其指针指向当前cur
    return reverse(cur, temp);
}

struct ListNode* reverseList(struct ListNode* head) {
    return reverse(NULL, head);
}

方法四 新建链表法

struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
newNode->val = head->val;
新建一个链表,并初始化
newNode->next = newHead;将新节点插入到新链表的头部

在这里插入图片描述
newHead = newNode;
在这里插入图片描述
head = head->next;
在这里插入图片描述
遍历原链表,使用头插法新建链表,并不断移动newHead指针,当原链表头指针指向NULL最终返回newHead


struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode* newHead = NULL;
    while (head) {
        // 创建一个新节点
        struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
        newNode->val = head->val;        
        // 将新节点插入到新链表的头部
        newNode->next = newHead;
        newHead = newNode;
        // 移动到原链表的下一个节点
        head = head->next;
    }
    return newHead;
}


感谢您的阅读
如有错误烦请指正


以下是双向链表反转的 C 语言代码: ```c #include <stdio.h> #include <stdlib.h> struct Node { int data; struct Node* next; struct Node* prev; }; void printList(struct Node* node) { while (node != NULL) { printf("%d ", node->data); node = node->next; } printf("\n"); } void reverseList(struct Node** head) { struct Node* temp = NULL; struct Node* current = *head; while (current != NULL) { temp = current->prev; current->prev = current->next; current->next = temp; current = current->prev; } if (temp != NULL) { *head = temp->prev; } } int main() { struct Node* head = NULL; struct Node* first = (struct Node*)malloc(sizeof(struct Node)); struct Node* second = (struct Node*)malloc(sizeof(struct Node)); struct Node* third = (struct Node*)malloc(sizeof(struct Node)); first->data = 1; first->prev = NULL; first->next = second; second->data = 2; second->prev = first; second->next = third; third->data = 3; third->prev = second; third->next = NULL; head = first; printf("Original List: "); printList(head); reverseList(&head); printf("Reversed List: "); printList(head); return 0; } ``` 在这个代码中,我们定义了一个 `Node` 结构体,包含了数据、前驱指针和后继指针。`printList` 函数用于打印链表中的每个元素。`reverseList` 函数用于反转链表,该函数的参数是一个指向指针的指针,因为我们需要在函数内部改变链表头指针的值。 在 `reverseList` 函数中,我们使用 `temp` 变量来保存当前结点的前驱指针,因为我们需要在交换当前结点的前驱和后继指针后,把它赋给下一个结点的前驱指针。最后,我们需要更新链表头指针的值,否则我们会得到一个不完整的链表。 在 `main` 函数中,我们创建了一个简单的双向链表,并将其传递给 `reverseList` 函数来反转它。最后,我们使用 `printList` 函数来检查链表是否被正确地反转。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值