数据结构,多个集合的交并差运算

#include<iostream>
#include<string>
using namespace std;
typedef struct node
{
	int data;//数据
	node* next;//连接下一个节点的指针
}node;
typedef struct Head
{
	node* head;//头指针
	int n;//每个集合中元素的个数
}Head;
class List
{
private:
	int total;//总集合数
public:
	void Input(Head a[], int n1)
	{
		int n;//各个集合中的元素
		this->total = n1;
		for (int i = 0; i < n1; ++i)
		{

			a[i].head = new node;
			a[i].head->next = NULL;
			node* last = a[i].head;
			cout << "输入第" << i + 1 << "个集合的结点数" << endl;
			cin >> n;
			a[i].n = n;
			cout << "输入元素" << endl;
			for (int i = 0; i < n; ++i)
			{
				node* p = new node;
				cin >> p->data;
				last->next = p;
				last = p;
			}
			last->next = NULL;
		}
		Sort(a);
	}
	void Output(Head a[])
	{
		for (int i = 0; i < total; ++i)
		{
			cout << "第" << i + 1 << "个集合的元素有" << a[i].n << "个,分别为" << endl;
			for (node* p = a[i].head->next; p; p = p->next)
			{

				cout << p->data << '\t';
			}
			cout << endl;
		}
	}
	//利用将该链表数据清空思想,再将数据排序插入

	void Sort(Head a[])//递增排序
	{
		//用直接插入排序对每个集合中的元素进行排序
		for (int i = 0; i < total; ++i)
		{
			cout << "第" << i + 1 << " 个集合 ";
			node* p = a[i].head->next->next;//未排序好的结点从第二个数据开始
			a[i].head->next->next = NULL;
			node* q;//未排序好的结点的下一个结点
			node* pre;//已排序好的结点的起点
			while (p)
			{
				q = p->next;
				pre = a[i].head;//不能直接pre=head->next,一但这样如果序好为1,0就无法排序好了
				while (pre->next && pre->next->data < p->data)
					pre = pre->next;
				//只要遍历结束采用头插法插入
				p->next = pre->next;
				pre->next = p;
				p = q;
			}
			int count = 0;//重复数
			//清除重复结点
			for (node* p = a[i].head, *q = a[i].head->next; q;)
			{
				if (p->data == q->data)//重复就删除
				{
					cout << p->data << " ";
					//删除时不要急着p,q移动,p还是指向原来的结点,q指向下一个节点,这样有多少个重复都没事·
					p->next = q->next;
					delete q;
					q = p->next;
					--a[i].n;//该集合中的元素数目减一
					++count;
				}
				else
				{
					p = p->next;
					q = q->next;
				}

			}
			if (count)cout << "重复" << count << "个" << endl;
			else cout << " 无重复 " << endl;
		}

		//用希尔排序对每个集合中数据个数递增排序
		for (int d = total / 2; d > 0; d = d / 2)
			for (int i = d; i < a[i].n; i = i + 1)//未排好序的元素
			{
				int temp = a[i].n;//记录要排序的结点
				//当碰到比temp大的就向后移,否则在碰到小的后面插入
				int j = i - d;
				for (; j >= 0 && a[j].n > temp; j = j - d);
				a[j + d].n = temp;
			}




		cout << "整理结果" << endl;
		Output(a);
	}
	void Union(Head a[], node*& L3)//L1与L2合并成L3
	{
		//初始化L3
		L3 = new node;
		L3->next = NULL;
		node* last = L3;//L3尾结点
		if (total == 1)//只有一个集合时直接复制
		{
			for (node* temp = a[0].head->next; temp; temp = temp->next)
			{
				node* s = new node;
				s->data = temp->data;
				last->next = s;
				last = s;
			}
			last->next = NULL;
			cout << total << "个元素合并结果" << endl;
			for (node* p = L3->next; p; p = p->next)
				cout << p->data << " ";
			cout << endl;
			return;
		}

		for (int i = 1; i < total; ++i)
		{
			node* p = a[i].head->next;
			node* q = a[i - 1].head->next;




			while (p && q)
			{
				if (p->data > q->data)
				{
					node* s = new node;
					s->data = p->data;//数据复制
					last->next = s;
					last = s;
					p = p->next;//插入后要移动
				}
				else if (p->data < q->data)
				{
					node* s = new node;
					s->data = q->data;
					last->next = s;
					last = s;
					q = q->next;//插入后要移动

				}
				else//此时两个相等,只插一个,然后同时移动
				{
					node* s = new node;
					s->data = p->data;
					last->next = s;
					last = s;
					q = q->next;
					p = p->next;
				}

			}

			//跳出循环可能只有一个为空就跳出了
			//若单单p为空,那就直接利用while(q)就余下结点复制下去
			//若单单q为空,可以利用q=p,用q指向p那条不空的链表,同样也可以用while(q)循环复制下去
			if (p)q = p;

			//复制余下结点
			while (q)
			{
				//同样的结点复制过程
				node* s = new node;
				s->data = q->data;
				last->next = s;
				last = s;
				q = q->next;
			}
			last->next = NULL;


		}
		/*合成L3链表的测试
		cout << total << "个集合,合并结果" << endl;
		for (node* p = L3->next; p; p = p->next)
			cout << p->data << " ";
		*/
		//本次合并过程是第一个集合与第二个集合合并,第二个与第三个合并,但能保证相邻集合间无重复,但可能1与4集合有重复数也合并进去了
		//所以还要用一个循环清除L3的重复数
		//而在删去重复的时候也来个排序,过程采用清空,设新指针重新对L3进行插入
		node* p = L3->next->next;//乱序的数据从第二个开始
		node* q;//记录乱序q的下一个节点
		L3->next->next = NULL;//重置L3链表
		node* pre;//指向L3头结点
		while (p)//对乱序数进行排序
		{

			pre = L3;
			q = p->next;
			while (pre->next && pre->next->data < p->data)//当pre下一个结点小于p的data,或不为空继续循环
				pre = pre->next;
			//跳出循环表示遍历到p的data小于pre的data或pre->next此时为空,两者都可以用头插法进行插入
			p->next = pre->next;
			pre->next = p;
			p = q;

		}
		//删除重复结点
		for (node* p = L3->next, *q = p->next; p && q;)
		{
			if (p->data == q->data)
			{
				p->next = q->next;
				delete q;
				q = p->next;
			}
			else
			{
				p = p->next;
				q = q->next;
			}
		}
		cout << total << "个集合,合并结果" << endl;
		for (node* p = L3->next; p; p = p->next)
			cout << p->data << " ";
		cout << endl;

	}


	/*将元素最少的集合赋予链表L4,创建链表时已排序好,再用链表L4与各个集合求交集*/

	void Insersection(Head a[], node*& L4)//交集
	{
		L4 = new node;
		L4->next = NULL;
		node* r = L4;//尾指针
		node* p;//数据插入的结点
		for (node* q = a[0].head->next; q; q = q->next)
		{
			p = new node;
			p->data = q->data;
			r->next = p;
			r = p;
		}
		r->next = NULL;
		//当只有一个集合时直接复制
		if (total == 1) return;
		//使用二路归并
		for (int i = 1; i < total; ++i)
		{
			node* p = L4->next;//p指向L4的首结点
			node* q;//q记录p所指向的下一个结点
			L4->next = NULL;//L4所指的下一个结点指向空当碰到相同的在给L4插入数据
			r = L4;
			node* temp;//遍历比较的集合 
			while (p)
			{
				q = p->next;

				for (temp = a[i].head; temp->next; temp = temp->next)
				{
					if (temp->next->data == p->data)//数据一样,交集插入
					{
						r->next = p;
						r = p;
						p = q;
						break;
					}
					if (temp->next->data > p->data)//此情况表明p前的所有结点都比temp所指结点的数值都小,那p要向后移才可能找到交集
					{
						p = q;
						break;//将p后移然后跳出循环就可
					}

				}
				if (temp->next == NULL)break;//在p所有的元素大于temp时,不可能再有交集,直接进入下一个集合,而判断标志为temp->next==NULL
			}

		}
		r->next = NULL;
		if (L4->next == NULL) { cout << "无交集" << endl; return; }
		cout << "交集结果为" << endl;
		for (node* p = L4->next; p; p = p->next)
			cout << p->data << "  ";
		cout << endl;
	}

	//用数据最多的集合赋予L5,再用L5删去与各集合中最小的
	void Subs(Head a[], node*& L5)
	{
		//initialize L5(初始化L5)
		L5 = new node;
		L5->next = NULL;
		node* r = L5;//tail pointer of L5
		for (node* p = a[total - 1].head->next; p; p = p->next)
		{
			node* q = new node;//split new space for data creation(开辟空间用于数据创建
			q->data = p->data;//data replication(数据的复制)
			//data connection(数据连接)
			r->next = q;
			r = q;
		}
		r->next = NULL;
		//if there is only one set,copy the data of set directly to the linked list
		//(集合只有一个那就将直接将集合里的数据复制给链表)
		if (total == 1);
		else
		{
			//with two-way merge method,reset L5 evert time ,find the match and connect
			//用二路归并法,每次都重置L5,找到符合的再连接起来
			for (int i = total - 2; i>=0; --i)
			{
				node* p = L5->next;
				node* q;//record the next node of p(记录p的下一个结点)
				L5->next = NULL;
				r = L5;//don't forget to reset the tail node(别忘了重置尾结点)
				while(p)
				{
					q = p->next;
					node* temp=a[i].head->next;//pointer to iterate through the ith set(遍历第i个集合的指针)
					//when the value of temp if small,temp alaways move backward
					//当temp的数据比p小,temp就一直往后移
					for (; temp && p->data > temp->data; temp = temp->next);
					if(!(temp!=NULL&&temp->data==p->data))
					{
						r->next = p;
						r = p;
						
					}
					p = q;
				}
				r->next = NULL;
			}
		}
		if (L5->next == NULL) 
		{
			cout << "作差为空" << endl;
			return;
		}
		cout << "最后一个元素与其他元素做差的结果";
		for (node* p = L5->next; p; p = p->next)
			cout << p->data << " ";
		cout << endl;
	}

};
int main()
{
	List list;
	Head* L;
	node* L3;//并集头结点
	node* L4;//交集头结点
	node* L5;//差集头结点
	int n;

	cout << "输入你要创建的集合数" << endl;
	cin >> n;
	L = new Head[n];
	list.Input(L, n);
	list.Union(L, L3);
	list.Insersection(L, L4);
	list.Subs(L, L5);
	return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值