PAT 1025 反转链表 (25)(STL-map+思路+测试点分析)

时间:2023-03-09 07:22:38
PAT 1025 反转链表 (25)(STL-map+思路+测试点分析)

1025 反转链表 (25)(25 分)

给定一个常数K以及一个单链表L,请编写程序将L中每K个结点反转。例如:给定L为1→2→3→4→5→6,K为3,则输出应该为3→2→1→6→5→4;如果K为4,则输出应该为4→3→2→1→5→6,即最后不到K个元素不反转。

输入格式:

每个输入包含1个测试用例。每个测试用例第1行给出第1个结点的地址、结点总个数正整数N(<= 10^5^)、以及正整数K(<=N),即要求反转的子链结点的个数。结点的地址是5位非负整数,NULL地址用-1表示。

接下来有N行,每行格式为:

Address Data Next

其中Address是结点地址,Data是该结点保存的整数数据,Next是下一结点的地址。

输出格式:

对每个测试用例,顺序输出反转后的链表,其上每个结点占一行,格式与输入相同。

输入样例:

00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218

输出样例:

00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1

思路: 如何实现链表的反转呢?难点在于每次反转next都要改变,这就很头疼了,其实我们只需要将连接好的链表按顺序存到一个顺序表中,反转顺序,本身的“地址“不变,next刚好就是顺序表下一个元素的“地址”,只是最后一个的next为NULL(-1);

1、输入结点:输入每一个结点的地址(嗯,这是个假地址0.0),数据,next,这里就全部用int了,为什么不用string呢?因为我不知道scanf怎么输入stringT.T

2、链接链表:这里我用map的key(不懂就理解成下标)索引来连接链表。注意输入的结点并不是全部有效,只需要记录有效值(测试点6答案错误)

3、反转链表:这里用reverse函数(反转数组的数据),直接进行反转。

4、输出链表:输出每行结点的格式为(当前结点地址_数据_下一结点地址(最后一个为-1));

注意:1、输入输出最好用scanf、printf,因为cin,cout有缓存。(测试点5运行超时)

测试点6推荐用例:

00001 5 3
00001 1 00002
00002 2 00003
00003 3 00004
00004 4 -1
99999 5 12345 //这个并不需要存到链表里
#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
struct Node {
int ads, data, next;
}node[100000];
int main() {
int n, k, str, start;
map<int, Node> m;
cin >> start >> n >> k;
for (int i = 0; i < n; i++) {
scanf("%d", &str); //输入结点数据
scanf("%d %d", &m[str].data, &m[str].next);
}
for (int i = 0; i < n; i++) {
node[i] = { start,m[start].data ,0 }; //通过map直接索引start将链表按顺序转到node数组里面
start = m[start].next;
if (start == -1) //当start被赋值为-1的时候,链表就结束了,更新n的值,测试点6
n = i + 1;
if ((i + 1) % k == 0)
reverse(node + i + 1 - k, node + i + 1); //反转
}
for (int i = 0; i < n; i++) { //输出
printf("%05d %d ", node[i].ads, node[i].data);
if (i != n - 1)
printf("%05d\n", node[i + 1].ads);
else
printf("-1"); //最后一个结点next为-1
}
return 0;
}