给定一个单链表 L1→L2→⋯→Ln−1→Ln,请编写程序将链表重新排列为 Ln→L1→Ln−1→L2→⋯。例如:给定L为1→2→3→4→5→6,则输出应该为6→1→5→2→4→3。
输入格式:
每个输入包含1个测试用例。每个测试用例第1行给出第1个结点的地址和结点总个数,即正整数N (≤105)。结点的地址是5位非负整数,NULL地址用−1表示。
接下来有N行,每行格式为:
Address Data Next
其中Address
是结点地址;Data
是该结点保存的数据,为不超过105的正整数;Next
是下一结点的地址。题目保证给出的链表上至少有两个结点。
输出格式:
对每个测试用例,顺序输出重排后的结果链表,其上每个结点占一行,格式与输入相同。
输入样例:
00100 6
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
输出样例:
68237 6 00100
00100 1 99999
99999 5 12309
12309 2 00000
00000 4 33218
33218 3 -1
我们需要先找到链表的中间节点,再把后半段链表反转(用头插法就行),怎么走到中间节点呢?直接循环n/2次?(那么就可能会wa3,他这个测试点有多个节点的next值都是-1,就是说可能会存在多个单节点的链表,很坑啊),按数据结构讲的知识,我们可以设置两个指针,一个指针p向前走一步,另一个指针q向前走两步,走到最后,p就会指向中间节点。
#include<bits/stdc++.h>
using namespace std;
const int N=100010,M=30*N,mod=1e9+7;
typedef long long LL;
int n;
int head,e[N],ne[N];
int main()
{
cin>>head>>n;
for(int i=0;i<n;i++)
{
int address,data,next;
cin>>address>>data>>next;
e[address]=data;
ne[address]=next;
}
int p=head,q=ne[head];
//我希望如果是奇数个节点,后半段链表的个数比前半段多1
//如果是奇数个节点 1 2 3 4 5
//最后 p 前半段为1,2,后半段为3,4,5
//如果是偶数个节点 1 2 3 4 5 6
// p 前半段为1,2,3,后半段为4,5,6
while(ne[q]!=-1)
{
q=ne[q];
if(ne[q]==-1) break;
q=ne[q];
p=ne[p];
}
q=ne[p],ne[p]=-1;
int hh=-1;
//逆置后半段链表
while(q!=-1)
{
p=ne[q];
ne[q]=hh;
hh=q;
q=p;
}
p=head,q=hh;
//把前半段链表插入后半段链表中。
while(p!=-1)
{
int pp=ne[p],qq=ne[q];
ne[p]=ne[q];
ne[q]=p;
p=pp,q=qq;
}
p=hh;
while(p!=-1)
{
printf("%05d %d ",p,e[p]);
if(ne[p]==-1) cout<<-1<<endl;
else printf("%05d\n",ne[p]);
p=ne[p];
}
return 0;
}