反转链表

描述给定一个常数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-1i=012...)个元素进行反转,当(i+1)*k-1>n-1,则这最后i*kn-1个元素不反转。

3. reversal()函数,设置两个游标i=leftj=righti从左开始加加,j从右开始减减,交换在ij上的元素,同时更换他们的nextadd的值,需要注意的是每次还要修改ij前面一个元素的nextadd,所以再加两个个游标qi=i-1,qj=j-1i0时另做处理)。

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
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值