C语言集合的运算

时间:2022-09-08 02:14:32


一.集合运算目的
        通过对集合交集,并集,差集运算来进一步熟悉和掌握链表的创建,删除,插入等一些基本的操作。
二.集合运算内容
      定义两个集合A和B:
           差集 :A与B的差集就是该元素属于A集合而不属于集合。并集:A与B相结合该元素既属于A又属于B。交集:A与B相同的一部分,既属于A又属于B。其实这个运算器有两种做法,一是重新malloc空间,将它们处理后的数都专门放到一个链表中去,这样虽然简单,易操作,但是空间的复杂度就高了;二是不malloc空间,我直接用A链为主链对其操作,在其上对链表的元素进行插入,删除,等操作,空间复杂度就可以不用考虑了。

三.集合运算代码

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<conio.h>
typedef struct node
{
	int data;
	struct node *next;
}linklist;
linklist *initlist()      //链表的初始化
{   
	int d;
        linklist *p,*head,*q;
	head=(linklist*)malloc(sizeof(linklist)); //具有头结点
	head->next=NULL;
	p=head;
        scanf("%d",&d);
        while(d)                        
	{
	   q=(linklist*)malloc(sizeof(linklist));
	   q->data=d;
           p->next=q;                   //  利用尾差法
           p=q;
	   p->next=NULL;
	   scanf("%d",&d);
	 }
	return head;
}
linklist *xiangjian(linklist *head1,linklist *head2)         //集合的差运算
{  
	int flag=0;
        linklist*p1,*p2,*q;
	p1=head1;
        p2=head1->next;
        while(p2&&p2->next)
	{
	 for(q=head2->next;q;q=q->next)
            if(p2->data==q->data)
	    {
		p1->next=p2->next;
		free(p2);
                p2=p1->next;
		 flag=1;
	    }
	   if(flag==0)
	   {
		   p1=p1->next;
		   p2=p2->next;
	   }
	   else
		   flag=0;
	}
	
	return head1;
} 
linklist *hebing(linklist *head1,linklist *head2)     // 集合的合并
{    
	int flag=0;
        linklist *p,*q,*m;
        p=head1->next;  
        while(p)
	 {
	    for(q=head2->next;q;q=q->next)
	     {
		  if(p->data==q->data)
		  {
		     flag=1;
                     break;
		   }	 
		
	     }
	     if(flag==0)
	     {
		  m=(linklist*)malloc(sizeof(linklist));
		  m->data=p->data;
                  m->next=head2->next;
	          head2->next=m;
	     }
	     flag=0;
	     p=p->next;
	 }
     return head2;
}
linklist *jiaoji(linklist*head1,linklist *head2)    // 集合的交集
{
        linklist *p,*q,*m,*head;
	head=(linklist*)malloc(sizeof(linklist));
	head->next=NULL;
	p=head1->next;
       while(p)
	{
	  for(q=head2->next;q;q=q->next)
	  if(q->data==p->data)
	  {
             m=(linklist*)malloc(sizeof(linklist));
	     m->data=p->data;
             m->next=head->next;
	     head->next=m;
	     break;
          }
    	 p=p->next;
	}
  return head;
}
int estimate(linklist *head)      // 看链表里面是否有重复元素
{ 
	linklist *p,*q;
	if(head->next==NULL)
           return 0;
	for(p=head->next;p->next;p=p->next)
          for(q=p->next;q;q=q->next)
		   if(p->data==q->data)
		   {
			   return 1;
		   } 
	return 0;
}
 void print(linklist *head)         //链表的输出
{
	linklist *p;
	p=head->next;
	while(p)
	{	
		
	    printf("%d  ",p->data);
	    p=p->next;
	}
}
int main()
{     
	  int x;
	  char ch;
          linklist *head1,*head2,*head3,*head4,*head5;
	  printf("请输入链表1: ");
	  head1=initlist();
	  printf("请输入链表2: ");
          head2=initlist();
	  if(estimate(head1)||estimate(head2))
	  {
		  printf("集合 1 或者 集合 2 不合法,自动退出\n");
		  exit(-1);
	  }
	  else
	     printf("\n创建列表成功\n");
	  Sleep(2000);
	  while(1)
	  {
          system("cls");
		  printf("1  集合相减 \n");
		  printf("2  集合合并 \n");
		  printf("3  集合交集 \n");
		  printf("       请选择(1-3)");
		  scanf("%d",&x);
		  switch(x)
		  {
		  case 1 :system("cls");
			  printf("输出链表1: ");
                          print(head1);
	                  printf("\n 输出链表2: ");
	                  print(head2);
			  head3=xiangjian(head1,head2);
		          printf("\n 集合相减: ");
		          print(head3);
			  printf("\n按任意继续.................\n");
			  getch();
			  break;
		  case 2 :system("cls");
		          printf("输出链表1: ");
                          print(head1);
	                  printf("\n 输出链表2: ");
	                  print(head2);
			  head4=hebing(head1,head2);
			  printf("\n 集合合并: ");
			  print(head4);
			  printf("\n按任意继续.................\n");
			  getch();
			  break;
		  case 3 :system("cls");
		          printf("输出链表1: ");
                          print(head1);
	                  printf("\n 输出链表2: ");
	                  print(head2);
			  head5=jiaoji(head1,head2);
			  printf("\n 集合交集: ");
			  print(head5);
			  printf("\n按任意继续.................\n");
			  getch();
			  break;
		  default:system("cls");
			  printf("你的输入有误 ");
			  printf("\n按任意继续.................\n");
			  getch();
			  break;
		  }
		  printf("\n如果想退出,请按n\n");
		  ch=getch();
		  if(ch=='n')
			  break;
	  }
	  printf("程序已完成,谢谢\n");			 
	  return 0;
}

四.集合运算分析

     差集:将A和B链表传入差集函数xiangjian(head1,head2),定义3个指针变量,p1总是p2的前驱节点,遇到相等就把A链中的值删除了,p2和p1重新指向,用flag标记遇到相等转变一次,否则,p1和p2同时向后面移动,主要思路还是两层循环,在A链一层循环基础上让B链进行第二层循环遍历,对值进行判断。

    并集:将A和B链表传入合并函数hebing (head1,head2),还是用到3个指针变量,在A链一层循环基础上让B链进行第二层循环遍历是,一遇相等的值,直接break跳出,标记flag=1;进行下一次。当遍历B链表完之后,没有相等的值,那么给m开辟空间,利用头插法插在B链表的前面,最后返回head2.

   交集:将A和B链表传入交集函数jiaoji (head1,head2),对于这个函数,我重新开辟了一个链表,继续两层循环,和上面的思路一样,如果遇到相等的,就把该值放在新开辟的链表中。

五. 总结

    我这次做的集合只考虑数字,用int而没有用char,如果出现字母我的就不能运行了,我也想过用字符做,我认为最应该考虑的地方输入问题,字符是一个一个读入的,连续输入就能出现95,110等多位数字,这就需要用到空格隔开处理,其他的做法和整型一样的。