题目描述
Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K=3, then you must output 3→2→1→6→5→4; if K=4, you must output 4→3→2→1→5→6.
Input Specification:
Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (≤) which is the total number of nodes, and a positive K (≤N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.
Then N lines follow, each describes a node in the format:
Address Data Next
where Address is the position of the node, Data is an integer, and Next is the position of the next node.
Output Specification:
For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.
Sample Input:
00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
Sample Output:
00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1
题目分析
对链表进行逆置
链表是以静态链表的方式给出的,可以继续用静态链表也可以存到动态链表里
存储在静态链表
法一 data[address] next[address]
法二 struct node{int data,int next}Nodes[5] 结构体数组的下标就是节点的地址
逆置方法
一个入门的方法:swap(i,i+K) ,swap(i+1,i+K-1)swap(i+2,i+K-2)
一个重要的思想:链表不好处理,可以放到数组里
于是就放到数组里,然后相当于对数组进行逆置,reverse()函数
于是总体的方法是
读入静态链表
按照节点顺序存储到数组(vector)中
逆置
生成next地址
输出
问题
节点(addr,data,next)是存储在一起的,我们是要改变链表节点的顺序,而一旦改变节点的顺序,这个next就变了(但是data和地址是不变的),因此需要重新生成一下next节点
输出00001 printf("%05d",data); 但是如果是-1,需要单独来进行输出
对于for循环中,只能循环到 sum- sum%k的地方,这个终止条件很好,也可以是用一下min函数
reverse(it,min(it+k,array.end()));(但是会超时,也是慎用)
思考与收获
对于终止条件一定要判断好!
min有时候会超时
思路先理清晰再写代码
静态链表可以用数组来存,链表也是
代码
刚开始有俩测试点不能通过
后来修改了终止条件,才通过
可以见到终止条件十分重要
#include <iostream>
#include <vector>
#include<algorithm>
#include <iterator>
using namespace std;
struct node{
int data;
int next;
}List[100005]; //为何多加5个?
int main() {
// 首先将静态链表读入
// 两种方法读入静态链表
int initaddress,num,k;
scanf("%d %d %d",&initaddress,&num,&k);
int addr,data,next;
for(int i=0;i<num;i++)
{
scanf("%d %d %d",&addr,&data,&next);
List[addr].data = data;
List[addr].next = next;
}
// 将静态链表转为数组,数组的排序是链表的排序,数组的内容是节点的 地址 和 数据
// 由于不一定所有的节点都是有效的,不可以直接去以num为个数进行循环,转为判断next是否等于-1即可
vector<vector<int>> array ;
int sum=0;
int addr1 = initaddress;
int nextaddr=-2;
while(nextaddr!=-1)
{
vector<int> temp;//保存data和地址
temp.push_back(List[addr1].data);
temp.push_back(addr1);
array.push_back(temp) ;
nextaddr = List[addr1].next;
addr1 = nextaddr;
sum++;
}
// 对数组的部分进行reverse,由于
int i=0;
for(vector<vector<int>> ::iterator it= array.begin() ;it!=array.end();it+=k)
{
i+=k;
if(i>sum)//边界条件不能判断出错 i=sum的时候,当然是不能中断的了
{
break;
}
// reverse(it,min(it+k,array.end()));//直接用这个会超时!
reverse(it, it+k );
}
// 这个时候是新的顺序,但是不是静态链表形式,压根没有next地址,next地址是下一个,生成一下
int newnextaddr[num+2];
int j=0;
for(auto it:array)
{
newnextaddr[j++] = it[1];
}
newnextaddr[j++] = -1;
int m=1;
for(auto it:array)
{
if(newnextaddr[m]==-1)
{
printf("%05d %d %d\n",it[1],it[0],-1);
} else{
printf("%05d %d %05d\n",it[1],it[0],newnextaddr[m]);
}
m++;
}
return 0;
}
更简洁的代码(但不好理解)重点在17行
#include <iostream>
using namespace std;
int main() {
int first, k, n, sum = 0;
cin >> first >> n >> k;
int temp, data[100005], next[100005], list[100005], result[100005];
for (int i = 0; i < n; i++) {
cin >> temp;
cin >> data[temp] >> next[temp];//用data[],next[]来存储静态链表
}
while (first != -1) {
list[sum++] = first;
first = next[first];
}
for (int i = 0; i < sum; i++) result[i] = list[i];//复制一下数组
for (int i = 0; i < (sum - sum % k); i++)// i 的范围是这个!很好
result[i] = list[i / k * k + k - 1 - i % k];// k-1 - i%k
for (int i = 0; i < sum - 1; i++)
printf("%05d %d %05d\n", result[i], data[result[i]], result[i + 1]);
printf("%05d %d -1", result[sum - 1], data[result[sum - 1]]);
return 0;
}