1025 反转链表
记录一道瞎研究了一下午的题…方法比较笨,但好歹是独立把自己的思路实现出来了
给定一个常数 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 (≤105)、以及正整数 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
结尾无空行
思路
创建二维map,map键值表示地址,第一个位置存值,第二个位置存下一个元素地址。检测有效点数。每一小段进行逆序前,先记录首位地址,从第二位开始逆序,本小段全部逆序后令首位元素后件为下一小段第一个元素,最后令上一小段逆序后最后一个元素后件为本小段逆序后第一个元素。
#include <iostream>
#include <map>
using namespace std;
int main(){
string fir;
int n, k, count = 0;
map<string, map<int, string> > m; //二维map
cin >> fir >> n >> k;
//map键值表示地址,第一个位置存值,第二个位置存下一个元素地址
for(int i = 0; i < n; i++){
string t;
cin >> t;
cin >> m[t][0];
cin >> m[t][1];
}
//检测有效点数
string addre = fir;
while(addre != "-1"){
count++;
addre = m[addre][1];
}
string p = fir; //p为一个流动的指针
int flag1 = 0;
string flag2,flag4; //flag2存放最后输出时开始地址,flag3存放每次逆序前第一个元素地址
for(int i = 0; i < (count/k)*k; i+=k){
string flag3 = p; //存放本小段起始元素
string pre = p; //从第二个元素开始操作,第一个元素即前项
p = m[p][1]; //p移动到第二个元素
for(int j = 1; j < k; j++){
string temp = m[p][1]; //存放此元素的后项
m[p][1] = pre; //令此元素后项指向前项
pre = p; //此元素为下次判断的前项
p = temp; //p移动到下一个元素
}
//如果是第一轮循环
if(flag1 == 0){
flag2 = pre; //记录第一小段最后一个元素(即逆序后的第一个元素)
flag1 = 1;
}
m[flag4][1] = pre; //令上一小段逆序后的最后一个元素的后件为本小段逆序后的第一个元素
m[flag3][1] = p; //令本小段起始元素(即逆序后的最后一个元素)后件为下一小段第一个元素
flag4 = flag3; //记录本小段逆序后的最后一个元素
}
p = flag2; //p为操作完成后第一个元素
for(int i = 0; i < count; i++){
printf("%s %s %s\n",p.c_str(),m[p][0].c_str(),m[p][1].c_str());
p = m[p][1];
}
return 0;
}