PTA—— 两个有序链表序列的交集

PTA—— 两个有序链表序列的交集C]

题目:
已知两个非降序链表序列S1与S2,设计函数构造出S1与S2的交集新链表S3。
输入格式:
输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。
输出格式:
在一行中输出两个输入序列的交集序列,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出NULL。
输入样例:
1 2 5 -1
2 4 5 8 10 -1

输出样例:
2 5

这道题看着简单,做起来有好多坑啊(呜呜呜)
先说说我的思路吧
首先,用一个结构体存储第一个序列每个节点信息,1).数值 2).cnt 3).指向下一结点的指针。cnt表示数组出现的次数。

struct node{
 int num;
 int cnt;
 struct node* next;
};
typedef struct node LISTNODE;
typedef LISTNODE* LISTPTR;

接下来就是读取第一个序列中的元素创建链表了,那么出现了重复的元素呢?跳过还是cnt++呢。这个问题暂时不说,下面随着分析就知道了。
对于第二个序列,刚开始我用一个insert函数对每一个读入的x,如果是第一个序列的元素的话,对应元素cnt++,否则把x插入链表。但是这样做最后一组数据运行超时。想想如果x不是第一个序列中的元素的话直接跳过就?干嘛还要连接在原来的序列上?
所以我就改了insert函数,确实不超时了,但是!但是!答案错误!

这就引出了这道题又一处特别坑的地方:当一个数在两个序列中都不止一次出现时,举个例子,第一个序列含有1、1,第二个序列也含有1、1,那么对应交集元素是1、1而不是1。啊,原来是这样。原来和数学中的集合元素互异性矛盾了呀。做到这回到题目,题目说的是非降序序列,貌似不是非降序集合啊。好吧,只能承认,这是自己的问题。
所以到这,所有问题都有答案了。cnt只有1、2取值。1表示只在第一个序列出现过,2表示在第两个序列都出现过。建第一个链表是把每个值的cnt置为1(出现相同元素先不管就直接连在后面)。max是记录序列最后一个书也就是最大的那个数。这个在后面的主函数中可以看到,对运行时间还是有一定帮助的。
代码就是这样的

LISTPTR creat(int *max){
 int x;
 LISTPTR head=NULL,p=NULL,pre=NULL,last=NULL;
 head=(LISTPTR)malloc(sizeof(LISTNODE));head->num=0;head->cnt=0;
 pre=head;last=head;
 scanf("%d",&x);
 while(x!=-1){
  p=(LISTPTR)malloc(sizeof(LISTNODE));
  p->num=x; p->cnt=1;pre->next=p;pre=pre->next;last=p;
  scanf("%d",&x);
 }
 last->next=NULL;*max=last->num;
 return head;
}

建好以后就可以对第二个序列每一个x查找插入了。

LISTPTR insert(LISTPTR head,int x){
 LISTPTR pre=head,p=head->next;
 while(p!=NULL&&(x>p->num||(x==p->num&&p->cnt==2))){//注意22 和22的交集是22不是2啊啊啊啊啊 
  pre=pre->next;p=p->next;
 }
 if(p!=NULL){
  if(x==p->num) p->cnt++;
 }
 return head;
}

下面是完整代码

#include<stdio.h>
#include<stdlib.h> 
struct node{
 int num;
 int cnt;
 struct node* next;
};
typedef struct node LISTNODE;
typedef LISTNODE* LISTPTR;
LISTPTR creat(int *max);//创建带头结点的链表 
LISTPTR insert(LISTPTR head,int x);
void print_intersection(LISTPTR head);//输出交集 
void destroylist(LISTPTR head);//释放 
int main(){
 LISTPTR head;
 int x,max;
 head=creat(&max);
 scanf("%d",&x);
 while(x!=-1){
  if(x>max) break;//还有这里也是 减少运行时间的一步 第二个序列大于max的部分直接咔掉 
  head=insert(head,x);
  scanf("%d",&x);
 }
 print_intersection(head->next);
 destroylist(head);
 return 0;
}
LISTPTR creat(int *max){
 int x;
 LISTPTR head=NULL,p=NULL,pre=NULL,last=NULL;
 head=(LISTPTR)malloc(sizeof(LISTNODE));head->num=0;head->cnt=0;
 pre=head;last=head;
 scanf("%d",&x);
 while(x!=-1){
  p=(LISTPTR)malloc(sizeof(LISTNODE));
  p->num=x; p->cnt=1;pre->next=p;pre=pre->next;last=p;
  scanf("%d",&x);
 }
 last->next=NULL;*max=last->num;
 return head;
}
LISTPTR insert(LISTPTR head,int x){
 LISTPTR pre=head,p=head->next;
 while(p!=NULL&&(x>p->num||(x==p->num&&p->cnt==2))){//注意22 和22的交集是22不是2啊啊啊啊啊 
  pre=pre->next;p=p->next;
 }
 if(p!=NULL){
  if(x==p->num) p->cnt++;
 }
 return head;
}
void print_intersection(LISTPTR head){//交集重新组一条链 
 LISTPTR headPtr=NULL,ptr=head,lastPtr=NULL;//headPtr、lastPtr是交集链表的头、尾 
 while(ptr!=NULL){
  if(ptr->cnt>1){
   if(headPtr==NULL){//当前的Ptr指向交集第一个元素 
    headPtr=ptr;lastPtr=ptr;
   }
   else{
    lastPtr->next=ptr;
    lastPtr=lastPtr->next;
   }
  }
  ptr=ptr->next;
 }
 if(headPtr!=NULL)lastPtr->next=NULL;//直接=NULL会出现段错误,有可能交集是空集 
 if(headPtr==NULL) printf("NULL");
 else{
  while(headPtr->next!=NULL){
   printf("%d ",headPtr->num);
   headPtr=headPtr->next;
  }
  printf("%d",headPtr->num);
 }
}
void destroylist(LISTPTR head){
 LISTPTR tempPtr;
 while(head!=NULL){
  tempPtr=head;
  head=head->next;
  tempPtr->next=NULL;
  free(tempPtr);
 }
}
  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值