给定一个常数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
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
using namespace std;
map >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;
}