给定一个单链表 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
代码:
#include<stdio.h>
struct Node // 链表
{
int next, data;
} node[100001]; // 用下标表示地址
int main()
{
int start_address, num, temp;
scanf("%d%d", &start_address, &num);
for (int i = 0; i < num; i++) // 输入每个点
{
scanf("%d", &temp);
scanf("%d%d", &node[temp].data, &node[temp].next);
}
int order[num]; order[0] = start_address; // 新建一个数组 order 用来 按顺序 存储链表地址
for (int i = 1;; i++)
{
// 如果该节点的指向-1就break,同时更新有效节点的数量
if (node[order[i - 1]].next == -1) {num = i; break;}
order[i] = node[order[i - 1]].next;
}
int flag = -1, a = 0, b = num - 1; // 根据 order 的顺序来重新链接链表,a是头 b是尾;
for (int i = 1; i < num; i++, flag *= -1) // flag在-1 1反复横跳来表示从左/从右来连接
{
if (flag == -1) {node[order[b--]].next = order[a];}
else {node[order[a++]].next = order[b];}
} // 循环完之后 a,b 记录的就是排序结束后最后一个节点在order里的索引
// 把最后一个节点的指向设置为-1; temp用来记录当前读取到的节点地址
// (在这里temp应该为排序后第一个节点,应该为原先链表的最后一位)
node[order[a]].next = -1; temp = order[num - 1];
// 就可以依据链表一个一个输出了
for (int i = 1; i < num; i++)
{
printf("%05d %d %05d\n", temp, node[temp].data, node[temp].next);
temp = node[temp].next;
}
printf("%05d %d %d\n", temp, node[temp].data, node[temp].next);
return 0;
}
总结:
很明显链表的题(名字都叫链表了..)
但是因为他输入格式给的是节点的地址,所以我们就可以建立一个数组,用数组的下标来表示地址,方便省事。
讲讲思路:
对于这样一个链表,要右左右左的重排列,知道整个列表的顺序那就是必须的,所以我们用一个数组记录下顺序,依找此数组再循环两头轮流改变节点指向的地址就行。
但是我前几次写的时候一直一个点过不去。。。上网搜了搜才发现这题的坑点在于 他给的节点不一定是在链表内的 ,比如如下数据:
00100 6
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
11451 4 99999
这一点注意下就行了