描述:给定一个常数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 33218
00000 4 99999 33218 3 12309
00100 1 12309 12309 2 00100
68237 6 -1 00100 1 99999
33218 3 00000 99999 5 68237
99999 5 68237 68237 6 -1
12309 2 33218
解题思路:
1. 因为输入并不是按链表节点顺序来的,所以需要对输入进行一次排序整理,就在函数input()里面进行排序处理;
2. 对链表元素进行每k个的划分,然后进行反转,划分函数partition()
3. 进行k个元素的反转,反转函数reversal()
4. 最后打印结果,output()
详细处理:
1. input()函数,首先的问题在于对输入数据的排序,因为不进行排序,之后的反转操作进行不了,而又考虑到题目输入的节点可能有一万个,所以排序这里时间复杂度不能高。利用空间换时间,建立一张长度足够的哈希表,实现映射hash(add)->addnext;这样就不存在排序问题。然后从表中按节点顺序存到一个结构体数组,顺便记录节点个数。(说明一下,题目的输入并不保证所有节点都是链表上的节点,即存在无效节点)
2. partition()函数,每i*k到(i+1)*k-1(i=0,1,2...)个元素进行反转,当(i+1)*k-1>n-1,则这最后i*k到n-1个元素不反转。
3. reversal()函数,设置两个游标i=left,j=right,i从左开始加加,j从右开始减减,交换在i和j上的元素,同时更换他们的nextadd的值,需要注意的是每次还要修改i和j前面一个元素的nextadd,所以再加两个个游标qi=i-1,qj=j-1(i为0时另做处理)。
4. output()函数,由于前面的操作都将链表的地址看成数组下标,即一个整数,所以在输出时,要将整数换成和输入一样的形式,我们用格式控制输出%05d,尾节点-1要另作输出形式。
5.我是萌新一枚,以上思路很多是借鉴了论坛里面的,有错误或者可以改进的地方,希望大家多多指出。#include<stdio.h>
#define LEN 100001
typedef struct Link{
int address;
int data;
int nextadd;
}link;
typedef struct HashTable{
int data;
int nextadd;
}hash;
void input(link *L,int *n,int *k)
{
hash h[LEN];
int firstadd,N;
int add,i,j;
scanf("%d%d%d",&firstadd,&N,k);
for(i=0;i<N;++i){
scanf("%d",&add);
scanf("%d",&h[add].data);
scanf("%d",&h[add].nextadd);
}
i=0;
j=firstadd;
while(1){
L[i].address=j;
L[i].data=h[j].data;
L[i].nextadd=h[j].nextadd;
++i;
j=h[j].nextadd;
if(j==-1) break;
}
*n=i;
return;
}
void reversal(link *L,int left,int right)
{
int i=left,j=right;
int qi=-1,qj=j-1;
int t;
if(i!=0) qi=i-1;
do{
t=L[i].address; L[i].address=L[j].address; L[j].address=t;
t=L[i].data; L[i].data=L[j].data; L[j].data=t;
L[qj].nextadd=L[j].address;
if(qi!=-1) L[qi].nextadd=L[i].address;
++i;
--j;
qi=i-1;
qj=j-1;
}while(i<j);
return;
}
void partition(link *L,int n,int k)
{
int i;
for(i=0;;++i)
{
if((i+1)*k-1>n-1) break;
reversal(L,i*k,(i+1)*k-1);
}
return;
}
void output(link *L,int n)
{
int i;
for(i=0;i<n-1;++i)
{
printf("%05d %d %05d\n",L[i].address,L[i].data,L[i].nextadd);
}
printf("%05d %d %d",L[i].address,L[i].data,L[i].nextadd);
return;
}
int main()
{
link L[LEN];
int n,k;
input(L,&n,&k);
partition(L,n,k);
output(L,n);
return 0;
}
/*
00100 6 6
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
*/