【问题标题】:The most efficient way to find mode in an array?在数组中查找模式的最有效方法?
【发布时间】:2018-08-12 21:57:11
【问题描述】:

最近我正在尝试使用 C 在一组数字中找到模式。 我的代码在集合很小的情况下可以做得很好。

这是我的代码:

int frequency[10001]; //This array stores the frequency of a number that between 0 to 10000
int main()
{
    int x[10]={1,6,5,99,1,12,50,50,244,50};
    int highest = 0;
    int i,j,k;

    for(i=0;i<10;i++)
    {
        frequency[x[i]]++;
        if(frequency[x[i]]>highest)
            highest = frequency[x[i]];
    }

    printf("The mode in the array : ");
    for(i=0;i<=10001;i++)
        if(frequency[i]==highest)
            printf("%d ",i);
    return 0;
}

后来,我发现如果有大量的数字,我的方法会非常慢。此外,如果数字小于 0 或大于 10000,我的程序将无法运行,除非我增加“频率”数组的大小。

因此,我想知道有什么方法可以更有效地找到数组中的模式?谢谢。

【问题讨论】:

  • 小心:for(i=0;i&lt;=10001;i++) => for(i=0;i&lt;10001;i++)
  • 我会给你一个提示,获取数组中的最大数,然后像这样定义数组频率[max_number]
  • 为什么不存储highest 时也存储indexhighest 所在的位置,这样可以节省第二遍。将此与上面给出的提示相结合以找到最大值。也可以将 unordered_map 与 save the highest 策略一起使用。
  • C 还是 C++?选择一个。
  • 点击以下链接获取答案:stackoverflow.com/questions/19920542/…

标签: c++ c arrays mode


【解决方案1】:

使用hash table。 (即 unordered_map 通常是这样实现的)。

您将问题标记为 C++,因此您将获得一些 C++ 示例代码。用 C 语言实现哈希表是您自己的事。这不是一个糟糕的学习练习。

int x[10]={1,6,5,99,1,12,50,50,244,50};
std::unordered_map<int, int> table; // map of items in "x" to the number of times observed.
for (int i = 0; i < 10; i++)
{
     table[x[i]]++;
}

int mode = 0;
int mode_freq = 0;
for (auto itor = table.begin(); itor != table.end(); itor++)
{
    if (itor->second > mode_freq)
    {
        mode = itor->first;
        mode_freq = itor->second;
    }
}
std::cout << "The mode in the array is " << mode << std::endl;

【讨论】:

  • 我们如何知道std::unordered_map 默认分配了多少项目?或者[] 运营商会分配新的吗?看起来很奇怪,STL 通常不会那样做。你确定这不是错误?
  • @Lundin operator[] 默认构造一个元素以在传递新键时返回。只有mapunordered_mapoperator[](key_type),而且它们的行为都是这样的
  • @Lundin 这就是如果您将用户定义的对象作为值传递给 unordered_map 并且您没有默认 ctor 编译器会抱怨的原因。
  • 您可以用 std::max_element 和自定义比较替换第二个循环 auto mode_it = std::max_element(table.begin(), table.end(), [](auto lhs, auto rhs) { return lhs.second &lt; rhs.second; });,但这一切仅适用于 OP 需要 C++ 答案时
  • @Lundin 序列容器的行为与关联容器不同,是的
【解决方案2】:

您可以简单地对数组进行排序(man qsort),然后搜索相同数字的最长序列。 问题是:当两个数字同样出现在数组中的最高频率时,你的行为如何?

【讨论】:

  • 确实是统计分析中的标准方法来查找众数、中值和百分位数...
【解决方案3】:

我认为您的问题过于笼统,无法得到明确的答案:

  • “最高效”是一个相当大的要求,我想您会对任何“更”高效的解决方案感兴趣:)。
  • 以什么方式更高效?更快的执行时间?更少的内存使用?更好的代码?

首先我会这样写这篇小文章:

static const size_t NUM_FREQ=1000;

int main()
{
    vector< unsigned int > frequency(NUM_FREQ);
    vector< unsigned int > samples[10]={1,6,5,99,1,12,50,50,244,50};
    int highest = 0;
    int i,j,k;

    for ( size_t i = 0; i < samples.size(); i++ )
    {
    assert( samples[i] < NUM_FREQ && "value in samples is bigger than expected" ); 
        frequency[ samples[ i ] ]++;
        if( frequency[ samples[ i ] ] > highest )
            highest = frequency[ samples[ i ] ];
    }

    printf("The mode in the array : ");
    for ( size_t i = 0; i < frequency.size(); i++ )
        if ( frequency[ i ] == highest )
            printf("%d ",i);
    return EXIT_SUCCESS;
}

在我更改的所有不良做法中,您应该更加小心的是依赖普通类型的隐式初始化。

现在,有很多事情可能有问题,也可能没有问题:

  • 最明显的是,你不需要循环两次,只需使用一个额外的变量来记住最高频率的位置并完全摆脱第二次循环。

  • 在您的示例中,样本很少,使用如此大的频率阵列是浪费空间。如果样本的大小小于 NUM_FREQ 我会简单地使用对向量。我假设您的实际应用程序使用的示例数组大于频率数组。

  • 最后,排序或散列可以加快速度,但这在很大程度上取决于频率数据在应用程序的其余部分中的使用方式(但除了这个简单的代码之外,您没有展示任何内容)。

【讨论】:

    【解决方案4】:
    • 您找不到数的出现。您只能找到数字的出现。
    • 不要使用frequency[10001] 的数组,而是使用MAPS in C++

    现在让我修改你的代码。使用地图而不是数组。

    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
      int x[10]={1,6,5,99,1,12,50,50,244,50};
      map <int, int> freq;//using map here instead of frequency array
      int highiest=0;
      for(int i=0;i<10;i++)
      {
        freq[x[i]]+=1;//indexing
      }
      for(int i=0;i<sizeof(freq);i++)
      {
        if(freq[i]>highiest)//finding the highiest occurancy of a number.
        highiest=i;
      }
      cout<<highiest<<endl;//printing the highiest occurancy number
    }
    

    【讨论】:

      猜你喜欢
      • 2011-10-08
      • 1970-01-01
      • 2022-06-10
      • 2014-01-31
      • 2015-05-22
      • 1970-01-01
      • 1970-01-01
      • 2015-08-09
      • 1970-01-01
      相关资源
      最近更新 更多