集合的交集、并集、差集和输入数据时查重(链表)

一、实验要求

a)从程序完善性上考虑,集合元素输入时,要有检查元素重复的功能,每个集合中不允许有重复的元素。集合可以用数组存储,也可以用链表存储。

b)实现交、并、差运算时,分别把代码写成函数的形式,即实现交运算的函数,实现并运算的函数,实现差运算的函数,在主函数中分别调用三个函数。

c)使用菜单形式对应各个操作,应允许用户反复查看结果,想结束程序时,输入负数结束,使其编成一个完整的小软件。菜单参考示例如下:

1---输入集合A和B

2---求集合A交B

3---求集合A并B

4---求集合A-B

退出,输入一个负数!

二、设计思想

1.实验要求写为菜单形式,用Switch分支语句最方便,并且应用while循环语句使用户得以重复使用功能。先把菜单和Switch的框架写出来,然后再填充各个函数实现功能。在用户选择2,3,4操作时,应先判断此时是否存在集合A,B。

2.对于查重,应在每次输入数据后,用该数据与已输入数据进行比对,若有重复的则使其重新输入,所以此处应用循环语句,设一标记flag,当输入符合条件的数据时跳出循环。对于查重函数,参数为链表头指针和输入的数据,先检查头指针是否为NULL,若是表明链表无数据,不需要比较,否则依次比较。当输入的数据已存在时,为了使数据可以继续输入(我设置当输入 -1 时停止输入,以防用户一次输入所有数据(例1 2 1 3 4 5 -1)造成输入停止),应清空重复数据之后的缓冲区,使用户得以继续输入。

3.求并集,为保留原数据,创建新的链表复制集合A,拿集合B的一个元素依次与新链表的全部元素比较,若没有相同的数据则在新链表之后添加该数据,直至集合B的最后一个元素比较完毕。

4.求交集,创建新链表,拿集合B的一个元素依次与集合A的元素比较,若有相同的元素,则把这个元素复制到新链表末尾。

5.求差,创建新链表,A-B时,拿集合A的一个元素依次与集合B的元素比较,若无相同的元素,把其复制到新链表末尾。B-A同理。

三、代码

1.主函数、菜单和判断集合是否存在的函数

struct Link
{
	int date;
	struct Link* next;
};
typedef struct Link link;

void menu()
{
	cout << "*******************************" << endl;
	cout << "* 请选择:                    *" << endl;
	cout << "*        1.输入集合A和B       *" << endl;
	cout << "*        2.求集合A并B         *" << endl;
	cout << "*        3.求集合A交B         *" << endl;
	cout << "*        4.求集合 A-B 和 B-A  *" << endl;
	cout << "*       输入任意负数退出      *" << endl;
	cout << "*******************************" << endl;
}

//判断集合AB是否存在
bool judge(link* head1, link* head2)
{
	if (head1 != NULL && head2 != NULL)
		return true;
	else
	{
		cout << "请先输入集合A B(完成操作1)" << endl;
		return false;
	}
}

int main()
{
	link* head1 = NULL,* head2 = NULL;
	int n = 0;
	while (n >= 0)
	{
		menu();
		cin >> n;
		switch (n)
		{
		case 1:
			cout << "请输入集合A(当输入-1时结束):" << endl;
			head1 = create();
			cout << "请输入集合B(当输入-1时结束):" << endl;
			head2 = create();
			cout << "集合A: ";
			output(head1);
			cout << "集合B: ";
			output(head2);
			break;
		case 2:
			if (judge(head1, head2))
				bing(head1, head2);
			break;
		case 3:
			if (judge(head1, head2))
				jiao(head1, head2);
			break;
		case 4:
			if (judge(head1, head2))
			{
				cout << "集合A-B: ";
				cha(head1, head2);
				cout << endl;
				cout << "集合B-A:";
				cha(head2, head1);
			}
			break;
		}
     if (n > 4)
			cout << "请输入合适的代号" << endl;
	}
	return 0;
}

2.创建集合A、B,查重

我设置当输入 -1 时停止输入,以防用户一次输入所有数据(例1 2 1 3 4 5 -1)造成输入停止,应清空重复数据之后的缓冲区,使用户得以继续输入。

bool check(link* head, int n) //查重
{
	link* pre = head;
	int ch = 0;
	if (pre->next == NULL)//空链表不用比较
		return false;
	while (pre->next != NULL)
	{
		pre = pre->next;
        //拿新输入的数和之前输入进来的数比较,若重复则置为true,再次进入循环重新输入
		if (pre->date == n)
		{
			cout << "元素" << n << "与已输入元素重复,无效输入,请重新输入后续元素" << endl;
			while (getchar() != '\n')
			{//清空缓存区,当输入重复时不因为-1而结束该集合的输入,可以继续输入新的元素
			}
			return true;
		}
	}
	return false;
}

//创建链表(当输入-1时结束)
link* create()
{
	link* head, * pre, * p;
	head = pre = (link*)malloc(sizeof(Link));
	head->next = NULL;

	while (1)
	{
		bool flag = true;
		int n = 0;
		p = (link*)malloc(sizeof(Link));
		while (flag)
		{
			cin >> n;
			flag = check(head, n);//先比较,输入不重复置false出循环
			if (n == -1)
				break;
		}
		if (n == -1)
			break;
		p->date = n;
		p->next = NULL;
		pre->next = p;
		pre = p;
	}
	return head;
}

//输出链表
void output(link* head)
{
	link* pre;
	pre = head->next;
	cout << "{ ";
	while (pre->next != NULL)
	{
		cout << pre->date << ",";
		pre = pre->next;
	}
	cout << pre->date << " }";
	cout << endl;
	cout << endl;
}

3.集合并集

void bing(link* head1, link* head2)
{
	link* pre1, * pre2, * head, * pre, * p;
	pre1 = head1->next;
	pre2 = head2->next;
	head = (link*)malloc(sizeof(Link));
	pre = head;
	head->next = NULL;
	while (pre1 != NULL) //保留原数据,新建集合C复制集合A
	{
		p = (link*)malloc(sizeof(Link));
		p->date = pre1->date;
		pre->next = p;
		pre = p;
		p->next = NULL;
		pre1 = pre1->next;
	}
	while (pre2 != NULL)//拿集合B里的一个数和新集合的每一个数进行比较
	{
		int flag = 1;
		pre = head->next;//保证每次从头开始比较

		while (pre->next != NULL)//若此处为pre->next!=NULL则出循环时pre为空,无法在末尾拼接数据。
		{
			if (pre2->date == pre->date)//相等时,集合B元素不符合条件
			{
				flag = 0;         //flag置0,不让该元素进入新集合
				break;            //跳出这次循环,从集合B的下一个元素重新开始
			}
			pre = pre->next;
		}

		if (pre2->date == pre->date)  //此时pre在末尾,刚好可以进行拼接
		{
			flag = 0;
		}
		if (flag == 1)
		{
			p = (link*)malloc(sizeof(Link));
			pre->next = p;
			p->date = pre2->date;
			p->next = NULL;
		}
		pre2 = pre2->next;
	}
	cout << "集合A并B为: ";
	output(head);
}

4、集合交集

void jiao(link* head1, link* head2)
{
	link* head, * pre, * pre1, * pre2, * p;
	pre1 = head1->next;
	head = pre = (link*)malloc(sizeof(Link));
	head->next = NULL;//创新新链表保存交集元素
    //拿集合A的一个数和集合B的每个数比较
	while (pre1 != NULL)
	{
		pre2 = head2->next;
		while (pre2 != NULL)
		{
			if (pre1->date == pre2->date) //相等时符合条件,直接添加到新链表里
			{
				p = (link*)malloc(sizeof(Link));
				p->date = pre1->date;
				p->next = NULL;
				pre->next = p;
				pre = p;
				break;
			}
			pre2 = pre2->next;
		}
		pre1 = pre1->next;
	}
	cout << "集合A交B为: ";
	output(head);
}

5、集合差集

A-B是在集合A而不在B中的元素,拿集合A的一个元素和集合B的每个元素比较,一旦相等就不符合条件。B-A同理。

void cha(link* head1, link* head2)
{
	link* head, * pre, * pre1, * pre2, * p;
	pre1 = head1->next;
	head = pre = (link*)malloc(sizeof(Link));//新建链表保存差集元素
	head->next = NULL;  
  //A-B是在集合A而不在B中的元素,拿集合A的一个元素和集合B的每个元素比较,一旦相等就不符合条件
	while (pre1 != NULL)
	{
		bool flag = true;
		pre2 = head2->next;
		while (pre2 != NULL)
		{
			if (pre1->date == pre2->date)
			{
				flag = false;   //相等不符合条件,置false不让其进入新链表
				break;
			}
			pre2 = pre2->next;
		}
		if (flag)
		{
			p = (link*)malloc(sizeof(Link));
			p->date = pre1->date;
			p->next = NULL;
			pre->next = p;
			pre = p;
		}
		pre1 = pre1->next;
	}
	output(head);
}

练习才是王道!

与君共勉。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值