求交集和并集的线性算法

这篇博客介绍了如何利用哈希表在线性时间复杂度内找到两个集合的交集和并集。通过创建哈希表存储集合元素及其出现次数,遍历两个集合,最终得到交集(哈希表中值为2的键)和并集(哈希表中的所有键)。这种方法可扩展到多个集合的求解,并且可以用map、hash_map或常见数组实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于给定的两个集合,使用哈希表可以在线性时间复杂度内得到他们的交集和并集,具体说明如下:

假设有集合A={1, 7, 5, 13, 9, 10, 11}, B={5, 7, 10, 1, 18, 12},

1)求交集,需要得到结果:A∩B={1, 5, 7,10}

思路如下:

①建立一个哈希表(HashTable),其键(KEY)表示集合中数字的值,其值(VALUE)表示集合中数字出现的次数

②遍历集合A,将集合中的每个数字(KEY)插入哈希表,每个数字的出现次数(VALUE)设置为1

③遍历集合B,对于集合中的每个数字:

如果哈希表中已经存在该数字,将对应的VALUE改为2; 

如果哈希表中不存在该数字,忽略; 

④遍历哈希表,输出VALUE为2的数字,即得到A和B的交集

  1. 求并集,需要得到结果:AUB={1,5,7,9,10,11,12,13,18}

    思路如下:

①建立一个哈希表(HashTable),其键(KEY)表示集合中数字的值,其值(VALUE)可以无视;

②遍历集合A,将集合中的每个数字(KEY)插入哈希表 ;

③遍历集合B,对于集合中的每个数字:

如果哈希表中已经存在该数字,忽略; 

如果哈希表中不存在该数字,将这个数字插入哈希表; 

④遍历哈希表,输出哈希表中的每个KEY,即为A和B的并集

上面以两个集合为例说明了交集和并集的求法,事实上,上述算法可以很方便的扩展到3个或3个以上的集合的求交集和求并集。另外求并集时,由于哈希表的值(VALUE)部分不需要用到,所以这个数据结构也可以更换为哈希集(HashSet或hash_map\map)。

#include <stdio.h>
#include <stdlib.h>
#include <list>
#include <map>
//求交集
void interSection(list<int> &A,list<int> &B,list<int>& C)
{
	map<int,int> mp; 
	for (list<int>::iterator it=A.begin(); it!=A.end(); it++){
		mp[*it] = 1;
	}
	for (list<int>::iterator it=B.begin(); it!=B.end(); it++){
		if (mp.find(*it) != mp.end()){
			mp[*it] += 1;
		}
	}
	for (map<int,int>::iterator it=mp.begin(); it!=mp.end(); it++){
		 //printf("%d-%d\n",it->first,it->second);
		if (it->second > 1){
			C.push_back(it->first);
		}
	}

	return;
}

//求并集
void unionList(list<int> &A,list<int> &B,list<int>& C)
{
	map<int,int> mp;
	for (list<int>::iterator it=A.begin(); it!=A.end(); it++){
		mp[*it] = 1;
	}
	for (list<int>::iterator it=B.begin(); it!=B.end(); it++){
		 mp[*it] = 1;
	}
	for (map<int,int>::iterator it=mp.begin(); it!=mp.end(); it++){
		//printf("%d-%d\n",it->first,it->second);
		if (it->second == 1){
			C.push_back(it->first);
		}
	}

	return;
}

int main()
{
	list<int> L,P;
	for (int i=0; i<10; i++){
		L.push_back(i+1);
		P.push_back(i+6);
	}	 
	list<int> a;
	interSection(L,P,a);

	for (list<int>::iterator it=a.begin(); it!=a.end(); it++){
		printf("%d ",*it);
	}
	a.clear();
	printf("\n");
	unionList(L,P,a);
	for (list<int>::iterator it=a.begin(); it!=a.end(); it++){
		printf("%d ",*it);
	}

	system("pause");
	return 0;
}

以上使用map实现,仍然可以改成hash_map或者常见数组实现。


参考资料:
http://akalius.iteye.com/blog/1211726
另外比较好的资料:
http://blog.csdn.net/jie1991liu/article/details/13168255
map或hash_map常见操作:
http://blog.sina.com.cn/s/blog_61533c9b0100fa7w.html
http://blog.chinaunix.net/uid-26548237-id-3800125.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值