题目:
Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
You must do this in-place without altering the nodes' values.
For example,
Given {1,2,3,4}
, reorder it to {1,4,2,3}
.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void reorderList(ListNode* head) {
if (NULL == head || NULL == head->next) return;
//找到中间点(快慢指针,快指针指向最后一个节点时,慢指针刚好指向中间节点)
ListNode *slow = head;//注意初始化值
ListNode *fast = head->next;//注意初始化值
while (fast && fast->next){
slow = slow->next;
fast = fast->next ? fast->next->next : NULL;
}
//如果节点个数为偶数,循环结束时fast->next为NULL,slow指向前一半的最后一个节点
//如果节点个数为奇数,循环结束时fast为NULL,slow指向中间节点
//无论以上哪种情况,slow都指向第一段链表的最后一节点
ListNode *headOfSecondHalf = slow->next;
slow->next = NULL;
//将后半部分反转
reverse(headOfSecondHalf);
//合并两部分
mergeTwoList(head, headOfSecondHalf);
}
private:
void reverse(ListNode *&head){//翻转链表,因为反转后head可能会改变,所以参数使用引用
if (NULL == head || NULL == head->next) return;
ListNode *p = head->next;//当前节点
head->next = NULL;//原链表的第一个节点变为最后一个节点
while (p){
ListNode *pNext = p->next;
p->next = head;
head = p;
p = pNext;
}
}
void mergeTwoList(ListNode *head1, ListNode *head2){//链表1和链表2交叉合并,并且链表2的节点放在链表1之后,并通过head1返回新链表。
if (NULL == head2) return;//在本题的环境下,head1不为NULL
ListNode *p1 = head1->next;
ListNode *p2 = head2->next;
//初始化新链表
head1->next = head2;
ListNode *last = head2;
last->next = NULL;
while (p1 && p2){
ListNode *p1Next = p1->next;
ListNode *p2Next = p2->next;
last->next = p1;
p1->next = p2;
last = p2;
last->next = NULL;
p1 = p1Next;
p2 = p2Next;
}
//两个链表可能不一样长,将较长链表的剩余部分连入新链表(当然在本题情况下,只存在两种可能:一两者一样长;二链表1比链表2多一个节点)
if (p1) last->next = p1;
if (p2) last->next = p2;
}
};