02-线性结构3 Reversing Linked List(25 分)
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 (≤105) 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
分析:这道题很有意思,题目要求给定一个链表,长度N,需要反向输出的长度K,就是说对一个链表实现循环前K个反向输出, 直到输出长度小于K。例子: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。我的算法设计是:首先设计单向链表的反向输出函数,返回首地址。然后定义数组来存储这些不同段的首地址,最后将这些段连接起来。算法复杂度O(N)。
如果只是这样的话,这道题也不能算难。但是仔细看输入输出要求:
1、输入的链表还需要重新按照给定的当前地址与下一个地址排序。我设计的算法是:首先找出在链表中找出给定的首地址。然后对当前结点指向地址与后面结点的当前地址进行判断(遍历),如相等则与当前结点的下一个结点进行数据交换。算法复杂度大于O(N),但小于O(N^2).
2、输入的链表中有些是无效结点,需要剔除。我的思路是判断结点指向地址是否等于-1.
3、链表的逆序算法原理:
代码有些长,两百多行,可以只看函数实现部分,输入输出可以不看,欢迎互相探讨,谢谢!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct LNode *List;
struct LNode{
char Address[6];
int Data;
char Next_Address[6];
List next;
};
void Gets(char a[]);
List ReadInput(int N);
void Print(List L);
List Reversing(List L, char First_Address[], int K, int N);
void LSord(List L, List P);
List Ni_Xu(List L,int K);
int main()
{
// while(getchar()!=EOF)
// {
List L,R;
/*
** 0<N<=10^5,0<K<=N;
*/
char First_Address[6];
int N,K,i;
Gets(First_Address);
scanf("%d%d",&N,&K);
getchar();
L = ReadInput(N);
// printf("结果:\n");
R = Reversing(L, First_Address, K, N);
Print(R);
//}
return 0;
}
List ReadInput(int N)
{
List L,P,t;
int i;
L = (List)malloc(sizeof(struct LNode));
P = L;
for(i = 0; i < N; i++)
{
Gets(P->Address);
scanf("%d",&P->Data);
getchar();
Gets(P->Next_Address);
t = P;
P = (List)malloc(sizeof(struct LNode));
t->next = P;
}
free(P);
t->next = NULL;
return L;
}
void Print(List L)
{
List P = L;
if(P == NULL) printf("NULL\n");
for( ; P != NULL; P = P->next)
printf("%s %d %s\n", P->Address, P->Data, P->Next_Address);
}
List Reversing(List L, char First_Address[], int K, int N)
{
List P,P1,t;
int i,cnt=1;
/*
** 将链表按地址排序
*/
for(P = L; P != NULL; P = P->next) /* 查找首地址,并放于头结点 测试:OK*/
{
if( strcmp( First_Address, P->Address) == 0 ) /* 交换头结点与查找结点的元素 */
{
LSord( L, P );
break;
}
}
for(P = L; P->next != NULL; P = P->next) /* 按地址重排 */
{
P1 = P->next;
for(; P1 != NULL; )
{
if( strcmp( P->Next_Address, P1->Address) != 0 )
P1 = P1->next;
else
{
LSord(P->next,P1);
break;
}
}
}
for( P = L; strcmp(P->Next_Address,"-1") != 0 ; P = P->next) /* cnt 实际有效结点数 */
cnt++;
P->next = NULL;
// Print(L);
P = L;
int len;
if( cnt % K == 0) len = cnt/K;
else len = cnt/K +1;
List R[len]; /* 分段保存逆序后的链表 */
for(i = 0; P != NULL && (i+1)*K <= cnt; i++) /* 变换前K个元素顺序 */
{
List f0 = P;
int j;
for(j = 0; j < K; j++)
P = P->next;
R[i] = Ni_Xu(f0,K);
}
if( cnt % K != 0) /* 为变换的段 */
R[i] = P;
else /* 后面指向NULL */
{
P = R[i-1];
int j;
for(j = 1; j < K; j++)
P = P->next;
P->next = NULL;
}
for(i=0; i<len-1; i++) /* 将分段后的链表连接 */
{
P = R[i];
int j;
for(j = 1; j < K; j++)
P = P->next;
P->next = R[i+1];
}
P = R[0]; /* 此时下一个结点的地址需要重新修改 */
for( ;P->next != NULL; P = P->next)
strcpy(P->Next_Address,P->next->Address);
P->Next_Address[0] = '-'; /* 最后一个结点下一个地址为-1 */
P->Next_Address[1] = '1';
P->Next_Address[2] = '\0';
// Print(R[0]);
// printf("test4\n");
return R[0];
}
/*
** 交换L,P中元素
*/
void LSord(List L, List P)
{
char s1[6],s2[6];
int d;
strcpy(s1, L->Address);
strcpy(s2, L->Next_Address);
d = L->Data;
strcpy(L->Address, P->Address);
strcpy(L->Next_Address, P->Next_Address);
L->Data = P->Data;
strcpy(P->Address, s1);
strcpy(P->Next_Address, s2);
P->Data = d;
}
List Ni_Xu(List L,int K)
{
List P0,P,t;
int i;
P0 = L;
P = P0->next;
for( i = 1; P != NULL && i < K; i++ )
{
t = P->next;
P->next = P0;
P0 = P;
P = t;
}
return P0;
}
void Gets(char a[])
{
int i;
for(i=0;;i++)
{
a[i]=getchar();
if(a[i] == ' ' || a[i] == '\n') break;
}
a[i] = '\0';
}