PAT天梯赛L2-002 链表去重 c语言(动态链表存储)

给定一个带整数键值的链表 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;
}
  • 30
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值