链接 :https://www.patest.cn/contests/gplt/L2-002
题目内容:
给定一个带整数键值的单链表L,本题要求你编写程序,删除那些键值的绝对值有重复的结点。即对任意键值K,只有键值或其绝对值等于K的第一个结点可以被保留。同时,所有被删除的结点必须被保存在另外一个链表中。例如:另L为21→-15→-15→-7→15,则你必须输出去重后的链表21→-15→-7、以及被删除的链表-15→15。
输入格式:
输入第一行包含链表第一个结点的地址、以及结点个数N(<= 105 的正整数)。结点地址是一个非负的5位整数,NULL指针用-1表示。
随后N行,每行按下列格式给出一个结点的信息:
Address Key Next
其中Address是结点的地址,Key是绝对值不超过104的整数,Next是下一个结点的地址。
输出格式:
首先输出去重后的链表,然后输出被删除结点组成的链表。每个结点占一行,按输入的格式输出。
输入样例: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
用数组下标存放 结点的id,可以迅速访问到该结点。因为题目的结点id在100000之内,所以开数组这个方法还是很有效的
*方法一 2017-3-23 9:59
#include<iostream>
#include<cstdio>
#include<set>
using namespace std;
struct Node
{
int key;
int next;
Node ()
{
key=-1;
next=-1;
}
}a[110001];//开一个数组存放结点,题目要求的id在0~99999之间,所以这个数组的大小110001足够放了
int node1[110001],node2[110002];//node1存放主链表中结点的id,node2存放删除的结点id
int main()
{
set<int>v;//存放主链表中的key值,用于检测key是否重复
int begin,n;//头结点的Id,以及结点总个数
int pos1=0,pos2=0; //记录主链表和被删除结点链表的大小
scanf("%d %d",&begin,&n);
int i;
int tmp;
for(i=0;i<n;i++)
{
scanf("%d",&tmp); //得到id
scanf("%d %d",&a[tmp].key,&a[tmp].next); //将id作为数组下标,存放key和next
}
//下标及是结点的id
tmp=a[begin].key;//第一个结点的key
v.insert(tmp); //集合中添加key
v.insert(-tmp); //再添加-key
node1[pos1++]=begin; //主链表添加一个结点
int next=a[begin].next; //下一个结点的id
while(next!=-1)
{
tmp=a[next].key;//得到它的key
if(v.find(tmp)==v.end())//主链表中没有这个key,可以添加
{
v.insert(tmp); //插入key 和-key
v.insert(-tmp);
node1[pos1++]=next; //该结点可以进入主链表
next=a[next].next; //下一个结点的id
}else{ //链表中没有这个key,或者-key,主链表不能添加
node2[pos2++]=next; //把结点放进node2[] 中
next=a[next].next;
}
}
//按题目指定格式输出
printf("%05d %d",node1[0],a[node1[0]].key);
for(i=1;i<pos1;i++)
{
printf(" %05d\n%05d %d",node1[i],node1[i],a[node1[i]].key);
}
printf(" -1\n");
if(pos2>0)
{
printf("%05d %d",node2[0],a[node2[0]].key);
for(i=1;i<pos2;i++)
{
printf(" %05d\n%05d %d",node2[i],node2[i],a[node2[i]].key);
}
printf(" -1\n");
}
return 0;
}
//一开始的写法: 2017-03-19 20:08
// 方法二: 运行时间太长,占内存太大,不过还是贴在这里,毕竟也是劳动成果,爱自己的代码
这道题做了很久,虽然最后通过了,但觉得方法很笨,不过过程中还是有几点细节值得注意
1.在map中用char *作为key,在查找find()的过程中,虽然存在,但一直找不到值,最后百度后说用自定义结构体cmp可以解决,加在map的定义map<char*,Node,cmp>中才解决
2.用头文件<cstdio>,用printf(),scanf(),在数据多的时候可以省下不少时间,一开始用cin,cout超时
3.对map和stl 中的类有点生疏,要重新回去翻一翻。
#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<string.h>
using namespace std;
struct Node
{
char id[6];
int key;
char next[6];
}f[100001],list1[100001],list2[100001];
struct cmp
{
bool operator ()(char *a,char *b)// 一开始忘记加bool,编译出错
{
return strcmp(a,b)<0;
}
};
map<char *,Node,cmp>m;
map<char *,Node,cmp>::iterator it;
set<int>s;
set<int>::iterator itt;
int main()
{
char a[6];
cin>>a;
int n;
cin>>n;
int i;
for(i=0;i<n;i++)
{
scanf("%s %d %s",f[i].id,&f[i].key,f[i].next);
m.insert(pair<char*,Node>(f[i].id,f[i]));
}
it=m.find(a);
int j=0,k=0;
while(1)
{
if(s.find(it->second.key)==s.end())
{
s.insert(it->second.key);
s.insert(-(it->second.key));
list1[j]=(it->second);
j++;
}else{
list2[k]=(it->second);
k++;
}
if(strcmp(it->second.next,"-1")==0)
{
break;
}
it=m.find(it->second.next);
}
if(j>1)
{
printf("%s %d ",list1[0].id,list1[0].key);
for(i=1;i<j-1;i++)
{
printf("%s\n%s %d ",list1[i].id,list1[i].id,list1[i].key);
}
printf("%s\n%s %d -1\n",list1[i].id,list1[i].id,list1[i].key);
}else if(j==1){
printf("%s %d -1\n",list1[0].id,list1[0].key);
}
if(k>1)
{
printf("%s %d ",list2[0].id,list2[0].key);
for(i=1;i<k-1;i++)
{
printf("%s\n%s %d ",list2[i].id,list2[i].id,list2[i].key);
}
printf("%s\n%s %d -1\n",list2[i].id,list2[i].id,list2[i].key);
}else if(k==1){
printf("%s %d -1\n",list2[0].id,list2[0].key);
}
return 0;
}
下标也可以作为某种信息的存储,在有些时候可以节省内存,也可以节省搜索时间。加油,渣科