【问题标题】:find most occurence element in array查找数组中出现次数最多的元素
【发布时间】:2011-04-17 10:18:59
【问题描述】:

这是一个简单的程序,用于查找数组中最常出现的元素:

#include <cstdlib>
#include <iostream>
#include <vector>

using namespace std;

int main(int argc, char *argv[]) {
    int a[] = {1,2,3,4,4,4,5};
    int n = sizeof(a) / sizeof(int);
    int max = 0;
    int result = 0;
    int *b = new int[n];
    for (int i = 0;  i < n;  i++) {
        b[a[i]] = (b[a[i]] || 0) + 1;
        if (b[a[i]] > max) {
            max = b[a[i]];
            result = a[i];
        }
    }
    cout << result << endl;
    system("PAUSE");
    return EXIT_SUCCESS;
}

但它不起作用;它打印1。为什么?

【问题讨论】:

  • 你能保证数组总是按照你的例子排序吗?或者,你能保证给定元素的所有出现都是连续的吗?如果是这样,则存在具有 O(1) 额外存储空间的更简单、更快的算法。

标签: c++


【解决方案1】:

既然包含了vector anway,为什么不把int *b=new int [n];换成std::vector&lt;int&gt; b(n)呢?这也负责释放内存,你忘了delete[] b

但正如其他人所提到的,如果数组包含大于 n 的元素,您的解决方案将会中断。更好的方法可能是使用映射到 int 来计算元素。这样,您还可以计算不能用作数组索引的元素,例如字符串。

我们也没有理由将自己局限于数组。这是一个通用解决方案,适用于任何小于可比元素类型的任何容器:

#include <algorithm>
#include <iterator>
#include <map>

struct by_second
{
    template <typename Pair>
    bool operator()(const Pair& a, const Pair& b)
    {
        return a.second < b.second;
    }
};


template <typename Fwd>
typename std::map<typename std::iterator_traits<Fwd>::value_type, int>::value_type
most_frequent_element(Fwd begin, Fwd end)
{
    std::map<typename std::iterator_traits<Fwd>::value_type, int> count;

    for (Fwd it = begin; it != end; ++it)
        ++count[*it];

    return *std::max_element(count.begin(), count.end(), by_second());
}

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> test {1, 2, 3, 4, 4, 4, 5};
    std::pair<int, int> x = most_frequent_element(test.begin(), test.end());
    std::cout << x.first << " occured " << x.second << " times";
}

【讨论】:

  • 嗯,您的编辑可能技术上很好,但考虑到问题,我认为您提出的代码过于复杂。提问者仍在学习基础知识,我们暂时不要用模板和迭代器细节来压倒他......
  • @Loïc:但为什么需要它? typedef 引入的名称不总是类型名称吗?
  • @FredOverflow typename 适用于value_type,不适用于map_t。如果省略typename,则map_t::value_type 被视为非类型,然后编译器在解析模板时被授予拒绝by_second&lt;map_t::value_type&gt;,因为by_second 需要类型参数。
  • @Eamon:像这样的任务(嗯,它是计算文本中出现的单词)是我的学生必须做的头几个任务之一。当然,到那时他们只能使用模板,但这很好。手动摆弄内存远比这糟糕。
【解决方案2】:

你还没有初始化你的数组b。你可以这样做:

int *b=new int [n]();
                  ^^

完成后,您可以将频率数组递增为:

b[a[i]]++;

代替

b[a[i]]=(b[a[i]]||0)+1;

您的(b[a[i]]||0)+1 方式适用于Javascript、Perl 等语言,其中未初始化的数组元素将具有称为undefnull 的特殊值。 C++ 没有类似的东西,未初始化的数组将有垃圾

【讨论】:

  • +1 用于简单的解决方案。虽然这个程序仍然很脆弱,如果数组 a 的值像 {1, 600, 765, 2000, 600}
【解决方案3】:

您需要将数组 b 初始化为零。

 b[a[i]]||0

行不通,你不知道b原来是什么。

短代码:

int main(int argc, char *argv[])
{
    int a[]={1,2,3,4,4,4,5};
    int n = sizeof(a)/sizeof(int );
    int *b=new int [n];
    fill_n(b,n,0); // Put n times 0 in b

    int val=0; // Value that is the most frequent
    for (int i=0;i<n;i++)
        if( ++b[a[i]] >= b[val])
            val = a[i];

    cout<<val<<endl;
    delete[] b;
    return 0;
}

注意: 您的代码(我的也是)只有在最大值小于数组 a 中值的数量时才能工作。

如果不是这种情况并且最大值远大于元素的数量,您可能需要对数组进行排序,然后在线性时间(和恒定空间)中搜索最大值。

【讨论】:

    【解决方案4】:

    这里,O(n) 时间,O(1) 空间通用解,适用于排序范围。

    #include <iostream>
    
    template <class ForwardIterator>
    ForwardIterator
    most_common(ForwardIterator first, ForwardIterator last) {
      /** Find the most common element in the [first, last) range.
    
          O(n) in time; O(1) in space.
    
          [first, last) must be valid sorted range.
          Elements must be equality comparable.
      */
      ForwardIterator it(first), max_it(first);
      size_t count = 0, max_count = 0;
      for ( ; first != last; ++first) {
        if (*it == *first) 
          count++;
        else {
          it = first;
          count = 1;
        }      
        if (count > max_count) {
          max_count = count;
          max_it = it;
        }
      }  
      return max_it;
    }    
    int main() {
      int a[] = {1, 2, 3, 4, 4, 4, 5};
      const size_t len = sizeof(a) / sizeof(*a);
      std::cout << *most_common(a, a + len) << std::endl;
    }
    

    【讨论】:

      【解决方案5】:

      利用事实图的实现被排序。

      #include <iostream>
      #include <vector>
      #include <map>
      
      using namespace std;
      
      template<class T> pair<T, int> getSecondMostOccurance(vector<T> & v) {
          map<T, int> m;
      
          for ( int i = 0; i < v.size(); ++i ) {
              m[ v[i] ]++;
          }
          return *m.end();
      }
      
      int main() {
          int arr[] = {1, 4, 5, 4, 5, 4};
          pair<int, int> p = getSecondMostOccurance(vector<int>(arr, arr+7));
          cout << "element: " << p.first << " count: " << p.second << endl;
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-05-01
        • 2020-07-22
        • 1970-01-01
        • 2011-04-29
        • 1970-01-01
        • 2019-10-27
        • 2010-11-06
        相关资源
        最近更新 更多