给定一个单链表 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
题解
适当参考了 https://blog.youkuaiyun.com/kz_java/article/details/87978705
https://blog.youkuaiyun.com/o_ohello/article/details/88372424
显然这是一个静态链表问题。
这里接触到了一个很妙的思想。
最开始读入是把地址当作数组下标来访问。这样确实有链表的感觉,并非顺序存储结构的状态。但遇到题中这种要求对链表第i个元素的操作就会变得很麻烦,每次都要从头开始循环,一旦进行拼接甚至会打乱原有顺序。
那我就想,要是可以像数组一样随机访问该多好。
其实真的可以。
原有链表有n个节点。我按着原有的链式前后顺序,一个一个向新建的数组里存,从下标1~N,每个位置存储的都是一个地址。下标为3,存的就是原有链表的第三节点的地址。而通过地址就可以在原有p结构数组中访问它的内容了。
这样,就可以像数组一样对链表任意位置的元素进行操作了。相当于按着链表原有顺序打造数组后,就把它们各自的联系切开了。
结构数组p[ i ]中的i(地址) | data | next |
---|---|---|
00000 | 4 | 99999 |
00100 | 1 | 12309 |
68237 | 6 | -1 |
33218 | 3 | 00000 |
99999 | 5 | 68237 |
12309 | 2 | 33218 |
two thousand years later~~~
address[i]中的i | value |
---|---|
1 | 00100 |
2 | 12309 |
3 | 33218 |
4 | 00000 |
5 | 99999 |
6 | 68237 |
不过这里的地址数组要遵循原有顺序的。
这样,对于6->1->5->2也就是走个循环而已。
主要问题已经解决了。
当然,只是想到这些并不能满分,如我在别人blog所了解的,几乎所有链表问题,都会考到一个东西:无效节点。这里也是,所以还要自己处理。不过这就算是代码的细枝末节了,也不想再多说。
ac代码
#include<bits/stdc++.h>
using namespace std;
struct node{
int data;
int next;
}p[200000];
int address[200000],ans[200005]; //address数组单纯用来装原有地址序列(方便访问)
//ans数组装的是最终结果的地址序列
int main()
{
int head,N;
cin>>head>>N;
int addr=-1,data,next=-1; //搭建最初的静态链表
for(int i=1;i<=N;i++)
{
cin>>addr>>data>>next;
p[addr].data = data;
p[addr].next = next;
}
for(int i=1;i<=N;i++) //组建原有地址序列
{
if(i==1)
{
address[1] = head;
addr = head;
}
else
{
addr = p[addr].next;
if(addr==-1) //有无效节点时会走这条路
{
N = i-1; //N小了,不会循环访问到了,也就相当于删去了
break;
}
address[i] = addr;
}
}
int top=0;
for(int i=N;i>N/2;i--) //重排的过程
{
ans[++top] = address[i]; //一个循环处理两个点(奇偶已考虑)
if(!(N-i+1==i))
ans[++top] = address[N-i+1];
}
for(int i=1;i<=N;i++)
{
printf("%05d %d ",ans[i],p[ans[i]].data); //鸡贼了一下
if(i!=N) printf("%05d\n",ans[i+1]); //我根本没有改节点的next
else printf("-1\n"); //我现在的数组就是最终序,那输出下标+1的地址不就是这里的next嘛
}
return 0;
}
最后再补充一下无效节点自己编的数据吧。
00100 6
00000 4 99999
00100 1 12309
33218 3 00000
99999 5 -1
12309 2 33218
88888 0 55555
若想看自己是否调整好了,不妨试试。结果是不该和88888那一行有关的。如果有,那就是还没调好。