Lc-143重排链表
问题描述 :
给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
给定链表 1->2->3->4, 重新排列为 1->4->2->3.
示例 2:
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.
可使用以下代码,完成其中的reorderList函数,其中形参head指向无头结点单链表。
#include<iostream>
using namespace std;
struct ListNode
{
int val;
ListNode *next;
ListNode() : val(0), next(NULL) {}
ListNode(int x) : val(x), next(NULL) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
class Solution
{
public:
void reorderList(ListNode* head)
{
//填充本函数完成功能
}
};
ListNode *createByTail()
{
ListNode *head;
ListNode *p1,*p2;
int n=0,num;
int len;
cin>>len;
head=NULL;
while(n<len && cin>>num)
{
p1=new ListNode(num);
n=n+1;
if(n==1)
head=p1;
else
p2->next=p1;
p2=p1;
}
return head;
}
void displayLink(ListNode *head)
{
ListNode *p;
p=head;
cout<<"head-->";
while(p!= NULL)
{
cout<<p->val<<"-->";
p=p->next;
}
cout<<"tail\n";
}
int main()
{
ListNode* head = createByTail();
Solution().reorderList(head);
displayLink(head);
return 0;
}
输入说明 :首先输入链表长度len,然后输入len个整数,以空格分隔。
输入范例 :
1 2 3 4 5
输入范例 :
head-->1-->5-->2-->4-->3-->tail
思路:
1.找到链表的中间节点
2.将中间节点之后的节点进行反转
3.按照要求依次合并前半截链表和后半截链表
因此,需要写2个函数:找到链表的中间的节点,反转链表。
使用快慢指针:使用两个指针变量,刚开始都位于链表的第 1 个结点,一个永远一次只走 1 步,一个永远一次只走 2 步,一个在前,一个在后,同时走。这样当快指针走完的时候,慢指针就来到了链表的中间位置。

本题使用的是后者:
private: ListNode *midOfList(ListNode *head){ //用快慢指针求中间结点 ListNode *slowTemp = head; ListNode *fastTemp = head;
while(fastTemp->next && fastTemp->next->next){ slowTemp = slowTemp->next; fastTemp = fastTemp->next->next; } return slowTemp; }
2.反转链表(参考)
利用两个指针来反转
private: ListNode *reverseList(ListNode *head){ //反转之后为链表的尾结点,故要定义一个指针指向NULL ListNode *tail = NULL; ListNode *cur = head;//当前要反转的结点 while(cur){ ListNode *nextCur = cur->next; //将结点放在尾部 cur->next = tail; tail = cur;//tail指向反转后的节点cur //cur指针后移,等待处理下一个结点 cur = nextCur; } return tail; }
3.合并链表
链接:合并两个有序链表(使用递归的思想)
本题:需要依次合并链表中的节点

private: void mergeList(ListNode *l1, ListNode *l2){ // 将后半部分的结点插入前半部分结点之后 ListNode *tmp1 = NULL; ListNode *tmp2 = NULL; while(l1 && l2){ //存储next节点 tmp1 = l1->next; tmp2 = l2->next; //连接节点 l1->next = l2; l2->next = tmp1; //指针后移 l1 = tmp1; l2 = tmp2; } } };
因此,整体代码为
class Solution { public: //填充本函数完成重排链表 //利用找链表的中间结点和反转链表 void reorderList(ListNode *head) { //特殊情况判断:空链表 if(head == NULL){ return; } //1.寻找链的中间结点 ListNode *midNode = midOfList(head); //p指向链表 ListNode *fronts = head; //q指向中间结点 ListNode *latter = midNode->next; midNode->next = NULL; //2.对中间结点的后半部分进行反转 latter = reverseList(latter); //3.按顺序合并处理好的链表 mergeList(fronts, latter); } private: ListNode *midOfList(ListNode *head){ //用快慢指针求中间结点 ListNode *slowTemp = head; ListNode *fastTemp = head; while(fastTemp->next && fastTemp->next->next){ slowTemp = slowTemp->next; fastTemp = fastTemp->next->next; } return slowTemp; } private: ListNode *reverseList(ListNode *head){ //反转之后为链表的尾结点,故要定义一个指针指向NULL ListNode *tail = NULL; ListNode *cur = head;//当前要反转的结点 while(cur){ ListNode *nextCur = cur->next; //将结点放在尾部 cur->next = tail; tail = cur;//tail指向反转后的节点cur //cur指针后移,等待处理下一个结点 cur = nextCur; } return tail; } private: void mergeList(ListNode *l1, ListNode *l2){ // 将后半部分的结点插入前半部分结点之后 ListNode *tmp1 = NULL; ListNode *tmp2 = NULL; while(l1 && l2){ //存储next节点 tmp1 = l1->next; tmp2 = l2->next; //连接 节点 l1->next = l2; l2->next = tmp1; //指针后移 l1 = tmp1; l2 = tmp2; } } };

浙公网安备 33010602011771号