1025. 反转链表 (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(<= 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
思路: 本题可以使用一个结构体来定义节点Node, 使用c++ 的模板类vector进行封装,就可以类似使用数组一样来遍历vector<Node> 类型的节点向量,需要对链表的基本性质有一定了解,相信大家应该都没有问题(参考数据结构)。 第一次解题时,遗漏了输入节点可能不在链表的情况,这是思维定视所导致的,这个很致命的,是思维上的漏洞。
算法:
1. 输入所有节点,用Node1[address]来存放
2. 从首地址开始,在Node1中依次寻找节点的后继,直到node.next=-1 , 自动跳过不在链表的节点,依次将节点存放在Node2中
3. 将Node2中的节点进行反转,按要求分组进行反转,将反转后的节点存放在Node3中,反转实现看具体代码
4.遍历输出Node3,下面的实现没有改变Node3中节点后继地址,而是取巧进行输出,算是节省了部分时间吧.但是
并不建议这样中,因为在实际问题中一般会对反转后的链表进行新的操作。
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
struct Node{
int address; //地址
int data; //节点数据
int next; //节点后继地址
};
vector<Node> Node1(100000); //地址为下标的位置存放相应节点
vector<Node> Node2; //用来存放反转前的链表节点
vector<Node> Node3; //用来存放反转后的链表节点
//交换a,b的位置
void swap(Node &a, Node &b){
Node temp = a;
a = b;
b = temp;
}
/*
测试用例
00100 6 2
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
中间有不在链表上的节点
00001 6 2
00001 1 00002
00002 2 00003
00006 3 00007
00003 4 00004
00004 5 00005
00005 6 -1
*/
int main(){
//接收输入
int firstAdd,n,k;
scanf("%d%d%d", &firstAdd, &n,&k);
Node temp;
for(int i=0;i<n;i++){
scanf("%d%d%d", &temp.address, &temp.data, &temp.next);
Node1[temp.address] = temp;
}
//从第一个节点开始,根据next地址寻找所有在链表中的节点
int next = firstAdd;
bool go_on = true; //记录是否继续进行
for(int i=0; go_on ;i++) {
Node2.push_back(Node1[next]); //从第一个节点开始顺序将后继节点存入Node2 向量
next = Node1[next].next;
if(next == -1) go_on = false;
}
int n1= Node2.size(); //可以组成完整链表的节点个数
int num = (n1 / k); //需要反转的节点组数
vector<Node>::iterator it; //遍历指针
for(int i=0;i<num;i++){
int lo=i*k, hi=(i+1)*k; //每次反转[lo,hi)区间内的节点,不考虑节点next地址的变化
while(lo<hi){
swap(Node2[lo++],Node2[--hi]);
}
}
//输出结果 ,最后一个节点末尾直接输出“-1”,其他的节点按照(本节点首地址,本节点数据,下一个节点首地址)格式输出
for(it = Node2.begin(); it!=Node2.end(); it++){
if(it!= Node2.end() -1 ){
vector<Node>::iterator temp=it;
printf("%05d %d %05d\n", (*it).address,(*it).data, (*(++temp)).address);
}
else
{
printf("%05d %d %d\n", (*it).address,(*it).data, -1);
}
}
return 0;
}