【算法-链表2】反转链表 和 两两交换链表节点

今天,带来链表相关算法的讲解。文中不足错漏之处望请斧正!

理论基础点这里


反转链表

1. 思路

链表操作的本质是修改连接关系,本题我们需要反转链表,也就是每次都让当前节点的next指向自己的上一个。而题目给的是单链表,所以我们需要始终记录前一个节点的地址,来满足当前节点被反转的条件;其次,我们当前节点迭代时要按原本顺序迭代。

2. 参考代码

class Solution6 {
public:
    ListNode *reverseList(ListNode *head) {
        // 每次都让当前节点的next指向前一个节点, 迭代时仍然向后迭代
        ListNode *prev = nullptr;
        ListNode *cur = head;
        ListNode *next = nullptr;
        while (cur != nullptr) {
            next = cur->next; // 保存, 等会要覆盖
            cur->next = prev; // 改变链接关系:让当前节点的next指向前一个节点
            prev = cur;
            cur = next; // 迭代时仍然向后迭代
        }
        return prev; // 当cur走到空, prev正好是最后一个节点, 即新的反转链表的头节点
    }
};

两两交换链表节点

1. 思路

像这种需要改变链接关系的场景,我们都可以给上一个虚拟头节点,来保证改变链接关系的逻辑相同。

具体如何交换呢?

在这里插入图片描述

1. 要能找得到

《移除链表元素》中,我们已经谈过,要操作节点1和节点2,我们必须要能找得到节点1和节点2

2. 统一操作逻辑

对单链表来说,当我们要从头开始操作的时候,逻辑和正常的交换不一样,所以我们选择加入虚拟头结点,来统一交换逻辑。操作逻辑是什么呢?如图。

在这里插入图片描述

3. 何时结束交换?

我们给一个cur,一开始指向dummyHead,它来操作后两个节点。

前提是后面还有两个节点可以操作,所以当cur->next != nullptr && cur->next->next != nullptr的时候我们可以进行操作,反之结束。

这里是有细节的:

  1. cur不可能为空,因为我们给他初始化为dummyHead
  2. cur→next的判断必须放在前面,因为表达式是从左到右判断,如果cur→next→next的判断放在前面,当cur→next==nullptr,对cur→next→next的判断就对空指针解引用了

4. 改变链接需谨慎

修改节点间的链接关系,很容易丢失节点或陷入死循环。

在这里插入图片描述

如上图,要交换1和2,操作应该是:

  1. cur指向2
  2. 2指向1
  3. 1指向3

对应代码就是

  1. cur->next = cur->next->next

这里其实已经出问题了!cur->next被修改,代表1是丢失了。后续我们还需要让1指向3,找不到1了就没法玩。

同理,直接让2指向1以后,3也丢失了,1和3都找不到了。怎么办?

我们可以提前保存,直接把1、2、3保存为node1、node2、node3。

也可以不保存节点2,因为cur指向2后,2是可以找到的,但我们这样写可读性高点。

最后,cur应该怎么迭代呢?

在这里插入图片描述

应该移动两位。

2. 参考代码

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode *dummy = new ListNode(-1, head);
        ListNode *cur = dummy;

        while (cur->next && cur->next->next) { // 后面还有两个节点才能交换
            ListNode *node1 = cur->next;
            ListNode *node2 = cur->next->next;
            ListNode *node3 = cur->next->next->next;

            cur->next = node2; // cur->node2
            node2->next = node1; // node2->node1
            node1->next = node3; // node1->node3

            cur = cur->next->next; // 移动2位
        }

        head = dummy->next;
        delete dummy;
        dummy = nullptr;
        return head;        
    }
};

今天的分享就到这里了,感谢您能看到这里。

这里是培根的blog,期待与你共同进步!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周杰偷奶茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值