求两个数组的交集、并集和差集算法分析与实现

一、数组内数据无序且可以重复

 

本文采用一种交换的方式来求出两个数组的并集,交集和差集,这种算法运算速度较快,内存消耗空间较少,是一个值得学习的好方法,另外,作者提醒您,重要的不是算法本身,而是该算法会开拓我们的思维空间,要注意对问题的多思考。

 

算法概述:

两个任意元素的数组,比较出两个数组中相同的元素和不同的元素。

 

元素划分:

计算过程中,两个数组内部元素的划分:

 

 
 

算法流程:

从数组1的尚未比较的元素中拿出第一个元素array1(i),用array1(i)与array2(j)进行比较(其中j>i且j<array2的长度),可能出现下面两种情况,

1.  数组2中找到了一个与array1(i)相等的元素,则将array2(j)与array2(i)进行交换,i加一,进行下次迭代

2.  数组2直到结尾也没找到与array1(i)相等的元素,则将array1(i)与尚未进行比较的最后一个元素array1(k)进行交换,i不加一,进行下次迭代。

算法实现代码:

#include <stdio.h>
 
bool join(const int *arrA, const int lenA, const int *arrB, const int lenB, \
          int *arrDst, int *len)
{
    int i = 0, j = 0, nCount = 0;
 
    while (i < lenA && j < lenB) 
    {
        if (arrA[i] == arrB[j])
        {
            //两个相等即交集
            arrDst[nCount ++] = arrA[i];
            i ++;
            j ++;
        } 
        else if(arrA[i] > arrB[j])
        {
            //移动小的数组index
            j ++;
 
        }
        else 
        {
            //移动小的数组index
            i ++;
        }
    }
 
    //交集的真实数目
    *len = nCount;
    
    return true;
}
 
bool merge(const int *arrA, const int lenA, const int *arrB, const int lenB, \
           int *arrDst, int *len)
{
    int i = 0, j = 0, nCount = 0;
 
    while (i < lenA && j < lenB) 
    {
        if (arrA[i] < arrB[j])
        {            
            arrDst[nCount ++] = arrA[i];
            //移动小的数组index
            i ++;        
        } 
        else if(arrA[i] > arrB[j])
        {        
            arrDst[nCount ++] = arrB[j];
            //移动小的数组index
            j ++;
 
        }
        else 
        {
            arrDst[nCount ++] = arrA[i];
            //相等只取一个
            i ++;
            j ++;
        }
    }
 
    while(i < lenA) 
    {
        arrDst[nCount ++] = arrA[i ++];
    } 
    while(j < lenB) 
    {
        arrDst[nCount ++] = arrB[j ++];
    } 
 
    //并集的真实数目
    *len = nCount;
    
    return true;
}
 
void print(const int *arr, const int len)
{
    int i;
    printf("Data : ");
    for(i = 0; i < len; ++ i)
    {
        printf("%2d ", arr[i]);
    }
    printf("\n\n");
}
 
void main()
{
    int a[] = {0,1,3,5,7,8,9,10,11};
    int b[] = {1,2,3,4,5,6,7,8,9,10,13,15,19};
    int sizeA = sizeof(a) / sizeof(a[0]);
    int sizeB = sizeof(b) / sizeof(b[0]);
    
 
    int i = 0;
    int j = 0;
    int len;
 
    int *c = new int [sizeA + sizeB];
 
    printf("数组A和B的交集:\n");
    join(a, sizeA, b, sizeB, c, &len);
    print(c, len);
 
    printf("数组A和B的并集:\n");
    merge(a, sizeA, b, sizeB, c, &len);
    print(c, len);
 
    delete []c;
 
    printf("\n\n");
}

三、3个已经排序的整数数列,找到common elements。

1)三个index指向三个数列开始,比较三者的值,若相等则找到一个。若有两个元素相等且较大,则较小的一个index+;其他情况,较小的两个index++。时间复杂度O(N),N小于等于最长的数列长度。


2)先找两个数组的common element,过程和归并排序类似,然后看这个结果是否出现在数组三中即可,用二分查找。时间复杂度O(n),空间复杂度为O(1),如果是N个数组,则可以采用败者树。(新学习的,呵呵)

以下是 C 语言实现代码,包括交集并集差集(相对差和对称差)的计算和输出。 ```c #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 // 定义集合的最大元素个数 int main() { int setA[MAX_SIZE], setB[MAX_SIZE]; // 声明两个集合数组 int nA, nB; // 分别表示集合A和B的元素个数 int i, j; // 循环计数器 // 输入集合A printf("请输入集合A的元素个数(不超过%d个):", MAX_SIZE); scanf("%d", &nA); printf("请输入集合A的%d个元素:", nA); for (i = 0; i < nA; i++) { scanf("%d", &setA[i]); } // 输入集合B printf("请输入集合B的元素个数(不超过%d个):", MAX_SIZE); scanf("%d", &nB); printf("请输入集合B的%d个元素:", nB); for (i = 0; i < nB; i++) { scanf("%d", &setB[i]); } // 计算交集并输出 printf("集合A和集合B的交集为:"); for (i = 0; i < nA; i++) { for (j = 0; j < nB; j++) { if (setA[i] == setB[j]) { printf("%d ", setA[i]); break; } } } printf("\n"); // 计算并集并输出 printf("集合A和集合B的并集为:"); for (i = 0; i < nA; i++) { printf("%d ", setA[i]); } for (i = 0; i < nB; i++) { int flag = 1; for (j = 0; j < nA; j++) { if (setB[i] == setA[j]) { flag = 0; break; } } if (flag) { printf("%d ", setB[i]); } } printf("\n"); // 计算相对差并输出 printf("集合A和集合B的相对差(A-B)为:"); for (i = 0; i < nA; i++) { int flag = 1; for (j = 0; j < nB; j++) { if (setA[i] == setB[j]) { flag = 0; break; } } if (flag) { printf("%d ", setA[i]); } } printf("\n"); printf("集合B和集合A的相对差(B-A)为:"); for (i = 0; i < nB; i++) { int flag = 1; for (j = 0; j < nA; j++) { if (setB[i] == setA[j]) { flag = 0; break; } } if (flag) { printf("%d ", setB[i]); } } printf("\n"); // 计算对称差并输出 printf("集合A和集合B的对称差为:"); for (i = 0; i < nA; i++) { int flag = 1; for (j = 0; j < nB; j++) { if (setA[i] == setB[j]) { flag = 0; break; } } if (flag) { printf("%d ", setA[i]); } } for (i = 0; i < nB; i++) { int flag = 1; for (j = 0; j < nA; j++) { if (setB[i] == setA[j]) { flag = 0; break; } } if (flag) { printf("%d ", setB[i]); } } printf("\n"); return 0; } ``` 程序运行时,先要依次输入两个集合的元素个数和元素,然后程序就会计算并输出它们的交集并集、相对差和对称差,每个集合中的元素都会被输出一次,没有重复或遗漏。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值