题目链接:
24. 两两交换链表中的节点 - 力扣(LeetCode)
效果:
解题思路:
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
注意不可以只是单纯的改变节点内部的值,而是需要实际的对两个节点交换。
那需要有一定的交换顺序,先让12交换,其中交换时的顺序为,先把2放在开头,然后让1指向2的下一个结点,然后2再接1
这里使用虚拟结点比较好。第一步就是让虚拟结点指向2,然后接着上述步骤
然后1和2交换完之后,再接着把指针移到3的位置,让虚拟结点的下一个为3,接着按上述步骤执行,直到没有需要交换的即可
文字版分析好了,现在来看代码
使用的语言为c语言:
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* swapPairs(struct ListNode* head) { if(!head||!head->next) { return head; } struct ListNode* cur=(struct ListNode *)malloc(sizeof(struct ListNode)); cur->next=head; struct ListNode* q=head; struct ListNode* p=cur; while(p&&q&&q->next) { p->next=q->next; q->next=p->next->next; p->next->next=q; p=q;// q=p->next; } return cur->next; }
这个代码其中有很多地方需要注意:
1. 为什么要先建一个指针p来存储cur这个虚拟指针呢?
原因是——当转换链表后之前的head指针指向的不是链表的开头了,这时候要是返回head指针就不对了,而且如果只用cur指针的画,cur指针也在不断变换着,没办法保证返回的是整个链表。
2.为什么要让while循环的条件有q->next?
首先q是指向p指针的下一个结点的,而p结点是指向需要互换的第一个结点(就比如1、2中的1和3、4中的3)
在某种情况下(12345的情况),如果把3、4交换完,则p指向3,q指向5,5是不需要再交换的,这时候其实就可以退出了。所以条件上要加一个q->next
方法2:递归法:
这里由于每两个的步骤都是一样的,所以可以使用递归的方法来完成,当头结点不存在或者下一个结点不存在则不需要交换了。
struct ListNode* swapPairs(struct ListNode* head){
//头节点不存在或头节点的下一个节点不存在。此时不需要交换,直接返回head
if(!head || !head->next)
return head;
//创建节点-指针类型来保存头结点下一个节点
struct ListNode *newHead = head->next;
//更改头结点加2位节点后的值,将头结点的next指针指向这个更改过的list
head->next = swapPairs(newHead->next);
//将新的头结点的next指针指向老的头节点
newHead->next = head;
return newHead;
}