题目描述:
给定一个常数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
题目的坑
除了给的完整链表还可能有无关节点:
00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 -1
99999 5 68237
12309 2 33218
错以为只有完整一条
从而导致K可能大于链表实际长度
评论区copy代码
#include <stdio.h>
#include <memory.h>
#define LIMIT 100002
struct linknode {
int data;
int next;
};
int reversek(struct linknode *, int, int);
int main(void) {
struct linknode list[LIMIT]; //静态链表
int faddr, n, k;
int addr, data, next;
int i, j, count = 0;
scanf("%d %d %d", &faddr, &n, &k);
memset(list, 0, LIMIT * sizeof(struct linknode)); //结构体数组清零初始化
list[LIMIT-1].next = faddr; //head node
for(i = 0; i < n; ++i) {
scanf("%d %d %d", &addr, &data, &next);
list[addr].data = data;
list[addr].next = next;
}
for(i = list[LIMIT-1].next; i != -1; i = list[i].next)
++count; //count valid nodes 统计实际链表节点数
for(j = count / k, i = LIMIT - 1; j > 0 && i != -1; --j) //剩余反转数j
i = reversek(list, i, k); //reverse every k nodes //未完成头节点地址i
//传输(虚拟)头节点地址而不是反转头地址,是为了防止无法与前面链表连接
for(i = list[LIMIT-1].next; list[i].next != -1; i = list[i].next)
printf("%05d %d %05d\n", i, list[i].data, list[i].next);
printf("%05d %d %d\n", i, list[i].data, list[i].next);
return 0;
}
int reversek(struct linknode *list, int head, int k) {
int i, j, p;
int nexthead; //p!=-1 防止长度不够
for(j = 0, p = list[head].next; j < k && p != -1; ++j) //find tail
p = list[p].next;
nexthead = list[head].next; //该小段头节点地址
list[head].next = p; //剔除该小段
for(j = 0, i = nexthead; j < k && i != -1; ++j) {
p = list[i].next;
list[i].next = list[head].next; //insert at the head 头节点插入使该小段反转
list[head].next = i;
i = p;
}
return nexthead; //返回未完成节点前一个地址(作为未完成头节点)
}
附:
附解
1.void *memset(void *s, int ch, size_t n);
函数解释:将s中当前位置后面的n个字节 typedef unsigned int size_t 用 ch替换并返回 s 。
memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法 。
memset()函数原型是extern void *memset(void *buffer, int c, int count) buffer:为指针或是数组,c:是赋给buffer的值,count:是buffer的长度
2.memset函数按字节对内存块进行初始化,所以不能用它将int数组初始化为0和-1之外的其他值(除非该值高字节和低字节相同)
511的二进制码为(00000000 00000000 00000001 11111111)后八位为(11111111),
所以数组中每个字节,如a[0]含四个字节都被赋值为(11111111),其结果为a[0](11111111 11111111 11111111 11111111)
3.C里面数是以补码方式来储存的 -1为11111111 11111111 11111111 11111111
附自己写的 垃圾 代码
仅供自己反思:
#include<stdio.h> //惨不忍睹001
int main()
{
int N,K,i,*tadd=NULL,*padd=NULL,t=0,*tnext=NULL;
struct POINT{
int *address;
int data;
int *next;
}a[100050],*pa=a;
scanf("%d",&padd);
scanf("%d",&N);
scanf("%d",&K);
for(i=0;i<N;i++)
{
scanf("%d",&a[i].address);
scanf("%d",&a[i].data);
scanf("%d",&a[i].next);
}
for(i=0;i<N-1;i++)
{
while(pa->address!=padd)
pa++;
tadd=a[i].address;
a[i].address=pa->address;
pa->address=tadd;
tnext=a[i].next;
a[i].next=pa->next;
pa->next=tnext;
t=a[i].data;
a[i].data=pa->data;
pa->data=t;
padd=pa->next;
pa=a+i+1;
}
pa=a+K-1;
while(pa<a+N-1)
{
tnext=pa->next;
for(i=0;i<K-1;i++)
{
(pa-i)->next=(pa-i-1)->address;
}
(pa-K+1)->next=tnext;
for(i=0;i<4;i++)
printf("%d %d %d\n",(pa-i)->address,(pa-i)->data,(pa-i)->next);
pa+=K;
}
return 0;
}
#include<stdio.h> //惨不忍睹010
int main()
{
int N,K,i,*tadd=NULL,*padd=NULL,t=0,*tnext=NULL;
struct POINT{
int *address;
int data;
int *next;
}a[100000],*pa=a;
scanf("%d",&padd);
scanf("%d",&N);
scanf("%d",&K);
for(i=0;i<N;i++)
{
scanf("%d",&a[i].address);
scanf("%d",&a[i].data);
scanf("%d",&a[i].next);
}
for(i=0;i<N-1;i++)
{
while(pa->address!=padd)
pa++;
tadd=a[i].address;
a[i].address=pa->address;
pa->address=tadd;
tnext=a[i].next;
a[i].next=pa->next;
pa->next=tnext;
t=a[i].data;
a[i].data=pa->data;
pa->data=t;
padd=a[i].next;
pa=a+i+1;
if(a[i].next==NULL)
break;
}
N=pa-a;
pa=a+K-1;
while(pa<a+N)
{
tnext=pa->next;
for(i=0;i<K-1;i++)
{
(pa-i)->next=(pa-i-1)->address;
}
(pa-K+1)->next=tnext;
for(i=0;i<K;i++)
printf("%d %d %d\n",(pa-i)->address,(pa-i)->data,(pa-i)->next);
pa+=K;
}
pa=pa-K+1;
while(pa<a+N)
{
printf("%d %d %d\n",pa->address,pa->data,pa->next);
pa+=1;
}
return 0;
}
后个人补充代码
#include<stdio.h>
struct NODE{
int data;
int next;
};
int standard(struct NODE *a,int i,int k)
{
int pnext=a[i].next,paddr=a[i].next,j,addr,head=i;
for(j=0;j<k;j++)
pnext=a[pnext].next;
head=paddr;
for(j=0;j<k;j++)
{
addr=a[paddr].next;
a[paddr].next=pnext;
a[i].next=paddr;
pnext=paddr;
paddr=addr;
}
return head;
}
int main()
{
static struct NODE a[100002];
int addr,data,next;
int faddr,n,k;
int i,num=0,j;
scanf("%d %d %d",&faddr,&n,&k);
a[100001].next=faddr;
for(i=0;i<n;i++)
{
scanf("%d",&addr);
scanf("%d",&a[addr].data);
scanf("%d",&a[addr].next);
}
printf("static实验%d %d %d\n",5,a[5].data,a[5].next);
i=100001;
while(a[i].next!=-1)
{
num++;
i=a[i].next;
printf(" next address %05d\n",i);
}
n=num; //链表实际长度
printf("实际长度 %d \n",num);
i=100001;
for(j=0;j<n/k;j++)
{
i=standard(a,i,k);
}
printf("结果\n");
faddr=a[100001].next;
for(j=0;j<n;j++)
{
printf("%05d %d %05d\n",faddr,a[faddr].data,a[faddr].next);
faddr=a[faddr].next;
}
}