思路:
(1)找到链表中心点,如果链表节点为奇数,那么要保证前面要比后面多一个节点。
(2)将后一部分的结点进行反转。
(3)将反转后的结点插入前一部分的结点。
(1)找链表中心
找链表中心,主要使用快慢指针,当快指针以两倍速度出发,指针指向末尾的时候,慢指针正好指向中心。难点主要是考虑停止条件。因为快指针有可能最后一次不能移动2步,所以移动一步后就要判断是否为空,不为空继续移动,移动后也有可能为空或者不为空这两种情况,所以循环的条件就是快指针为空,或者让快指针下一步为空,这样就能保证循环条件符合要求了。最后返回慢指针。
ListNode* findmid(ListNode* head)
{
ListNode* fast = head;
ListNode* slow = head;
while (fast->next != nullptr&&fast!=nullptr)
{
slow = slow->next;
fast = fast->next;
if (fast->next != nullptr)
fast = fast->next;
}
return slow;
}
(2)反转链表
这里使用递归的方式,直接反转。
ListNode* reverseList(ListNode* head) {
if (!head || !head->next) {
return head;
}
ListNode* newHead = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return newHead;
}
(3)插入链表
插入链表是最复杂的一步,因为当你修改一个结点的next的时候,会覆盖掉后面的所有元素,所以最重要的就是提前保存后面的元素,并在移动中循环起来这一过程。这里新增两个指针,一个为temp它的作用是保存主链中的下一个元素,一个为pre的它作用是保存副链中的下一个元素。总的来说主链必须指向副链(head->next = newHead),这个时候就必须要有一个变量,保存主链后一个结点(ListNode* temp = head->next),每次结束后要将主链指向后一个(head = temp)。同理每一次主链作用一次后,副链也要指向主链一次(pre->next = head),副链也要做移动(pre = newHead,newHead = newHead->next)。
ListNode* cut(ListNode* head, ListNode* newHead)
{
ListNode* pre = new ListNode(0);
pre->next = head;
while (head != nullptr && newHead != nullptr)
{
ListNode* temp = head->next;
pre->next = head;
head->next = newHead;
pre = newHead;
head = temp;
newHead = newHead->next;
}
if (head != nullptr)
{
pre->next = head;
}
return head;
}
(4)总的主函数
中间有一个断链的操作。
void reorderList(ListNode* head) {
ListNode* mid = findmid(head);
ListNode* next = mid->next;
mid->next = nullptr;
ListNode* newHead = reverseList(next);
ListNode* newnewHead = cut(head, newHead);
}