两个数组取交集算法
‘壹’ c语言求两个数组的并交集
只简单地分析了一下交集的情况,求并集类似。网络知道这个代码支持不怎么好,复制粘贴到 vs 之类的代码编辑器里面缩进一下会比较好看。
见代码如下:
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <time.h>
// 使用整型数组为例,其它数组同理
// 交集
// 通过迭代遍历判断相同元素,时间复杂度较高,平方量级
// 传入原数组及其长度、结果数组
// 返回结果数组的长度
// (需要自行保证结果数组足够大)
size_t getIntersection(array1, array1_len, array2, array2_len, result_array)
int* array1, * array2, * result_array;
size_t array1_len, array2_len;
{
size_t result_p = 0;
for (size_t i = 0; i < array1_len; ++i)
{
for (size_t j = 0; j < array2_len; ++j)
{
if (array1[i] == array2[j])
{
result_array[result_p++] = array1[i];
break;
}
}
}
return result_p;
}
// 另一种思路是用快速排序等高效的排序算法先将数组排序,
// 然后再遍历一次数组,这时因为已经排好序了,所以最多只要
// 遍历 array1_len + array2_len 即可,此时时间复杂度较低,
// 因为快速排序等一般是 nlog(n),然后后面接一个一次量级的遍历,
// 总的来说是 nlog(n) + n,也就是 nlog(n),比 n^2 要快一些。
int intAscendingComparor(const void* left, const void* right)
{
return *(int*)left - *(int*)right;
}
// 交集
// 先排序后遍历判断相同元素,时间复杂度较低
// 传入原数组及其长度、结果数组
// 返回结果数组的长度
// (需要自行保证结果数组足够大)
size_t getIntersection_optimized(array1, array1_len, array2, array2_len, result_array)
int* array1, * array2, * result_array;
size_t array1_len, array2_len;
{
size_t result_p = 0;
size_t i = 0;
// 使用标准库的 qsort 比较方便
int* tmpArray = (int*)malloc(sizeof(int) * (array1_len + array2_len));
for (i = 0; i < array1_len; ++i) tmpArray[i] = array1[i];
for (i = 0; i < array2_len; ++i) tmpArray[array1_len + i] = array2[i];
qsort(tmpArray, array1_len + array2_len, sizeof(int), intAscendingComparor);
for (size_t i = 0; i < array1_len + array2_len - 1; ++i)
{
if (tmpArray[i] == tmpArray[i + 1])
{
result_array[result_p++] = tmpArray[i];
do {
++i;
} while (i < array1_len + array2_len - 1 && tmpArray[i] == tmpArray[i + 1]);
}
}
free(tmpArray); tmpArray = NULL;
return result_p;
}
// 自定义的一个简单的输出数组内容的函数
void printArray(int* array, size_t len)
{
for (size_t i = 0; i < len - 1; ++i)
{
printf("%d, ", array[i]);
}
printf("%d", array[len - 1]);
}
int main()
{
clock_t start, end;
int first_array[5] = { 1, 2, 3, 4, 5 };
int second_array[4] = { 4, 5, 6, 7 };
printf("数组1为:{ 1, 2, 3, 4, 5 },数组2为:{ 4, 5, 6, 7 } ");
// 第一种方法
int result_array[10];
start = clock();
size_t result_array_len = getIntersection(first_array, 5, second_array, 4, result_array);
end = clock();
printf("交集为:{ ");
printArray(result_array, result_array_len);
printf(" },使用时间:%d ms ", (end - start) * 1000 / CLOCKS_PER_SEC);
// 第二种方法
start = clock();
result_array_len = getIntersection_optimized(first_array, 5, second_array, 4, result_array);
end = clock();
printf("使用优化算法求出的交集:{ ");
printArray(result_array, result_array_len);
printf(" },使用时间:%d ms ", (end - start) * 1000 / CLOCKS_PER_SEC);
// 接下来用两个比较大的数组,测试一下两种方法的效率
printf(" 下面是测试,求一个包含 100000 个元素和一个包含 199999 个元素的数组的交集: ");
#define len1 100000
#define len2 199999
int* testArray1 = (int*)malloc(sizeof(int) * len1);
int* testArray2 = (int*)malloc(sizeof(int) * len2);
int* testArray = (int*)malloc(sizeof(int) * len1);
start = clock();
for (size_t i = 0; i < len1; ++i) testArray1[i] = i;
for (size_t i = 0; i < len2; ++i) testArray2[i] = i + 12345;
end = clock();
printf("初始化数组用时:%d ms ", (end - start) * 1000 / CLOCKS_PER_SEC);
start = clock();
result_array_len = getIntersection(testArray1, len1, testArray2, len2, testArray);
end = clock();
printf("第一种方法用时:%d ms ", (end - start) * 1000 / CLOCKS_PER_SEC);
start = clock();
result_array_len = getIntersection_optimized(testArray1, len1, testArray2, len2, testArray);
end = clock();
printf("第二种方法用时:%d ms ", (end - start) * 1000 / CLOCKS_PER_SEC);
return 0;
}
注释应该说明得比较清楚了,这里就不赘言了。
下面分别是在 Windows 上 msvc 和 mingw 编译并运行的结果:
mingw
‘贰’ 如何求两个数组的交集
可以新建一个集合,遍历一个数组,逐个判断另一个数组是否包含这个元素,包含则list.add(),最后这个list中的元素,就是重叠的
‘叁’ 求两个数组的交集算法
数组求交集的方法
1.暴力搜索
2.利用HashMap
3.先排序再用两个指针查找
4.位图法
5.大文件求交集用分治法,组内用位图法
‘肆’ 求助:两个数组的交集
在php中求数组的交集,我们可以与PHP给我们提供的现成函数:array_intersect(),其用法格式为:
array array_intersect(array array1,array array2[,arrayN…])
根据上述的语法格式,我们来写一个例子:
1 <?php
2 $fruit1 = array("Apple","Banana","Orange");
3 $fruit2 = array("Pear","Apple","Grape");
4 $fruit3 = array("Watermelon","Orange","Apple");
5 $intersection = array_intersect($fruit1, $fruit2, $fruit3);
6 print_r($intersection);
7 // 输出结果:
8 // Array ( [0] => Apple )
9 ?>
本例子将返回在$fruit1数组中出现且在$fruit2和$fruit3中也出现的所有水果的名子。
使用array_intersect()函数时要注意:只有在两个元素相等且具有相同的数据类型时,array_intersect()函数才会认
为它们是相同的,否则不能进行交集计算。array_intersect()函数返回一个保留了键的数组,只由第一个数组中出现的且在其它数组中都出现的
值组成。
若要求关联数组的交集,请使用array_intersect_assoc()函数,给你个简单的例子:
1 <?php
2 $fruit1 = array("red"=>"Apple","yellow"=>"Banana","orange"=>"Orange");
3 $fruit2 = array("yellow"=>"Pear","red"=>"Apple","purple"=>"Grape");
4 $fruit3 = array("green"=>"Watermelon","orange"=>"Orange","red"=>"Apple");
5 $intersection = array_intersect_assoc($fruit1, $fruit2, $fruit3);
6 print_r($intersection);
7 // 输出:
8 // Array ( [red] => Apple )
9 ?>
array_intersect_assoc()函数语法格式如下:
array array_intersect_assoc(array array1,array array2[,arrayN…])
array_intersect_assoc()与array_intersect()基本相同,只不过他在比较中还考虑了数组的键。因此,只有在第一个数组中出现,且在所有其他输入数组中也出现的键/值对才返回到结果数组中。
‘伍’ 如何快速取两个二维数组中的交集
一维数组取交集是非常的简单,直接用一个函数即可。array_intersect($arr, $ar),那么二维数组又是如何的取出它们的交集呢,可能有人同样想用这个函数,但结果却不是我们想要的。下面有这样的一个数组:
$arr=array(
array('a'=>'1',2),
array(3,4)
);
$ar=array(
array('a'=>1,2),
array(3,4)
);
如果我单独用 array_intersect($arr, $ar)。返回的结果如下:
array(
array('a'=>'1',2),
array(3,4)
);
‘陆’ 怎样对数组进行交集与并集运算
数组的并集
给定两个数组:
int[] a = {1, 2, 3, 4, 5};
int[] b = {2, 3, 5, 6, 7};
输出:
1,2,3,4,5,6,7
我的思路:
两个数组的交集第一时间想到的肯定是最简单的两两比较,如果相等就加进新数组,但是这样做会造成时间的大量浪费,如果两个长度各1W的数组,比较完的时间….不可想象。
然后马上就想到Java的HashSet,重复不添加,所以把所有的数组遍历进Set,再遍历Set岂不是就完成了。
于是很容易实现了我的代码:
int[] a = {1, 2, 3, 4, 5}; int[] b = {2, 3, 5, 6, 7};
HashSet<Integer> hashSet = new HashSet<>(); for (int aNum : a) {
hashSet.add(aNum);
} for (int bNum : b) {
hashSet.add(bNum);
}
Iterator<Integer> iterator = hashSet.iterator(); while(iterator.hasNext()){
System.out.print(iterator.next()+" ");
}
数组的交集
给定两个数组:
int[] a = {1, 2, 3, 4, 5};
int[] b = {2, 3, 5, 6, 7};
输出:
3,4,5
我的思路:与之前相同,强行跑遍历的算法肯定是不可取的,又想到了之前在一堆有重复数的数组中找出唯一一个没有重复的算法:
一是看到的最优解对自身进行^运算。
二是自己思考出的通过HashMap对每个数进行个数统计,如果为1则得出。
同理得出此处交集的运算规则,统计每一个数的出现次数,如果为2,则是交集。
以下为代码实现:
int[] a = {1, 2, 3, 4, 5}; int[] b = {2, 3, 5, 6, 7};
HashMap<Integer, Integer> hashMap = new HashMap(16); for (int i = 0; i < a.length; i++) { if (hashMap.get(a[i]) != null) {
hashMap.put(a[i], hashMap.get(a[i]) + 1);
} else {
hashMap.put(a[i], 1);
}
} for (int i = 0; i < b.length; i++) { if (hashMap.get(b[i]) != null) {
hashMap.put(b[i], hashMap.get(b[i]) + 1);
} else {
hashMap.put(b[i], 1);
}
} for (int i : hashMap.keySet()) { if (hashMap.get(i).equals(2)) {
System.out.print(i+" ");
}
}
}
‘柒’ 有什么好的算法求两个数组的交集
首先对较短的一个数组(设长度为a)建立平衡二叉搜索树(需要alog2(a)的时间)。
然后对另一个数组(设长度为b)的每一个元素,在a的搜索树中查找(需要blog2(a)的时间)。
所以总共需要alog2(a)+blog2(a)的时间。
而2楼的算法需要ab的时间。
当b>a>4时,
a>2log2(a)
log2(a)<a-log2(a)
log2(a)/(a-log2(a))<1
alog2(a)/(a-log2(a))<a
又b>a
alog2(a)/(a-log2(a))<b
alog2(a)<ab-blog2(a)
alog2(a)+blog2(a)<ab
所以b>a>4时我的算法比2楼快。
当然,还有常数项的问题,上面的“快”只是渐进意义上的快。
‘捌’ 如何求两个数组的交集
定义另外一个数组,做一个循环,把两个数组的元素从下标为0的开始比较,又相等的就存到第三个数组中,一直到某一个数组的元素全部遍历完以后。第三个数组中即为这两个数组的交集。
‘玖’ 如何计算两个有序整型数组的交集
例如,两个含有n个元素的有序(非降序)整形数组a和b(数组a和b中都没有重复元素),求出其共同元素。
a[]={0,1,2,3,4};
B[]={1,3,5,7,9};
那么它们的交集为{1,3}。
计算数组交集可以采用很多种方法,但数组的相对大小一般会影响算法的效率,所以需要根据两个数组的相对大小来确定采用的方法。
(1)对于两个数组长度相当的情况,一般可以采取以下3种方法。
方法一:采用二路归并来遍历两个数组。(这个名字好霸气,有木有武功招数的赶脚)
设两个数组分别为array1[n1]和array2[n2],分别以i、j从头开始遍历两个数组。在遍历过程中,如果当前遍历位置的array1[i]与array2[j]相等,则此数为两个数组的交集,记录到随便array1或array2中,并继续向后遍历array1和array2.如果array1[i]>array2[j],则需继续向后遍历array2.如果array1[i]小于array2[j],则需要继续向后遍历array1,直到有一个数组结束遍历即停止。总的来说,就是谁落后了,谁的下标就自增去吧。
代码如下:
#include "stdafx.h"
#include <stdio.h>
void mixed(int array1[], int n1, int array2[], int n2)
{
int i = 0, j = 0, k = 0;
while (i < n1&&j < n2)
{
if (array1[i] == array2[j])
{
array1[k] = array1[i];
printf("%d\n", array1[k]);
i++;
j++;
k++;
}
else if (array1[i]>array2[j])
{
j++;
}
else if (array1[i] < array2[j])
{
i++;
}
}
}
void main()
{
int a[] = { 0, 1, 2, 3, 4 };
int b[] = { 1, 3, 5, 7, 9 };
mixed(a, 5, b, 5);
getchar();
}
效果如图:
方法二:顺序遍历两个数组,将数组元素存放到哈希表中,同时对同级的数组元素进行计数。如果为2,则为两者的交集元素。
方法三:遍历两个数组中任意一个数组,将遍历得到的元素存放到哈希表,然后遍历另外一个数组,同时对建立的哈希表进行查询,如果存在,则为交集元素。
(2)对于两个数组长度相差悬殊的情况,如数组a的长度远远大于数组b的长度,则可以采用下面几种方法。
方法一:依次遍历长度小的数组,将遍历得到的数组元素在长数组中进行二分查找。具体而言,设两个指向两个数组为元素的指针,取较小的那个数在另一个数组中二分查找,找到,则存在一个交集,并且将该目标数组的指针指向该位置前一个位置。如果没有找到,同样可以找到一个位置,使得目标数组中在该位置后的数肯定不在另一个数组中存在,直接移动该目标数组的指针指向该位置的前一个位置,再循环找,直到一个数组为空为止。因为两个数组中都可能出现重复的数,因此二分查找时,当找到一个相同的数x时,其下标为i,那么下一个二分查找的下界变为i+1,避免x重复使用。
方法二:采用与方法一类似的方法,但是每次查找在前一次查找的基础上进行,这样可以大大缩小查找表的长度。
方法三:采用与方法二类似的方法,但是遍历长度小的数组的方式有所不同,从数组头部和尾部同时开始遍历,这样可以进一步缩小查找表的长度。
‘拾’ 如何取两个已排序数组的交集
例如,两个含有n个元素的有序(非降序)整形数组a和b(数组a和b中都没有重复元素),求出其共同元素。
a[]={0,1,2,3,4};
B[]={1,3,5,7,9};
那么它们的交集为{1,3}。
计算数组交集可以采用很多种方法,但数组的相对大小一般会影响算法的效率,所以需要根据两个数组的相对大小来确定采用的方法。
(1)对于两个数组长度相当的情况,一般可以采取以下3种方法。
方法一:采用二路归并来遍历两个数组。(这个名字好霸气,有木有武功招数的赶脚)
设两个数组分别为array1[n1]和array2[n2],分别以i、j从头开始遍历两个数组。在遍历过程中,如果当前遍历位置的array1[i]与array2[j]相等,则此数为两个数组的交集,记录到随便array1或array2中,并继续向后遍历array1和array2.如果array1[i]>array2[j],则需继续向后遍历array2.如果array1[i]小于array2[j],则需要继续向后遍历array1,直到有一个数组结束遍历即停止。总的来说,就是谁落后了,谁的下标就自增去吧。
代码如下:
#include "stdafx.h"
#include <stdio.h>
void mixed(int array1[], int n1, int array2[], int n2)
{
int i = 0, j = 0, k = 0;
while (i < n1&&j < n2)
{
if (array1[i] == array2[j])
{
array1[k] = array1[i];
printf("%d\n", array1[k]);
i++;
j++;
k++;
}
else if (array1[i]>array2[j])
{
j++;
}
else if (array1[i] < array2[j])
{
i++;
}
}
}
void main()
{
int a[] = { 0, 1, 2, 3, 4 };
int b[] = { 1, 3, 5, 7, 9 };
mixed(a, 5, b, 5);
getchar();
}