【问题标题】:How does this implementation of array intersection work?这种数组交集的实现是如何工作的?
【发布时间】:2020-03-13 06:59:03
【问题描述】:

此代码查找两个未排序数组的交集。

void intersection(int arr1[],int m,int arr2[],int n)    //where m=size of arr1 and n=size of arr2
{
  map<int,int>mapp;

  for(int i=0;i<m;i++)
     mapp[arr1[i]]++;    //3

  for(int i=0;i<n;i++)
  {
    if(mapp[arr2[i]] >0)    //4
    {
      mapp[arr2[i]]--;     //5
      cout<<arr2[i] <<endl;
    } 
  }
}

它实际上在第 3、4 和 5 行尝试做什么?

【问题讨论】:

  • 所有这三个都使用存储在各自数组中的值作为将值关联到计数器的映射的键。请注意,如果m &lt; n 成立,则此代码是未定义行为 的潜在路径,因为在//4 中使用了arr1[i]
  • 这些行的作用无关紧要。之前的评论稍微提到了一点,但是根据参数的描述,以及这个函数的目的,很明显,显示的逻辑存在根本性的缺陷,并且无法产生正确的结果。

标签: c++ arrays algorithm stl intersection


【解决方案1】:

考虑一个数组 arr1[] = {2, 3, 2, 3, 4, 3}。

使用这种代码后,

map<int,int>mapp;

  for(int i=0;i<m;i++)
  mapp[arr1[i]]++; //3

mapp会像follow一样被存储,

mapp[2] = 2

mapp[3] = 3

mapp[4] = 1

这意味着一个独特的元素在 arr1 中重复了多少次。

现在回到主要部分。两个数组的交集是指两个数组中都有的元素。

mapp[arr2[i]] >0 //4

这一行确保 arr2[i] 元素在 arr1 中至少有一次。如果 mapp[arr2[i]] == 0 这意味着它不在 arr1 中(混淆?)。为什么我说 arr1。因为我们通过arr1迭代了mapp。记住您评论为“3”的内容。

for(int i=0;i<m;i++)
  mapp[arr1[i]]++;

为您的 5...

让我们看一个例子。

对于 arr2 中的每个元素,如果它也在 arr1 中,则将其交叉。其实就是交集后的数组元素。

arr1 = {2 , 2 , 2 , 2 , 3 , 5}

arr2 = {2 , 2 , 3 , 4}

在路口 {2, 2, 3} 之后

穿越的东西其实是,

mapp[arr2[i]]--; //5

用这种方式演示太难了。但我尽力了:)

【讨论】:

    【解决方案2】:

    该算法使用std::map 将数组中存储的每个值与找到的出现次数相关联。地图是有序的。

    第一次迭代只计算第一个数组中存在的值。所以如果第一个数组包含 3,2,3 和 5,语句//3 将更新映射以获得以下关联:

    key   counter value
    2   ->   1
    3   ->   2
    5   ->   1
    

    第二次迭代通过第二个数组。不在第一个数组中的数字将被忽略(因为映射值最多为 0,这就是 //4 的目的)。

    对于匹配的数字,它会减少地图中不匹配的值的数量并显示该值。

    因此,如果第二个数组包含 1、3、5、3、3,则迭代将如下所示

    1 -> mapp[1] is 0 so this number is ignored (indeed it was not in the first array)
    3 -> mapp[3] is 2 so the count is decreased to 1 and 3 is printed.  
    5 -> MAPP[5] is 1 so the count is decreased to 0 and 5 is printed, 
    3 -> mapp[3] is 1 (see above), so the cound is decreased to 0 and 3 is printed
    3 -> mapp[3] is 0 (see above), so either 3 was never found in the first array, or all the count occurences were already matched.  So nothing is done.  
    

    该算法将按照第二个数组中数字的出现顺序打印结果。不幸的是,它为arr2 中尚未在arr1 中的所有元素填充了mapp,因为使用[] 访问映射中的键这一事实将为它创建一个0 值.使用.find() 检查地图中是否存在值将是一种更好的方法。

    【讨论】:

      【解决方案3】:

      3:这可以写得更清楚一点:

      for (int i = 0; i < m; i++) {
          int value1 = arr1[i];
          int currentCount = mapp[value1];
          mapp[value1] = currentCount + 1;
      }
      

      这很容易解释。将arr1 的所有值作为键存储在mapp 中,并在每次满足相同值时将其值加1。这里我们假设任何值都应该总是从 0 开始。

      4:再一次,我们将重写它以使其更加清晰:

      for (int i = 0; i < n; i++) {
          int value2 = arr2[i];
          int currentCount = mapp[value2];
          if (currentCount > 0) {
              mapp[value2] = currentCount - 1;
              cout << value2 << endl;
          }
      }
      

      if-语句中,我们尝试查找mapp 中已经存在的值。 再次假设默认值为 0:我们将跳过第一个数组中未找到的任何值。 如果找到,它的计数将大于 0,我们继续在 if 内。

      5:前面的例子包含重写

      所以我们只在arr1arr2 中存在密钥时才输入if。 如果是这种情况,我们只需将计数器减 1,这样每次值都在两个数组中时,它只会显示一次。

      【讨论】:

        猜你喜欢
        • 2014-12-18
        • 2016-05-14
        • 2011-05-30
        • 1970-01-01
        • 2011-12-15
        • 1970-01-01
        • 2015-01-11
        • 2013-04-13
        • 1970-01-01
        相关资源
        最近更新 更多