给定一个带整数键值的链表 L L L,你需要把其中绝对值重复的键值结点删掉。即对每个键值 K K K,只有第一个绝对值等于 K K K 的结点被保留。同时,所有被删除的结点须被保存在另一个链表上。例如:给定 L L L 21→-15→-15→-7→15,你需要输出去重后的链表 21→-15→-7,还有被删除的链表 -15→15。
输入格式:
输入在第一行给出
L
L
L 的第一个结点的地址和一个正整数
N
(
≤
1
0
5
N(≤10^5
N(≤105 ,为结点总数)。一个结点的地址是非负的
5
5
5 位整数,空地址 NULL
用
−
1
−1
−1 来表示。
随后
N
N
N 行,每行按以下格式描述一个结点:
地址 键值 下一个结点
其中地址是该结点的地址,键值是绝对值不超过
1
0
4
10^4
104 的整数,下一个结点是下个结点的地址。
输出格式:
首先输出去重后的链表,然后输出被删除的链表。每个结点占一行,按输入的格式输出。
输入样例:
00100 5
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854
输出样例:
00100 21 23854
23854 -15 99999
99999 -7 -1
00000 -15 87654
87654 15 -1
可以有多种做法:
- 可以直接在原始链表上进行操作去重,然后单独提出重复的部分形成新链表
- 可以存储下来重复部分的地址和不重复部分的地址,输出时按照两部分地址输出
- 可以开三个链表,一个为初始,一个为去重后的,一个为重复部分,然后填充每个链表
很显然最简单的是第二种做法,并且不容易出错
接下来开始思考怎么实现:
- 如何存储重复与不重复的地址? 可以开两个vector数组,然后开一个
bool
类型的标记数组来判断重复与否,判断后直接push_back()
进相应的数组。 - 为什么可以直接压入vector而不用进一步保证他输出时是连接好的链表? 我们在去重的过程中一定是从首节点开始遍历到尾部,首先顺序就一定是正着的,之后在输出的过程中,已经有了所有应该输出的节点,我们并不需要管他们一开始是否相连,只需要在输出的时候输出成连着的链表就可以了,并且键值存的时候是依托于地址值的,并不是存入边上。
- 如何在输出的时候补齐应有的0? 只需要使用
printf()
函数中的%05d
,意思就是补齐五位,并且不足五位的在数前面补0。
同时需要注意:题目中的两种链表结尾都应该是-1,所以只需要在输出最后输出成-1就行了。
#include<iostream>
#include<vector>
using namespace std;
const int N = 1e5+10;
struct Node { //用结构体数组模拟链表
int to;
int len;
}lst[N];
vector<int>repeatedAddress; //记录键值重复的地址
vector<int>unrepeatedAddress; //记录键值不重复的地址
int head; //首地址
int n;
bool vis[N]; //标记是否出现过,判断重复
int main() {
cin >> head >> n;
for (int i = 0; i < n; i++) { //读入初始链表
int address, len, to;
cin >> address >> len >> to;
lst[address].to = to;
lst[address].len = len;
}
//从首地址开始遍历整个链表,如果当前键值没有出现过,就标记上并且把地址值压入记录数组
//如果出现过,那就吧地址压入记录重复地址的数组
for (int i = head; i != -1; i = lst[i].to) {
int t = lst[i].len; //取出键值
if (vis[abs(t)]) {
repeatedAddress.push_back(i);
}
else {
vis[abs(t)] = 1;
unrepeatedAddress.push_back(i);
}
}
auto& unrep = unrepeatedAddress; //引用
int len = unrep.size(); //数组长度
for (int i = 0; i < len; i++) { //遍历
//补0对齐输出
printf("%05d %d ",unrep[i],lst[unrep[i]].len);
if (i == len - 1)printf("-1\n"); //依照题目链表的尾部为-1,那么就在输出最后一个数的时候输出-1
else printf("%05d\n",unrep[i+1]);
}
auto& rep = repeatedAddress;
len = rep.size();
for (int i = 0; i < len; i++) {
printf("%05d %d ",rep[i],lst[rep[i]].len);
if (i == len - 1) printf("-1\n");
else printf("%05d\n",rep[i+1]);
}
return 0;
}