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 (≤10 5 ) 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
琢磨了好久才写出来的代码,没想到还是不完美【唉】,因为输入数据可以最多达到100000个,我的代码调用链表函数过多,导致时间复杂性过高,小部分样例就运行超时了【难受】,不过程序整体框架没问题,好歹25分满分也拿了22分【哈哈】。
#include<stdio.h>
#include<stdlib.h>
typedef struct Node List;
struct Node{
int Addr;
int Data;
int NextAddr;
List *Next;
};
int num = 0; //链表建好之后的链表节点数
List *ReadList(int N);
List *CreateList(List *L,int firstaddr,int N);
List *ListReverse(List *head,int K);
void PrintList(List *L);
int main()
{
int N,K,FirstAddr;
List *Read,*a;
scanf("%d %d %d",&FirstAddr,&N,&K);
Read = ReadList(N);
a = CreateList(Read,FirstAddr,N);
List *p = a; //p指向链表头结点
List *rp = NULL; //反转链表函数的返回值
if(K == 1){
PrintList(a);
}else if(K <= num){
for(int i=0; i<(num/K); i++){
rp = ListReverse(p,K);
p->Next = rp; // 使p->Next 指向反转后链表的第一个节点
p->NextAddr = rp->Addr; // 更改NextAddr值,指向逆转后链表的下一个节点的Addr
int j = 0;
/*使p指向下一段需要反转的子链表的头结点(第一个节点的前一个节点)*/
while (j < K){
p = p->Next;
j++;
}
}
PrintList(a); //输出反转后链表
}
return 0;
}
List *ReadList(int N) /*用单链表存储数据*/
{
List *head,*rear;
head = (List *)malloc(sizeof(struct Node)); //头结点
rear = head; //rear始终指向终端结点,开始时指向头结点
while( N-- ){
List *p;
p = (List *)malloc(sizeof(struct Node));
scanf("%d %d %d",&(p->Addr),&(p->Data),&(p->NextAddr));
rear->Next = p;
rear = p;
}
rear->Next = NULL;
return head;
}
List *CreateList(List *L,int firstaddr,int N) //建立有顺序的单链表(尾插法)
{
int nextaddr = firstaddr;
List *head,*rear,*p;
head = (List *)malloc(sizeof(struct Node)); //头结点
rear = head; //rear始终指向终端结点,开始时指向头结点
while((N--) && (nextaddr != -1)){
p = L->Next; //每次都从链表头开始遍历
while( p ){
if( p->Addr == nextaddr ){ /*若找到对应的下一结点*/
num++;
List *q = (List *)malloc(sizeof(struct Node)); //申请结点空间
q->Addr = p->Addr; //数据域赋值
q->Data = p->Data;
q->NextAddr = p->NextAddr;
rear->Next = q; //尾插法
rear = q;
break;
}else{
p = p->Next; //没找到,链表指针后移
}
}
nextaddr = rear->NextAddr; //每找到一个结点, nextaddr重新赋值
}
rear->Next = NULL;
return head;
}
List *ListReverse(List *head,int K)
{
int cnt = 1;
List *New,*Old,*Tmp;
New = head->Next;
Old = New->Next;
while(cnt < K){
Tmp = Old->Next;
Old->Next = New;
Old->NextAddr = New->Addr; // 更改NextAddr值,指向逆转后其下一个节点的Addr
New = Old;
Old = Tmp;
cnt++;
}
//使反转后的最后一个节点指向下一段子链表的第一个节点
head->Next->Next = Old;
if (Old != NULL){
//修改Next值,使它指向下一个节点的位置
head->Next->NextAddr = Old->Addr;
}else{
//如果old为NULL,即没有下一个子链表,那么反转后的最后一个节点即是真个链表的最后一个节点
head->Next->NextAddr = -1;
}
return New;
}
void PrintList(List *L)
{
List *p = L->Next; //链表带头结点,因此链表第一个非零项为下一个
while( p ){
if( p->NextAddr != -1){
//格式输出,%05d意味着如果一个整数不足5位,输出时前面补0 如:22,输出:00022
printf("%05d %d %05d\n",p->Addr,p->Data,p->NextAddr);
}else{
//-1不需要以%05d格式输出
printf("%05d %d %d\n",p->Addr,p->Data,p->NextAddr);
}
p = p->Next;
}
}
不愿放弃的我只好去找度娘了。【。。。】
借鉴了一位仁兄的代码,终于把代码撸出来了。。。
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 100005
typedef struct Node List;
typedef struct Node{
int Addr;
int Data;
int NextAddr;
List *Next;
}LNode;
List *ListReverse(List *head,int K);
void PrintList(List *L);
int main()
{
int N,K,FirstAddr;
int num = 0; //链表建好之后的链表节点数
int data[MaxSize]; //存data值 节点位置作为索引值
int next[MaxSize]; //存next值 节点位置为索引
int tmp; //临时变量,输入的时候用
scanf("%d %d %d", &FirstAddr, &N, &K);
LNode a[N+1]; //能存N+1个结点的数组
a[0].NextAddr = FirstAddr; //a[0] 作为头结点
//读输入的节点
for (int i = 1; i < N+1; i++){
scanf("%d", &tmp);
scanf("%d %d", &data[tmp], &next[tmp]);
}
//构建单链表
int i = 1;
while (1){
if (a[i-1].NextAddr == -1){
a[i-1].Next = NULL;
num = i-1;
break;
}
//a[0].NextAddr = FirstAddr; //a[0] 作为头结点
a[i].Addr = a[i-1].NextAddr;
a[i].Data = data[a[i].Addr];
a[i].NextAddr = next[a[i].Addr];
a[i-1].Next = a+i;
i++;
}
List *p = a; //p指向链表头结点
List *rp = NULL; //反转链表函数的返回值
if(K == 1){
PrintList(a);
}else if(K <= num){
for(int i=0; i<(num/K); i++){
rp = ListReverse(p,K);
p->Next = rp; // 使p->Next 指向反转后链表的第一个节点
p->NextAddr = rp->Addr; // 更改NextAddr值,指向逆转后链表的下一个节点的Addr
int j = 0;
/*使p指向下一段需要反转的子链表的头结点(第一个节点的前一个节点)*/
while (j < K){
p = p->Next;
j++;
}
}
PrintList(a); //输出反转后链表
}
return 0;
}
List *ListReverse(List *head,int K)
{
int cnt = 1;
List *New,*Old,*Tmp;
New = head->Next;
Old = New->Next;
while(cnt < K){
Tmp = Old->Next;
Old->Next = New;
Old->NextAddr = New->Addr; // 更改NextAddr值,指向逆转后其下一个节点的Addr
New = Old;
Old = Tmp;
cnt++;
}
//使反转后的最后一个节点指向下一段子链表的第一个节点
head->Next->Next = Old;
if (Old != NULL){
//修改Next值,使它指向下一个节点的位置
head->Next->NextAddr = Old->Addr;
}else{
//如果old为NULL,即没有下一个子链表,那么反转后的最后一个节点即是真个链表的最后一个节点
head->Next->NextAddr = -1;
}
return New;
}
void PrintList(List *L)
{
List *p = L->Next; //链表带头结点,因此链表第一个非零项为下一个
while( p ){
if( p->NextAddr != -1){
//格式输出,%05d意味着如果一个整数不足5位,输出时前面补0 如:22,输出:00022
printf("%05d %d %05d\n",p->Addr,p->Data,p->NextAddr);
}else{
//-1不需要以%05d格式输出
printf("%05d %d %d\n",p->Addr,p->Data,p->NextAddr);
}
p = p->Next;
}
}
非常感谢这位兄弟-https://blog.csdn.net/weixin_42182906/article/details/80343251,想法真心不错。