C数据结构——链表求交集与并集


//作者:Ricardo.M.Tan
#include"stdafx.h"
#include"stdio.h"
#include"malloc.h"
#include"string.h"
#include<iostream>

typedef int Datatype;
typedef struct Node
{
	Datatype data;
	struct Node *next;
}Node, *Link;

//定义两个全局的指针变量,作用类似于中转枢纽
Link gp1 = NULL;
Link gp2 = NULL;

static Link creat()
{
	Link H, p, q;
	Datatype data;
	int i = 1;
	int NodeCount = 0;
	printf("请输入将创建的链表的长度:");
	scanf_s("%d", &NodeCount);

	if (NodeCount <= 0)
	{
		printf("创建失败!");
		return H;
	}
	H = (Link)malloc(sizeof(Node));
	p = H;
	printf("请输入节点 %d 的存储值:", i);
	scanf_s("%d", &data);
	while (--NodeCount)
	{
		q = (Link)malloc(sizeof(Node));
		p->next = q;
		q->data = data;
		p = q;
		printf("请输入节点 %d 的存储值:", ++i);
		scanf_s("%d", &data);
	}
	q = (Link)malloc(sizeof(Node));
	p->next = q;
	q->data = data;
	p = q;
	p->next = NULL;
	return(H);
}



//求交集
Link Intersection(Link H1, Link H2){
	Link head = (Link)malloc(sizeof(Datatype));
	Link tmp = head, s;
	tmp->next = NULL;
	Link p1 = H1->next, p2 = H2->next;//p1,p2分别指向两张链表的第一个存储位置
	while (p1 != NULL)//p1指向空结束
	{
		while (p2 != NULL)//p2指向空结束
		{
			if (p2->data == p1->data)
			{
				s = (Link)malloc(sizeof(Datatype));
				s->data = p1->data;
				s->next = NULL;
				tmp->next = s;
				tmp = s;
				break;
			}
			p2 = p2->next;//p2前移,循环遍历
		}

		p1 = p1->next;
		p2 = H2->next;//重置p2的指向
	}

	return head;
}



//求并集
Link UnionSet(Link head1, Link head2)
{
	Link head = (Link)malloc(sizeof(Node));
	head->next = NULL;
	Link tail = head;
	Link InS = Intersection(head1, head2);//接收返回值
	Link s, p1 = head1->next, p2 = head2->next, p3 = InS->next;


	//遍历第一张链表并复制,以便接下来链接
	while (p1)
	{
		s = (Link)malloc(sizeof(Node));
		s->data = p1->data;
		s->next = tail->next;
		tail->next = s;
		tail = s;
		p1 = p1->next;
	}


	//接上面复制链表,将不是交集里含有的数据写入,类似链表插入
	while (p2)
	{
		while (p3)//此循环用于遍历交集,判断p2指向的存储单元的存储值是否在交集中出现
		{
			if (p2->data == p3->data)
				break;//终止此层循环,跳出前不会执行下一句
			p3 = p3->next;//条件不成立则p3指针前移
		}
		//若上面的执行后,p2指向的存储单元的存储值没在交集中出现,此时的p3指向NULL,若出现,p3将被重置,不写入
		if (!p3)//逻辑非运算(!),即当p3=NULL时,!p3=1,为真值(true),执行语句块,反之,当p3!=NULL时,!p3=0,为假值(false),不执行语句块 
		{
			s = (Link)malloc(sizeof(Node));
			s->data = p2->data;
			s->next = tail->next;
			tail->next = s;
			tail = s;
		}

		p3 = InS->next;/*重置p3的指向*/
		p2 = p2->next;/*p2指针前移,循环遍历第二张链表*/
	}
	return head;
}


//一般输出链表
void op(Link head)
{
	Link p;
	p = head;
	while (p->next != NULL)
	{
		printf("%4d", p->next->data);
		p = p->next;
	}
}


//用于输出集合(比op()函数多了:1、空链表的判断 2、统计集合中元素个数)
void Print(Link head)
{
	Link p = head->next;
	int count = 0;
	if (p == NULL)
	{
		printf("空集!\n");
		return;
	}

	while (p)
	{
		printf("%3d", p->data);
		count++;
		p = p->next;
	}
	printf("(共%d个数据)\n", count);
}



//主函数入口

int main()
{
	int flag = 1;
	int count = 1;//用于执行控制
	printf("----------------------\n提示:请先创建链表!!!\n----------------------\n");
	while (flag)
	{
		printf("\t\t 1--创建2张新链表\n");
		printf("\t\t 2--求交集\n");
		printf("\t\t 3--求并集\n");
		printf("\t\t 0--退出程序\n");
		printf("请选择序号:");
		scanf("%d", &flag);


		//简单处理异常
		if (flag>3){
			printf("----------------------------\n警告:指令表不包含该序号!!!\n----------------------------\n");
		}
		else{
			if (flag>count){
				count = 4;
				printf("----------------------------------------\n警告:还未创建链表,自动跳转到创建链表!!!\n----------------------------------------\n");
				goto lable;

			}
			switch (flag)
			{
			lable:
			case1 :
			{

				printf("创建第一张链表\n");
				gp1 = creat();
				printf("新建链表:");
				op(gp1);
				printf("\n");
				printf("\n创建第二张链表\n");
				gp2 = creat();
				printf("新建链表:");
				op(gp2);
				printf("\n\n");
			}
				  break;

			  case 2:
				  {
					  printf("\n交集为:");
					  Link InS = Intersection(gp1, gp2);
					  Print(InS);
					  printf("\n\n");
				  }
				  break;
			  case 3:
				  {
					  printf("\n并集为:");
					  Link Union = UnionSet(gp1, gp2);
					  Print(Union);
					  printf("\n\n");
				  }
				  break;
			  case 0:
				  break;
			default:
				printf("警告,错误!!!\n");
				break;
			}
		}
	}
	//system("pause");
	return 0;
}

 

  • 17
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值