1025 反转链表 (25)(25 分)

1025 反转链表 (25)(25 分)

给定一个常数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(<= 10^5^)、以及正整数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

这道题可让我波折 透了 最后一个情况无论怎么调都报段错误。然后我重头到脚检查了一遍 没有问题 非法数据 和不在链表上的节点100%是不会参与旋转的。可是就是通过不了 彻底的抓狂了 ,我决定用 STL 重写它 看一下到底是怎么个一回事。

结果STL AC之后,我越想越不明白 使用 STL的 代码逐一替换掉 原来的代码 直到我看到了输出函数。(就发现了造成段错误的非法语句~)


详细思路 :

少量STL语句思路(就是交换的时候用了 STL )


0.创建结构体,三个参量 依次是 该节点的地址 该节点的数据 该节点的下一地址 ;定义两个结构体数组,一个成员变量数组,另一个则是成员指针的数组。因此用指针数组主要是考虑到空间的问题,我们可以对指针数组进行排序。这个比再赋一遍值要好得多。

1. 读入数据 ,注意 读入的数据应该存在一个 大小为 100000 的结构体数组里面  下标不是从 0 开始 而是该节点的地址作为下标。 同时别忘记存储该节点的 地址 ,因为该节点的地址不仅作为数组的下标,更多的应该留心后面输出的情况。[这是一种严谨的思想,而不是要等到用的时候再回来定义 最好要把情况都考虑到,这是对我的要求。]

2.读入数据以后 就必须要“拉住头”把链表给抽出来。这个时候 由于我们索引 链表所用的值是链表的当前节点的值 ,我们还知道链表结尾肯定是 -1 结束的 那么 我们就非常轻而易举的知道 最优的方法就是 来循环 (不是递归) 。循环出口就是 -1.

实施方案是 (T是 成员指针数组的存储数据大小,初始化为 0)

 int T=0;  for(int i = 头结点索引值 ; i!=-1; i = 成员数组[i].next)    成员指针数组[T++] = &成员数组[i];

3.头被拉出来之后,根据题目要求 接下来是 "换" 怎么换  答案是以 第一行第三个数为基准 只要它不大过.......(不大过什么,这个很重要,可以想一下,是不大过 “第一行第二个数”吗?? 是就危险了哦) 因为它有可能存在不是链表上的节点 ,所以应该是不大过 成员指针数组的 存储数据大小 T  。

4.转换开始 转换可以沿袭 之前 C 语言的 方法 给定范围 然后 两个变量 一个指向起点 另一个指向终点,两个变量以撞车的方向前进移动,当两个变量不相互碰撞的时候 交换 两个存储指针变量的 值。直到交换完成。这是内层循环

5.外层循环 主要控制范围和 次数的 通常使用两个变量i,j 一个令它等于 T 一个令它等于 0 ,执行循环的先决条件是 i>=翻转值(这个值就是第一行第三个值) ,接着每次 循环结束以后 i-=翻转值 ;那个j是用来控制交换起点的,一开始等于 0 循环结束 后 i+=翻转值。 

6. 4 5 结束以后整个翻转就全部完成了,接下来就是输出的工作。

7.输出采用预判断的方法 先判断该节点是不是等于 尾节点(所谓的尾节点 就是循环有没有到 访问 成员指针数组[T-1]这个位置)

如果不是,就输出 

printf("%05d %d %05d",成员指针数组[当前遍历变量]->ID,成员指针数组[当前遍历变量]->data,成员指针数组[当前遍历变量 + 1]->ID);

8.程序执行完毕。

下面是上面实现的代码:

#include <bits/stdc++.h>
using namespace std;
struct sn {
	int ID;
	int data;
	int next;
};
struct sn P[100000 + 10]; // 存输入的内容
struct sn* Q[100000 + 10]; // 存输入内容的指针
void solve() {
	int toulist, cs, XZ; // 6 个节点(cs)  4个大翻转(XZ)
	scanf("%d%d%d", &toulist, &cs, &XZ);
	if (!cs)
		toulist = -1;
	for (int i = 0, inp, DE, NEXT; i < cs; i++) {
		scanf("%d%d%d", &inp, &DE, &NEXT);
		P[inp].data = DE;
		P[inp].next = NEXT;
		P[inp].ID = inp;
	}
	int tk = 0;
	for (int i = toulist; i != -1; i = P[i].next) {
		Q[tk++] = &P[i];
	}
	for (int i = tk,j=0;i>=XZ;i-=XZ,j+=XZ) {
		reverse(Q + j, Q + j + XZ);
	}
	for (int i = 0; i < tk; i++) {
		if (i != tk - 1) {  // 段错误是因为之前我这里写成了 i!=cs-1 导致越界访问,炸
			printf("%05d %d %05d\n", Q[i]->ID, Q[i]->data, Q[i + 1]->ID);
		}
		else {
			printf("%05d %d -1", Q[i]->ID, Q[i]->data);
		}
	}
}
int main() {

	solve();
	system("pause");
	return 0;
}


值的一提的是 我还写了另外的STL版本 那个版本时间效率不及 上面代码。但是就是因为这样我才找出了段错误的原因 可以让我暂时停止写博客 专心应付期末考试了 ~


STL实现: (思路相同 刚开始我是考虑可能数组开小了才这么写的 不推荐使用下面的方法。虽然代码 AC了)

#include <bits/stdc++.h>
using namespace std;

map<int, pair<int, int> >SN;

struct GZ { // 结构体构造 函数 解决
	int NO_this;
	int data;
	int last;
};
struct GZ T[100000 + 100000 + 10];

void solve() {

	int toulist = -1, x, FZ;
	scanf("%d%d%d", &toulist, &x, &FZ);
	if (x == 0)
		toulist = -1;

	for (int i = 0, tNO_, P1, P2; i < x; i++) {
		scanf("%d", &tNO_), tNO_;
		scanf("%d", &P1), P1;
		scanf("%d", &P2), P2;
		SN[tNO_] = { P1 ,P2 };
	}
	int Tcnt = 0;
	for (int j = toulist; j != -1; j = SN[j].second)
		T[Tcnt++] = { j,SN[j].first,SN[j].second };

	for (int i = Tcnt, j = 0; i >= FZ; i -= FZ, j += FZ) {
		 reverse(T+j, T+j + FZ);
	}
	for (int i = 0; i < Tcnt; i++) {
		i == Tcnt - 1 ? printf("%05d %d -1\n", T[i].NO_this, T[i].data) : printf("%05d %d %05d\n", T[i].NO_this, T[i].data, T[i + 1].NO_this);
	}
}

int main() {
	solve();
	system("pause");
	return 0;
}


 

  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值