在C++中查找整数向量的众数

9

我正在尝试编写一个基础程序来学习C++的基础知识,我正在生成100个0到100之间的随机数并将它们存储在一个向量中,然后显示向量的总和、平均值、中位数、众数、最高值和最低值。除了众数之外,我已经完成了所有其他内容。以下是我目前的代码。

int modeFunction()
     {
         numMode = 0;
         count = 0;
         for (int n = 0; n < 100; n++)
         {
             for (int y = 0; y < 100; y++)
             {
                 if (numVector.at(y) == numVector.at(n))
                {
                    numMode = numVector.at(y);
                    count++;
                }
             }

         }
         return numMode;
     }

之后我卡住了,因为在我的脑海中应该可以工作,但实际上并没有。它只输出最后一个数字,通常是100。任何帮助都将不胜感激。


1
如果myVector是一个std::vector<int>(至少看起来是这样),你可以像数组一样对其进行索引:myVector[y]myVector[n]将产生与myVector.at版本相同的结果,但我认为它看起来更好。 :) - Xeo
2
@Xeo:区别在于当索引超出范围时,at有定义的行为。可以说operator[]是一种微观优化,尽管正如你所说,它也是一种风格上的差异。 - Steve Jessop
@Steve:啊,谢谢你的提示。:)我还没有尝试过at,但是对于超出范围的访问,普通数组也有未定义的行为,尽管当你需要它时,拥有定义的行为肯定是很好的。:) - Xeo
@Xeo:说实话,我从来不使用 at。我偶尔会想是否应该使用它,但实际上我从不编写当索引超出范围时会抛出异常的代码,因此它只是作为调试辅助工具,它“应该”永远不会发生。尽管称其为微优化,但这是相当多余的代码,所以最终如果我需要边界检查,我就切换到Python;-) - Steve Jessop
8个回答

11

з”ұдәҺжүҖжңүзҡ„еҖјйғҪеңЁ0еҲ°100д№Ӣй—ҙпјҢдҪ еҸҜд»ҘйҖҡиҝҮзӣҙж–№еӣҫй«ҳж•Ҳең°жүҫеҲ°дј—ж•°пјҡ

std::vector<int> histogram(101,0);
for( int i=0; i<100; ++i )
  ++histogram[ numVector[i] ];
return std::max_element( histogram.begin(), histogram.end() ) - histogram.begin();

这对于[0,100]范围之外的值不起作用吗?(这应该适用于任何对称直方图,不是吗?) - 10GeV

4

由于众数是出现频率最高的数字,因此除非新数字的计数大于numMode的计数,否则不应更改numMode

编辑:为了澄清,您需要为当前元素和您认为是模式的当前数字保留单独的计数。理想情况下,将newMode设置为第一个元素是一个好方法。

此外,模式不一定唯一(即“1 1 2 2”)。如果您关心这一点,可以记住这一点。

newMode = element[0]
modeCount = # of occurrence of newMode

for ( i-th element from [1 to end] ) {
   tmpCount = # of occurrence of element[i]
   if tmpCount > modeCount {
     newMode = element[i]
     modeCount = tmpCount
   }
}

我是那个点了踩的人。我这么做是因为这个答案不完整,它假设值出现次数的数组已知,然而这个数组在这里是最重要的。 - LRDPRDX

3

如果元素数量较小,bmcnett的方法效果很好。但如果有大量元素,并且所有元素的值都在一个小范围内,则使用map / hashmap可以很好地解决问题。类似以下内容:

typedef std::pair<int, int> mode_pair;

struct mode_predicate
{
  bool operator()(mode_pair const& lhs, mode_pair const& rhs)
  {
    return lhs.second < rhs.second;
  }
};

int modeFunction()
{
  std::map<int, int> mode_map;
  for (int n = 0; n < 100; n++)
    mode_map[numVector[n]]++;
  mode_predicate mp;
  return std::max_element(mode_map.begin(), mode_map.end(), mp)->first;
}

1

替代方案。注意:未经测试。

int mode1(const std::vector<int>& values)
{   
    int old_mode = 0;
    int old_count = 0;
    for(size_t n=0; n < values.size(); ++n) 
    {
        int mode = values[n];
        int count = std::count(values.begin()+n+1, values.end(), mode);

        if(count > old_count) 
        {
            old_mode = mode;
            old_count = count;
        }
    }
    return old_mode;
}

int mode2(const std::vector<int>& values)
{   
    return std::max_element(values.begin(), values.end(), [](int value)
    {
        return std::count(values.begin(), values.end(), value);
    });
}

我认为在 mode1() 中,你应该将 count + 1old_count 进行比较,因为你从所计数的值的位置之后的第一个位置开始计数:也就是说,你必须将初始值加上 count - LRDPRDX
此外,我认为将具有搜索属性的值分配为“0”并不是一个好的做法。最好使用第一个元素来代替。 - LRDPRDX

1

你的算法有误 - 它输出数组中的最后一个数字,因为它只能做到这一点。每当索引y处的数字与索引n处的数字匹配时,您都会覆盖先前n的结果。由于您使用相同的循环条件,所以对于每个可能的n值,yn在嵌套循环的至少一个点上始终相同 - 您将始终得到numModenumVector.at(99)

您需要更改算法以保存沿途每个n索引的计数(或者至少是哪个n索引具有最大的count),以便在n循环结束时可以知道发生了最多次的条目。


0

Mode 意味着具有最高频率的数字。逻辑应该是 -

//Start of function

int mode = 0, globalCount = 0 ;  
// Start of outer for loop
for i = 0 to length - 1    
   int localCount = 0   

  // Start of inner for loop  
  for j = 0 to length - 1      
     if vec[i] == vec[j]    
     ++localCount    
 // End of Inner for loop 

 if ( localCount > globalCount )  
     globalCount = localCount  
     mode = vec[i]  
// End of outer for loop  

if globalCount > 1 // This should be checked whether vec has repetitions at all
   return mode
else
   return 0

// End of function

@Cistoran - 根据您的思维过程,算法应该是这样的,逻辑可以更好地提高效率。 - Mahesh

0
    int number = array_list[0];
    int mode = number;
    int count = 1;
    int countMode = 1;

    for (int i=1; i<size_of_list; i++)
    {
          if (array_list[i] == number) 
          { // count occurrences of the current number
             count++;
             if (count > countMode) 
                {
                      countMode = count; // mode is the biggest ocurrences
                      mode = number;
                }
          }
          else
          { // now this is a different number
                if (count > countMode) 
                {
                      countMode = count; // mode is the biggest ocurrences
                      mode = number;
                }
               count = 1; // reset count for the new number
               number = array_list[i];
      }
    }

0
所以,你有一个包含整数的向量。 遍历向量,并累积重复的元素,如果当前值等于下一个值。 如果相邻的值不相等,则将当前重复次数重置为1,并继续循环。 在此过程中存储并更新最大重复次数。
vector<int> nums;
int mode = 1;
for (int i = 0, cur_reps = 1; i < nums.size(); i++)
{
    if (i < nums.size()-1 && nums[i] == nums[i + 1])
    {
        cur_reps++;
        continue;
    }
    if (cur_reps > mode) mode = cur_reps;
    cur_reps = 1;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接