class Solution {
public ListNode swapPairs(ListNode head) {
//定义一个虚拟结点
ListNode dummy = new ListNode(-1);
//定义一个前结点指针 pre
ListNode pre = null;
//定义一个当前结点指针 cur
ListNode cur = null;
//初始化位置
//让虚拟结点和head结点链接,最后直接返回虚拟结点的下一个结点即是头结点
dummy.next = head;
//pre的初始位置,是当前虚拟结点,
// 即当前结点的前面的结点,
// 即操作的两个结点的前面的一个结点,来维护操作的两个结点和前面结点的关系的
pre = dummy;
//当前结点,指向当前操作的两个结点中的第一个结点,初始化是dummy.next,即head头结点
// 也可以写为cur = head;
cur = dummy.next;
//这里是核心操作!!!
// 判断条件是结点非空,当前结点的后的一个结点非空,
// 即保证操作的元素必须是两个结点的单位,1-2 3-4
// 如果是只有一个结点,则不操作,
// 如果是空结点也不操作
while(cur != null && cur.next != null){
//声明一个last结点指针,主要是操作两个两个结点的后一个结点,
// last的初始位置是cur的下一个结点
ListNode last = cur.next;
//当前结点的next指针指向last的下一个元素,即cur结点的下一个结点的指针变化为第三个元素
//假设初始结点是0- 1 - 2 - 3 - 4 ,现在是 0-1-3-4 2
// 2结点的位置保存在last中
cur.next = last.next;
//last结点的next指针变成了当前结点 ,现在是 2-1
//还有上一个步骤结果 0-1-3-4
// 0-1-3-4
// \
// 2
last.next = cur;
//现在就是要链接两个片段
//pre结点的next指向了last结点,即虚拟结点指向了2结点 0-2-1 即0-2-1-3-4
//这样就完成了1 2 结点的位置互换
// 1-3-4
// \
// 2
// \
// 0
pre.next = last;
//接下来就是移动元素,开始操作3 、4元素
//pre指向当前结点,cur=1
//注意这里不是往后移了一位而是两位, pre指向了0-2-1-3-4 中的1
pre = cur;
//cur指针后移一位,就是3。这样就开始了以3-4为操作单元的的操作单元
cur = cur.next;
}
return dummy.next;
}
}
对比一个不太好的实现
public ListNode swapPairs(ListNode head) {
//前节点,为了让整个连接不要断掉
ListNode pre= new ListNode(0) ;
//当前需要交换的第一个节点
ListNode cur = new ListNode(0) ;
//前一个节点,要保持在cur前面,一遍两两交换的时候能够保持中间连接
pre.next=cur;
//第一个要交换的节点
cur=head;
//判断边界
if (head == null || head.next == null) {
return head;
}
while (cur != null && cur.next!= null) {
//第二个需要交换的节点
ListNode last =cur.next;
//交换1,2的节点
cur.next =last.next;
last.next = cur;
//保持基数位置的链接关系
pre.next=last;
//由于节点有位置移动,要扶正head的位置
if(cur==head){
head = last;
}
//前移一位
pre =cur;
//在交换过程中有移动了一个步骤,所以这块只移动一个位置
cur=cur.next;
}
return head;
}
递归
class Solution {
public ListNode swapPairs(ListNode head) {
//终止条件:链表只剩一个节点或者没节点了,没得交换了。返回的是已经处理好的链表
if(head == null || head.next == null){
return head;
}
//一共三个节点:head, next, swapPairs(next.next)
//下面的任务便是交换这3个节点中的前两个节点
ListNode next = head.next;
head.next = swapPairs(next.next);
next.next = head;
//根据第二步:返回给上一级的是当前已经完成交换后,即处理好了的链表部分
return next;
}
}