L2-008 链表去重(两种方法)

来源:互联网 发布:浙江理工大学 知乎 编辑:程序博客网 时间:2024/05/24 15:37

链接 :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;//第一个结点的keyv.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;}
下标也可以作为某种信息的存储,在有些时候可以节省内存,也可以节省搜索时间。
加油,渣科






0 0