数据结构实验 第一单元 集合交并

引用LinkedList.h和string.h

头文件ColletionOpr.h

里面有一些操作集合的算法

//求两个集合的并集
LinkedList* UnionCollection(LinkedList *LA,LinkedList *LB)
{
	LinkedList *ans,*ele;
	DataType* dt;
	int lenA = GetListLength(LA), lenB = GetListLength(LB), len, i, j, exist;
	/*
	一、算法思路:
		1. 将A中 所有元素 填入ans中。
		2. 对于B中的元素,若 不存在于ans中 则加入到ans中。

		时间复杂度:
		第一步的 填入ans 中采用
		ToArray(O(lenA))、CreateListR(O(lenA))方法时间复杂度为:O(lenA)。

		第二步中 遍历B元素
		执行GetListElem(O(lenB)) 、LocateListElem(O(lenB)),
		由于在for循环中,复杂度为:O(lenB^2)。
		
		故整个算法的时间复杂度为:
		O(lenA + lenB^2) 
		
	二、算法优化:
		优化1:
			分析算法可知,将 A、B中长度较短 的放在后面遍历比较合适。
			第一步填入ans的时候,将A、B两者中长度较长的填入ans中。
			这样可以降低第二次遍历集合时候的次数
			优化后复杂度为:

			O(len(较长的) + len(较短的)^2)
		优化2:
	三、算法缺点:
		① 长度较长的那个集合中所有元素均是互异的,否则ans中将出现重复元素。

	四、算法修正:
		为弥补 三 提出的算法缺点。
		在将较长集合填入ans时,应检查重复性。
		修正后算法复杂度为:
		O(lenA^2+lenB^2)
		由此可见,修正后的算法使得 优化1 无效。
	*/
	//代码如下:
	//

	//1.将A中 所有元素 填入ans中。
	//优化1:将较长元素放在A
	/*if(lenA<lenB)
	{
		LinkedList *ltemp=LA;
		LA=LB;
		LB=ltemp;

		int itemp=lenA;
		lenA=lenB;
		lenB=itemp;
	}*/
	//dt = ToArray(LA,&len);
	//ans = CreateListR(dt,len);

	//以下为修正的算法,替换以上。目的是检查重复性。
	//时间复杂度为:O(lenA^2)
	dt = ToArray(LA, &len);//O(lenA)
	ans = CreateListR(NULL, 0);//创建空表
	len = 0;//ans的长度
	for (i = 0; i < lenA; i++)
	{
		exist = 0;
		for (j = 0; j < i; j++)
		{
			if (dt[i] == dt[j])
			{
				exist = 1;
				break;
			}
		}
		if (!exist)
		{
			len++;
			InsertList(ans, len, dt[i]);
		}
	}//O(lenA^2)
	//2. 对于B中的元素,若 不存在于ans中 则加入到ans中。
	for(i=1;i<=lenB;i++)
	{
		ele=GetListElem(LB,i);
		if(LocateListElem(ans,ele->data)==NULL)
		{
			//添加到ans中
			len++;
			InsertList(ans,len,ele->data);
		}
	}

	


	return ans;

}
//求两个集合的交集
LinkedList* InterCollection(LinkedList *LA,LinkedList *LB)
{
	LinkedList 
		*ans = CreateListR(NULL,0),
		*ele;
	int lenA=GetListLength(LA),
		lenB=GetListLength(LB),
		len=0,
		i,j,exist;
	/*
	算法思路:
		1. 遍历A和B中,长度较短的集合。
		2. 若另外一个集合中也存在这个元素,则将这个元素添加到ans中。
		时间复杂度:
		for循环 :O(lenA)
		GetListElem : O(lenA)
		LocateListElem : O(lenB)
		LocateListElem : O(len(ans))
		故总时间复杂度为:O(lenA^2 + lenA*lenB)
		由此可见将遍历较短的元素这个选择是明智的
	算法缺点:
		暂时没发现
	*/
	if(lenA>lenB)
	{
		LinkedList *ltemp=LA;
		LA=LB;
		LB=ltemp;

		int itemp=lenA;
		lenA=lenB;
		lenB=itemp;
	}
	//此时A必定是A,B中长度较短的
	for(i=1;i<=lenA;i++)
	{
		ele=GetListElem(LA,i);
		if(LocateListElem(LB,ele->data)!=NULL)
		{
			//B中存在这个元素
			//避免ans中重复元素。
			if (LocateListElem(ans, ele->data)==NULL)
			{
				len++;
				InsertList(ans, len, ele->data);
			}
		}
	}
	return ans;

}
void TestColletionOpr()
{
	LinkedList *listA,*listB,*unionAns,*interAns;
	char A[100001], B[100001];
	printf("计算两个集合的交集和并集,集合的长度不超过100000\n");
	printf("集合A:");
	scanf("%s",A);
	printf("集合B:");
	scanf("%s",B);

	//创建链表,尾插法。
	listA=CreateListR(A,strlen(A));
	listB=CreateListR(B,strlen(B));
	unionAns=UnionCollection(listA,listB);
	interAns=InterCollection(listA,listB);

	printf("A∪B=");
	PrintListInline(unionAns);
	printf("A∩B=");
	PrintListInline(interAns);
}


转载于:https://www.cnblogs.com/tinyjian/p/6550716.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值