两个排序数组的交集

时间:2010-03-08 08:52:01

标签: c++ algorithm arrays sorting

给出两个排序的数组:AB。数组A的大小为La,数组B的大小为Lb。如何找到AB的交集?

如果LaLb大得多,那么交叉点查找算法会有什么不同吗?

8 个答案:

答案 0 :(得分:48)

因为这看起来像一个HW ...我会给你算法:

Let arr1,arr2 be the two sorted arrays of length La and Lb.
Let i be index into the array arr1.
Let j be index into the array arr2.
Initialize i and j to 0.

while(i < La and j < Lb) do

    if(arr1[i] == arr2[j]) { // found a common element.
        print arr[i] // print it.
        increment i // move on.
        increment j
    }
    else if(arr1[i] > arr2[j])
        increment j // don't change i, move j.
    else
        increment i // don't change j, move i.
end while

答案 1 :(得分:18)

我现在一直在努力解决同样的问题,到目前为止我来了:

  1. 线性匹配,在最坏的情况下会产生O(m + n)。你基本上保留两个指针(A和B),每个指针指向每个数组的开头。然后前进指向较小值的指针,直到到达一个数组的末尾,这表示没有交集。如果在任何时候你有* A == * B - 这是你的交叉点。

  2. 二进制匹配。在最坏的情况下产生~O(n * log(m))。您基本上选择较小的数组并在较小数组的所有元素的较大数组中执行二进制搜索。如果你想要更加花哨,你甚至可以使用二进制搜索失败的最后位置,并将其用作下一个二进制搜索的起点。这样你可以略微改善最坏情况,但对于某些套装,它可能会创造奇迹:)

  3. 双重二进制匹配。它是常规二进制匹配的变体。基本上你从较小的数组中间获取元素并在更大的数组中进行二进制搜索。如果你什么也没找到,那么你将较小的数组切成两半(是的,你可以抛弃你已经使用的元素)并将更大的数组切成两半(使用二进制搜索失败点)。然后重复每一对。结果优于O(n * log(m)),但我懒得计算它们是什么。

  4. 这是最基本的两个。两者都有优点。线性更容易实现。二进制可以说更快(尽管有很多情况下线性匹配将胜过二进制)。

    如果有人比我更了解我想听的话。匹配数组是我现在所做的。

    P.S。不要引用我的术语“线性匹配”和“二进制匹配”,因为我自己制作它们并且它可能已经有了它的名字。

答案 2 :(得分:9)

set_intersection用作here。通常的实现类似于merge-sort算法的合并部分。

答案 3 :(得分:1)

void Intersect()
{
    int la, lb;
    la = 5;
    lb = 100;
    int A[5];
    int i, j, k;
    i = j = k = 0;
    for (; i < 5; ++i)
        A[i] = i + 1;
    int B[100];
    for (; j < 100; ++j)
        B[j] = j + 2;
    int newSize = la < lb ? la : lb;
    int* C = new int[newSize];
    i = j = 0;
    for (; k < lb && i < la && j < lb; ++k)
    {
        if (A[i] < B[j])
            i++;
        else if (A[i] > B[j])
            j++;
        else
        {
            C[k] = A[i];
            i++;
            j++;
        }
    }
    for (k = 0; k < newSize; ++k)
        cout << C[k] << NEWLINE;
}

答案 4 :(得分:1)

这是Java语言,但是可以满足您的要求。它实现了Nazar的答案(“双重”二进制搜索)中提到的变体3,应该是最快的解决方案。我很确定这能击败任何一种“疾驰”的方法。奔腾只是在浪费时间,因为我们从上而下的二进制搜索中跳了一步。

在这里应用哪个复杂度类尚不清楚。我们在较长的数组中执行二进制搜索,但是永远不会两次查看相同的元素,因此我们绝对在O(m + n)之内。

此代码已经过随机数据的全面测试。

import java.util.Arrays;

// main function. may return null when result is empty
static int[] intersectSortedIntArrays(int[] a, int[] b) {
  return intersectSortedIntArrays(a, b, null);
}

// no (intermediate) waste version: reuse buffer
static int[] intersectSortedIntArrays(int[] a, int[] b, IntBuffer buf) {
  int i = 0, j = 0, la = lIntArray(a), lb = lIntArray(b);
  
  // swap if a is longer than b
  if (la > lb) {
    int[] temp = a; a = b; b = temp;
    int temp2 = la; la = lb; lb = temp2;
  }
  
  // special case zero elements
  if (la == 0) return null;
  
  // special case one element
  if (la == 1)
    return Arrays.binarySearch(b, a[0]) >= 0 ? a : null;
    
  if (buf == null) buf = new IntBuffer(); else buf.reset();
  intersectSortedIntArrays_recurse(a, b, buf, 0, la, 0, lb);
  return buf.toArray();
}

static void intersectSortedIntArrays_recurse(int[] a, int[] b, IntBuffer buf, int aFrom, int aTo, int bFrom, int bTo) {
  if (aFrom >= aTo || bFrom >= bTo) return; // nothing to do
  
  // start in the middle of a, search this element in b
  int i = (aFrom+aTo)/2;
  int x = a[i];
  int j = Arrays.binarySearch(b, bFrom, bTo, x);

  if (j >= 0) {
    // element found
    intersectSortedIntArrays_recurse(a, b, buf, aFrom, i, bFrom, j);
    buf.add(x);
    intersectSortedIntArrays_recurse(a, b, buf, i+1, aTo, j+1, bTo);
  } else {
    j = -j-1;
    intersectSortedIntArrays_recurse(a, b, buf, aFrom, i, bFrom, j);
    intersectSortedIntArrays_recurse(a, b, buf, i+1, aTo, j, bTo);
  }
}


static int lIntArray(int[] a) {
  return a == null ? 0 : a.length;
}


static class IntBuffer {
  int[] data;
  int size;
  
  IntBuffer() {}
  IntBuffer(int size) { if (size != 0) data = new int[size]; }
  
  void add(int i) {
    if (size >= lIntArray(data))
      data = resizeIntArray(data, Math.max(1, lIntArray(data)*2));
    data[size++] = i;
  }
  
  int[] toArray() {
    return size == 0 ? null : resizeIntArray(data, size);
  }
  
  void reset() { size = 0; }
}

static int[] resizeIntArray(int[] a, int n) {
  if (n == lIntArray(a)) return a;
  int[] b = new int[n];
  arraycopy(a, 0, b, 0, Math.min(lIntArray(a), n));
  return b;
}

static void arraycopy(Object src, int srcPos, Object dest, int destPos, int n) {
  if (n != 0)
    System.arraycopy(src, srcPos, dest, destPos, n);
}

答案 5 :(得分:0)

让我们考虑两个排序的数组: -

int[] array1 = {1,2,3,4,5,6,7,8};
int[] array2 = {2,4,8};

int i=0, j=0;    //taken two pointers

while循环将一直运行,直到两个指针都达到相应的长度。

while(i<array1.length || j<array2.length){
    if(array1[i] > array2[j])     //if first array element is bigger then increment 2nd pointer
       j++;
    else if(array1[i] < array2[j]) // same checking for second array element
      i++;
    else {                         //if both are equal then print them and increment both pointers
        System.out.print(a1[i]+ " ");

        if(i==a1.length-1 ||j==a2.length-1)   //one additional check for ArrayOutOfBoundsException
            break;
        else{
            i++;
            j++;
        }
    }
}        

输出将是: -

2 4 8

答案 6 :(得分:0)

使用PYTHON非常简单

示例: A = [1,2,3,5,7,9,90] B = [2,4,10,90]

我们在这里输入三行代码

for i in A:
     if(i in B):
        print(i)

输出:2,90

答案 7 :(得分:-1)

 //intersection of two arrays
#include<iostream>
using namespace std;
int main() {

int i=0,j=0,m,n;
int arr1[i],arr2[j];
cout<<"Enter the number of elements in array 1: ";
cin>> m;
cout<<"Enter the number of elements in array 2: ";
cin>>n;
for (i=0;i<m;i++){
    cin>> arr1[i];
}
for(j=0;j<n;j++){
    cin>> arr2[j];
}
for(j=0;j<n;j++){
    for(i=0;i<m;i++) {
        if (arr1[i] == arr2[j]){
        cout<< arr1[i];
        cout << ' ';
        break;
        }
    } 
 }    

 return 0;
 }