题目:
给定一个单链表L: L0→L1→…→Ln-1→Ln, 重新排列后为:L0→Ln→L1→Ln-1→L2→Ln-2→…必须在不改变节点值的情况下进行原地操作。样例:给出链表 1->2->3->4->null,重新排列后为1->4->2->3->null。
思路:
1、首先找到链表中心节点,将链表分为两半(1->2->null和3->4->null)
方法是设置两个快慢指针,slow每次走一步,fast每次走两步,当fast==null(奇数个节点)或者fast->next==null(偶数个节点)时,slow刚好走到前一半链表的最后一个(2)。然后将链表拆开,此时注意先将后半部分链表的头结点设为slow的下一节点,然后将slow的下一节点置为空(这样前半段链表才有结束);
2、将后半段链表反转(参考链表反转的程序,链表反转)
3、将两个链表合并,实际上就是将第二个链表的每个节点依次插入第一个链表每个节点后面。
用两个指针进行操作,先保存下p2的下一节点(temp),然后令p2指向p1的下一节点,下一步才可以改变p1的指向,使其指向p2,然后p1=p2->next,指向第一个链表的原第二个节点,然后p2=temp,指向第二个链表的原第二个节点。直到p2为空,停止循环。合并完毕。
注意:当原链表有奇数个节点,第一步完成后拆分的两个链表,链表一比链表二多一个节点,所以循环的结束条件是判断p2是否为空,当第二个链表遍历完才表示合并全部做完。
ListNode* ReverseList(ListNode* pHead) {
if(pHead == NULL || pHead->next == NULL)//特殊情况:空链表,只有一个节点的链表
return pHead;
ListNode* pNode = pHead;//当前节点
ListNode* pNext;//下一节点
ListNode* pPre=NULL;//前一节点
ListNode* pNewHead;//新的链表头结点
while(pNode)
{
pNext = pNode->next;
if(pNext==NULL)
pNewHead=pNode;
pNode->next = pPre;
pPre = pNode;
pNode = pNext;
}
return pNewHead;
}
ListNode* reorder(ListNode* pHead)
{
//特殊情况:空链表,只有一个节点,只有两个节点。直接返回
if(pHead==NULL || pHead->next==NULL || pHead->next->next==NULL)
return pHead;
//将链表一分为二
ListNode* pHead2=NULL;//后半段链表的头指针
ListNode* slow=pHead;
ListNode* fast=pHead->next;//这样保证结束时slow指向的前半段链表的最后一个节点,而不是后半段链表的第一个,不然没法将前半段链表的最后一个节点指向空节点
while(fast && fast->next)
{
slow=slow->next;
fast=fast->next->next;
}
pHead2=slow->next;//保存下后半链表的头指针
slow->next=NULL;//让前半链表的最后一个节点指向空指针
//后半链表进行反转
pHead2=ReverseList(pHead2);
//两个链表的合并
ListNode* p1=pHead;
ListNode* p2=pHead2;
ListNode* temp;
while(p2) //注意循环结束的条件
{
temp=p2->next;
p2->next=p1->next;
p1->next=p2;
p1=p2->next;
p2=temp;
}
/*
if(p2)
{
p1->next=p2;
}
*/
return pHead;
}