- 重点是使用虚拟头结点,这样如果整个链表是个空链表,处理起来也会保持代码一致
- 内部处理过程是一个复杂过程
- 要定义一个当前结点,要通过这个当前结点
cur
,把其后要交换的两个结点获取到 - 通过当前结点,定义两个变量,
node_1st
,和node_next_1st
node_1st = cur->next;
表示要交换的第一个结点node_next_1st = cur->next->next->next;
表示在交换区域外的准备交换的第一个结点- 交换区域外是指准备交换两个结点之外的,准备下一次交换两个结点所在区域
- 交换过程:
cur->next = cur->next->next;
让当前结点指向交换区域的第二个结点,也就是与第一个结点断开链接cur->next->next = node_1st;
让原第二个结点指向原第一个结点(链接反转)node_1st->next = node_next
让原第一个结点指向交换区域外的第一个结点,这个代码相比于老师提供的做了优化,要检测是否正确cur = node_1st;
让当前结点移动到已经交换位置后的第二个结点上,也就是让其移动到准备下一次交换的两个结点前的一个结点上
- 上面的过程不看混是不可能的吧,可以参照网站的图片和B站上的视频来加深理解吧
#include <iostream>struct ListNode {int val;ListNode* next;ListNode(): val(0), next(nullptr) {}ListNode(int v): val(v), next(nullptr) {}ListNode(int v, ListNode* node): val(v), next(node) {}
};class Solution {
public:ListNode* swapPairs(ListNode* head) {ListNode* visualHead = new ListNode(0);visualHead->next = head;for(ListNode* cur = visualHead, *node_1st, *node_next_1st; cur->next != nullptr && cur->next->next != nullptr; cur = node_1st) {node_1st = cur->next;node_next_1st = cur->next->next->next;cur->next = cur->next->next;cur->next->next = node_1st;node_1st->next = node_next_1st;}ListNode* ret_head = visualHead->next;delete visualHead;return ret_head;}void show(ListNode* head) {for (auto* p = head; p != nullptr; p = p->next)std::cout << p->val << " ";std::cout << std::endl;}
};
int main()
{ListNode* head = nullptr;for (int val; std::cin >> val; head = new ListNode(val, head));Solution s;head = s.swapPairs(head);s.show(head);return 0;
}
- 测试数据:录入数据5 4 3 2 1 a,会生成1->2->3->4->5这样一个链表,字母a表示数据录入结束
- 汇总