C++链表02:反转链表

1.背景

大家好,我是酒馆店小二。

力扣206.翻转链表。
题意:反转一个单链表。
示例:
输入: 2->3->4->5->NULL
输出: 5->4->3->2->NULL
在这里插入图片描述

2.迭代

在这里插入图片描述

如图,

  • 定义pre指针,初始化为 nullptr
  • 定义cur指针,指向头结点;
  • 定义temp指针,指向cur->next节点,为什么要指向这个节点?因为接下来要改变cur->next的指向,将cur->next指向pre;
  • 重复执行上述操作,不断后移precur指针,直到cur指向nullptr,循环结束,链表反转完毕,返回pre指针即可。
    在这里插入图片描述

说一千道一万,没有代码都不算。

迭代代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
ListNode* reverseList(ListNode* head) {
    ListNode* pre = nullptr;  // 定义 pre 指针,初始化为 nullptr;
    ListNode* cur = head;  // 定义 cur 指针,指向头结点;
    while(cur) {
        ListNode* tmp = cur->next;  // 定义 temp 指针,指向 cur->next 节点
        cur->next = pre;
        pre = cur;  // 后移 pre 和 cur 指针
        cur = tmp;
    }
    return pre;
}

3.递归

递归版本稍微复杂一些,其关键在于反向工作。假设链表的其余部分已经被反转,现在应该如何反转它前面的部分?

假设链表为:
n1→…→n k−1→n k→n k+1 →…→n m →∅
若从节点 n k+1 到 n m已经被反转,而我们正处于 n k 。
n1 →…→n k−1 →n k →n k+1 ←…←n m
我们希望 n k+1的下一个节点指向 n k。
所以,nk→next→next = nk。
需要注意的是 n 1的下一个节点必须指向 ∅。如果忽略了这一点,链表中可能会产生环。

ListNode* reverseList(ListNode* head) {
    if (!head || !head->next) return head;
    // 递归调用,翻转第二个节点开始往后的链表
    ListNode* newHead = reverseList(head->next);
    // 反转头节点与第二个节点的指向
    head->next->next = head;
    // head节点指针指为空,因为它已经被它的下一个节点指向了,理论上它就是尾结点
    // 因为通过递归操作找到的就是尾结点,并且反转尾结点
    head->next = nullptr;
    return newHead;
}

4.进阶:反转链表内指定区间

将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)
例如:
给出的链表为 1→2→3→4→5→NULL,m = 2,n = 4,
返回 1→4→3→2→5→NULL。

解题思路:

  1. 判断参数 head 是否为空,若空则直接返回;判断m是否等于 n,相等则无需进行操作,直接返回;
  2. 创建一个头结点 dummyHead ,以便对整个链表的操作实现统一;
  3. 指针begin初始化为头节点 dummyHead,begin 将作为待反转链表第一个结点的前驱指针。然后通过变量 i (初始化为 0 )记录当前遍历的结点个数,顺序遍历链表的前 m -1个结点时,begin 不断向前移动,最终指向第 m - 1 个结点;
  4. 指针 start 指向待反转链表的第一个结点,初始化为 begin->next ;指针 finish 指向待反转链表的最后一个结点,初始化为 begin。然后在顺序遍历到第 n 个结点的过程中,finish不断向前移动,直到指向第 n 个结点。
  5. 指针 end 指向待反转链表的最后一个结点的下一个位置;

反转链表:

  • 初始时,指针 pre 指向 start,指针 cur 指向 start->next,begin->next = nullptr,finish->next = nullptr;
  • 反转过程: tmp = cur->next; cur->next = pre;pre = cur;cur = tmp
  • 结束条件:cur == finish
  • 最后一步:将反转后的链表与其余 begin 之前的链表和 end 之后的链表进行连接:
    begin->next = finish; start->next = end;

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

ListNode *reverseBetween(ListNode *head, int m, int n) {
    if (!head || m == n) return head;
    
    ListNode *dummyHead = new ListNode(-1);
    dummyHead->next = head;  // 创建链表的头结点
    ListNode *begin = dummyHead;  // begin 初始化为虚拟头结点
    
    int i = 0;
    while (i < m - 1) {
        begin = begin->next;  // 循环结束,begin 指向第 m - 1个节点,即待反转链表前一个节点
        ++i;
    }
    
	ListNode *start = begin->next;
    ListNode *finish = begin;
    while (i < n) {
        finish = finsh->next;   // 循环结束,finish 指向第 n 个节点,即待反转链表最后一个节点
        ++i;
    }
    ListNode *end = finish->next;  // end 指向待反转链表最后一个节点之后的一个节点
    
    ListNode *pre = start;
    ListNode *cur = start->next;
    begin->next = nullptr;
    finish->next = nullptr;
    
    while (pre != finish) {
        ListNode *tmp = cur->next;
        cur->next = pre;
        pre = cur;
        cur = tmp;
    }
	begin->next = finish;
    start->next = end;
    head = dummyHead->next;
    delete dummyHead;
    return head;
}

当时轻别意中人,山长水远知何处。
2022.3.23

  • 7
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
c 头插法链表是一种将链表进行倒置的方法。具体实现可以参考以下代码: ```c link *reverse(link *head) { link *new_head = NULL; link *temp = NULL; if (head == NULL || head->next == NULL) { return head; } while (head != NULL) { temp = head; //将 temp 从 head 中摘除 head = head->next; //将 temp 插入到 new_head 的头部 temp->next = new_head; new_head = temp; } return new_head; } ``` 这段代码使用了头插法的思路实现链表。通过遍历原链表,每次将头部的节点摘下并插入到新链表的头部,最终得到了一个后的链表。你可以将原链表的头节点作为参数传入该函数,函数将返回后的链表的头节点。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [字节跳动链表--头插法c++](https://blog.csdn.net/weixin_44026260/article/details/108450549)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [链表的4种方法c++实现](https://blog.csdn.net/wodazhouyi/article/details/119654297)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值