题目描述
给定一个单链表,请编写程序将链表元素进行分类排列,使得所有负值元素都排在非负值元素的前面,而 [0, K] 区间内的元素都排在大于 K 的元素前面。但每一类内部元素的顺序是不能改变的。例如:给定链表为 18→7→-4→0→5→-6→10→11→-2,K 为 10,则输出应该为 -4→-6→-2→7→0→5→10→18→11。
输入格式:
每个输入包含一个测试用例。每个测试用例第 1 行给出:第 1 个结点的地址;结点总个数,即正整数N (≤105);以及正整数K (≤103)。结点的地址是 5 位非负整数,NULL 地址用 −1 表示。
接下来有 N 行,每行格式为:
Address Data Next
其中 Address
是结点地址;Data
是该结点保存的数据,为 [−105,105] 区间内的整数;Next
是下一结点的地址。题目保证给出的链表不为空。
输出格式:
对每个测试用例,按链表从头到尾的顺序输出重排后的结果链表,其上每个结点占一行,格式与输入相同。
输入样例:
00100 9 10
23333 10 27777
00000 0 99999
00100 18 12309
68237 -6 23333
33218 -4 00000
48652 -2 -1
99999 5 68237
27777 11 48652
12309 7 33218
输出样例:
33218 -4 68237
68237 -6 48652
48652 -2 12309
12309 7 00000
00000 0 99999
99999 5 23333
23333 10 00100
00100 18 27777
27777 11 -1
问题分析
处理流程:
输入结点地址、数据、下一个结点地址;重排;按格式输出。
处理细节:
- 数据存储:用结构体数组存储,本题目中是 node 类型的 数组 list。list 下标是本结点地址,结点 node 中保存数据 data 和 下一个结点的地址;结点地址保存在 vector 类型的数组中,按分类要求分为三个部分 v[0]、v[1]、v[2];
- 输入输出:输入就按照 地址、数据、下一结点地址输入即可;输出的格式柳神写的是非常巧妙的,第一次输出时仅输出头结点的地址和数据,把下一个结点的地址交给下一个循环输出。之后的每个结点输出两次它的结点值,第一次是在上一行的最后输出,是相对于上一次输出的下一个地址,然后换行,输出本次结点值。这样就把问题做了简化。抓住了上一个结点的下一个结点与本结点相同这一问题特性;
- 分类处理:这是本题的核心,按照链表顺序分类处理,我想这是一句很好的总结了。首先怎么按照链表顺序读我们的输入呢?其实陈姥姥已经铺好了路:输入中是有第一个结点的地址的,而且已经用结构体存储好了它的结点地址,那么再加上循环,就可以正常的按顺序读取了;接下来就是在每次循环中处理,如果结点值是小于 0 的,那么放入 vec[0];结点值在[0, k] 区间的,放入vec[1];剩下的放入vec[2]。说白了就是对链表按区间分类,但每类中的前后顺序都与输入时一致
代码
#include <iostream>
#include <vector>
struct node{
int data, next;
}list[100000];
std::vector<int> vec[3];
int main(){
int sadr, n, k, tmpadr;
std::cin >> sadr >> n >> k;
for (int i = 0; i < n; i++) { // 循环输入
std::cin >> tmpadr;
std::cin >> list[tmpadr].data >> list[tmpadr].next;
}
int p = sadr;
while(p != -1) {
int data = list[p].data;
if (data < 0) vec[0].push_back(p);
else if (data >= 0 && data <= k) vec[1].push_back(p);
else vec[2].push_back(p);
p = list[p].next;
}
int flag = 0; // 标记是否有过输出
for (int i = 0; i < 3; i++) {
for (int j = 0; j < vec[i].size(); j++) {
if (flag == 0) {printf("%05d %d ", vec[i][j], list[vec[i][j]].data); flag = 1;}
else printf("%05d\n%05d %d ", vec[i][j], vec[i][j], list[vec[i][j]].data);
}
}
printf("-1");
return 0;
}
小结
好好读题,题目中总有线索;
这种存储比较多的情况可以考虑使用结构体;
解法参考
题目解法来自柳神,本人只是照敲、学习。