给定一个带整数键值的链表 L,你需要把其中绝对值重复的键值结点删掉。即对每个键值 K,只有第一个绝对值等于 K 的结点被保留。同时,所有被删除的结点须被保存在另一个链表上。例如给定 L 为 21→-15→-15→-7→15,你需要输出去重后的链表 21→-15→-7,还有被删除的链表 -15→15。
输入格式:
输入在第一行给出 L 的第一个结点的地址和一个正整数 N(≤105,为结点总数)。一个结点的地址是非负的 5 位整数,空地址 NULL 用 −1 来表示。
随后 N 行,每行按以下格式描述一个结点:
地址 键值 下一个结点
其中地址
是该结点的地址,键值
是绝对值不超过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
代码解释: 用的动态链表进行存储,没有使用函数,可能看起来有点费力,大体思路是结构体的节点使用了两个指针,其中一个为按照输入顺序进行链接,后一个为按照地址进行链接,所以输入完后需要先按照地址的顺序进行链接,该部分分了两部,首先找第一个,然后在循环,注意里面都被孤立的节点,该节点不需要输出,所以最后输出时不能按照计数器进行输出的终止,最后就是链表查重了,测试点同样有大数据,要注意时间不能超时,注意,在输出重复链表时他们的顺序必须和输入的相对顺序相同,否则错误,如果按照暴力搜索时不仅会超时,也会答案错误
代码:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
struct ListNode{
int data;
char next1[9]; //下一个节点地址
char last[9]; //上一个节点地址
struct ListNode *mei; //按照输入链表的顺序链接的指针
struct ListNode *next; //输出顺序链接的指针
};
int main()
{
struct ListNode *headnode,*s=NULL, *move = NULL;
int m;
headnode=(struct ListNode *)malloc(sizeof(struct ListNode)); //头节点
s = headnode; //头指针 插入节点时不用分情况
scanf("%s",headnode->last);
scanf("%d",&m);
for (int i=m;i>0;i--) //输入 插入新节点
{
move=(struct ListNode *)malloc(sizeof(struct ListNode));//必须在循环里
scanf ("%s %d %s",move->last,&(move->data),move->next1);
s->mei=move;
s=s->mei;
s->mei = NULL;
}
//找新链表的头指针head
struct ListNode *head = NULL;
move = headnode->mei;
while (move)
{
if (!strcmp(move->last,headnode->last)) //如果找到了第一个节点
{
head=move; //让head指向第一个节点
break; //没有也没事 没有地址相同的节点的情况
}
move=move->mei; //没有循环指向下一个节点
}
//连接 新链表
s=headnode; //s为指向输入顺序的链表 里面有删除 一开始指向头节点不用分情况
move = head; //move为连接好的链表中的最后一个节点
for (int i=m;i>1;i--)//每次找到1个 测试点中有 没有在链表上的废节点
{
while (s)
{
while ( s->mei && !strcmp(s->mei->last,move->next1) )//没有s->mei && 段错误
{
move->next=s->mei; //连接新节点
move=move->next;
move->next=NULL; //必须要有---野指针?pta没有也对
s->mei = s->mei->mei; //删除了旧链表的节点 如果没有会运行超时(因为这里有两个循环嵌套) 有执行完这个模块大数据是23ms 。删除了旧链表的节点所以上面用while
}
s=s->mei;
}
s = headnode; //从头重新开始找
}
//完美全对 在链接好的链表中筛选为两个链表 从该链表中招相同的节点链接为重复链表,并在原链表中删除
int flag=1;
s=head; struct ListNode *rehead=NULL,*oldmove=head;
int collect[100000]={0};
//找相同的 head前一个链表的头,rehead后一个链表的头,move后一个链表移动 oldmove前一个链表移动,s前一个链表找相同的
while(oldmove)
{
int a=abs(oldmove->data);
collect[a]=1; //每循环一次 会多一个1 也就是没有重复链表的节点多一个 在连接时注意顺序 不能改变原链表的相对顺序 所以要用数组记录
while(s->next && collect[ abs(s->next->data)])//没有s->next && 段错误
{
if (flag)//没有头节点分情况
{
rehead=s->next; //重复链表的头节点
move=rehead; //指向重复链表的最后一个节点
s->next = s->next->next;//上面结尾必须为空 否则执行完下面NULL语句后面都为空
move->next = NULL;
flag = 0;
}
else
{
move->next=s->next;//重复链表连接
move=move->next;
s->next=s->next->next;//删除 必须在上面 否则执行完下面后面都为空
move->next = NULL;
}
}
s=oldmove->next; //s指向没有重复链表的下一个 也就是没有重复的链表节点增加1个
oldmove=s;
}
//for (int i=zuihou-count; i>1;i--)有不在链表上的节点,不能用计数器
while (head) //输出没有重复的链表
{
if (head->next)
printf("%s %d %s\n",head->last,head->data,head->next->last);
else
printf("%s %d -1\n",head->last,head->data );
head=head->next;
}
if(rehead) //输出有重复的链表
{
while (rehead->next)
{
printf("%s %d %s\n",rehead->last,rehead->data,rehead->next->last);
rehead=rehead->next;
}
printf("%s %d -1\n",rehead->last,rehead->data );
}
return 0;
}