题目链接:
https://pintia.cn/problem-sets/994805260223102976/problems/994805296180871168
思路:
首先审题,由于地址是手动输入的缘故,本题采用数组的方式更为简单,每一个节点可以看成数组内的元素,采用结构体数组的方式进行链表数据的存储,在最初存储链表时,每一个数据的地址作为其在数组中的位置,方便后续进行查找。
设计两个结构体数组a[],b[],结构体内元素包括:address,data,next;
数组a用来存储输入的数据,数组b则用来整理数据以及翻转,在这里需要注意支节点的问题,因为链表会有游离在外的节点,使用sum进行统计一个完整的链表上节点的个数。
本题的翻转可以采用reverse()方法进行翻转,简单又快捷;
还需要注意的是翻转的次数,翻转距离为K,链表的数据量为sum,数组下标i在每次循环时要+K,循环量j要小于sum/K,(也就是算sum中有几个K啦,小学数学问题);
最后再进行输出,注意输出格式就可以了。
填坑日记:
多日不见的碎碎念,没错我又回来了。。。
好久不写代码感觉整个人都懵,这题其实挺有意思的,用数组解的话考到的不仅是数组+结构体,还有你对链表的理解程度,在使用翻转函数之后,结构体数组内的地址并不会随之改变(毕竟结构体数组里面的next不是真的next),需要我们手动进行指向的改变,(我之前就是没注意到这一点,死活不ac,用链表用多了就不太注意地址需要自己改变的这个事情了),ac之后感觉自己代码又臭又长哈哈哈哈,结构体里面放两个变量就可以了,Address不需要加进去,毕竟数据a的下标就是Address了没必要再用一个空间去存储,浪费啊。
再是有关测试点的问题(正经脸),
测试点0~4感觉就是常规测试点,把测试用例通过了基本都能过;
第5个测试点则是大量的数据,边界测试一类的,可能有游离在外的节点的情况(因为我把支节点问题解决之后,5,6都通过了);
测试点6就是考察存在支节点的问题,呜呜呜就是这个,坑了我半个上午,也是因为我太久没写代码脑袋都生锈了的缘故吧(卑微)。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
typedef struct LinkList{
int Address;
int Number;
int Next;
}List;
List a[100001];
List b[100001];
void answer(){
int A,K,N,address,number,next,i;
scanf("%d%d%d",&A,&N,&K);
for(i=0;i<N;i++){//写入
scanf("%d%d%d",&address,&number,&next);
a[address].Address=address;
a[address].Number=number;
a[address].Next=next;
}
b[0]=a[A];
int sum=1;
for(i=1;i<N;i++,sum++){
b[i]=a[b[i-1].Next]; //按顺序赋值
if(b[i].Next==-1)
{
sum++;
break;
}
}
for(int j=0,i=0;j<sum/K;j++){
reverse(b+i,b+i+K); //反转一下
i=i+K;
}
for(i=0;i<sum-1;i++){
b[i].Next=b[i+1].Address; //改变指向
}
b[sum-1].Next=-1;
for(i=0;i<sum;i++){
if(b[i].Next>=0)
printf("%05d %d %05d\n",b[i].Address,b[i].Number,b[i].Next);
else
printf("%05d %d %d\n",b[i].Address,b[i].Number,b[i].Next);
}
}
int main(){
answer();
return 0;
}
下面进行膜拜大佬代码的环节:
因为大佬的代码太好了,我进行了购买,在这里就不去找网上的链接了(捂脸),没错,我买的是柳大神的,想看她博客的同学可以在我以前的博客里找,我放了链接。
代码:
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int first, k, n, temp;
cin >> first >> n >> k;
int data[100005], next[100005], list[100005];
for (int i = 0; i < n; i++) {
cin >> temp;
cin >> data[temp] >> next[temp];
}
int sum = 0;
while (first != -1) {
list[sum++] = first;
first = next[first];
}
for (int i = 0; i < (sum - sum % k); i += k)
reverse(begin(list) + i, begin(list) + i + k);
for (int i = 0; i < sum - 1; i++)
printf("%05d %d %05d\n", list[i], data[list[i]], list[i + 1]);
printf("%05d %d -1", list[sum - 1], data[list[sum - 1]]);
return 0;
}
女神的代码果然还是这么简短清纯而又毫不做作\(^o^)/
来来来小伙伴们,现在是学习大佬代码的时间:
啊。。。这题可以直接这么解啊,用data和next数组直接进行数据的存储,他们之间对应的关系用数据的地址连接,然后用list数组存储链表数据的地址,就知道原始链表的地址顺序。
翻转的时候直接用list数组进行翻转,就不用再次更改next部分进行赋值了,因为此时list数组内存的地址就是翻转之后的地址顺序:list[0]的下一个地址是list[1],(而不会像我自己用结构体数组那样,内部内容不改变,还需要对Next进行重新赋值),输出时将list存储的地址与data数组的下标对应,就可以取出想要的数了,哇塞,真方便!