我正在尝试以函数的形式设计一个算法,该函数接受两个参数,一个数组和数组的大小。我希望它返回数组的模式,如果有多种模式,则返回它们的平均值。我的策略是采用数组并首先对其进行排序。然后计算所有出现的数字。当该数字发生时,添加一个计数器并将该计数存储在数组m中。所以m保持所有计数,另一个数组q保持我们比较的最后一个值。
例如:我的列表是{1, 1, 1, 1, 2, 2, 2}
然后我会m[0] = 4 q[0] = 1
and then m[1] = 3 and q[1] = 2.
因此模式为q[0] = 1;
不幸的是,到目前为止我没有成功。希望有人可以提供帮助。
float mode(int x[],int n)
{
//Copy array and sort it
int y[n], temp, k = 0, counter = 0, m[n], q[n];
for(int i = 0; i < n; i++)
y[i] = x[i];
for(int pass = 0; pass < n - 1; pass++)
for(int pos = 0; pos < n; pos++)
if(y[pass] > y[pos]) {
temp = y[pass];
y[pass] = y[pos];
y[pos] = temp;
}
for(int i = 0; i < n;){
for(int j = 0; j < n; j++){
while(y[i] == y[j]) {
counter++;
i++;
}
}
m[k] = counter;
q[k] = y[i];
i--; //i should be 1 less since it is referring to an array subscript
k++;
counter = 0;
}
}
答案 0 :(得分:5)
即使你已经有了一些好的答案,我决定发布另一个。我不确定它真的增加了很多新的,但我不确定它也不是。如果不出意外,我很确定它使用的标准标题比任何其他答案都要多。 : - )
#include <vector>
#include <algorithm>
#include <unordered_map>
#include <map>
#include <iostream>
#include <utility>
#include <functional>
#include <numeric>
int main() {
std::vector<int> inputs{ 1, 1, 1, 1, 2, 2, 2 };
std::unordered_map<int, size_t> counts;
for (int i : inputs)
++counts[i];
std::multimap<size_t, int, std::greater<size_t> > inv;
for (auto p : counts)
inv.insert(std::make_pair(p.second, p.first));
auto e = inv.upper_bound(inv.begin()->first);
double sum = std::accumulate(inv.begin(),
e,
0.0,
[](double a, std::pair<size_t, int> const &b) {return a + b.second; });
std::cout << sum / std::distance(inv.begin(), e);
}
与@ Dietmar的答案相比,如果您在数字中有很多重复,这应该更快,但如果数字主要唯一,那么他的速度可能会更快。
答案 1 :(得分:4)
根据评论,您似乎需要找到最常出现的值,如果有多个值出现的次数相同,则需要生成这些值的平均值。看来,这可以通过std::sort()
轻松完成,然后进行遍历查找,其中值会发生变化并保持一些运行计数:
template <int Size>
double mode(int const (&x)[Size]) {
std::vector<int> tmp(x, x + Size);
std::sort(tmp.begin(), tmp.end());
int size(0); // size of the largest set so far
int count(0); // number of largest sets
double sum(0); // sum of largest sets
for (auto it(tmp.begin()); it != tmp.end(); ) {
auto end(std::upper_bound(it, tmp.end(), *it));
if (size == std::distance(it, end)) {
sum += *it;
++count;
}
else if (size < std::distance(it, end)) {
size = std::distance(it, end);
sum = *it;
count = 1;
}
it = end;
}
return sum / count;
}
答案 2 :(得分:2)
如果您只想计算出现的次数,我建议您使用std::map
或std::unordered_map
。
如果您要将计数器映射到每个不同的值,那么使用std::map
计算出现次数很容易,因为每个键只能插入一次。要列出列表中的不同数字,只需遍历地图即可。
以下是您如何做到这一点的示例:
#include <cstddef>
#include <map>
#include <algorithm>
#include <iostream>
std::map<int, int> getOccurences(const int arr[], const std::size_t len) {
std::map<int, int> m;
for (std::size_t i = 0; i != len; ++i) {
m[arr[i]]++;
}
return m;
}
int main() {
int list[7]{1, 1, 1, 1, 2, 2, 2};
auto occurences = getOccurences(list, 7);
for (auto e : occurences) {
std::cout << "Number " << e.first << " occurs ";
std::cout << e.second << " times" << std::endl;
}
auto average = std::accumulate(std::begin(list), std::end(list), 0.0) / 7;
std::cout << "Average is " << average << std::endl;
}
输出:
Number 1 occurs 4 times
Number 2 occurs 3 times
Average is 1.42857
答案 3 :(得分:1)
这是您的代码的工作版本。 m将值存储在数组中,q存储它们的计数。最后,它遍历所有值以获得最大计数,模式总和以及不同模式的数量。
float mode(int x[],int n)
{
//Copy array and sort it
int y[n], temp, j = 0, k = 0, m[n], q[n];
for(int i = 0; i < n; i++)
y[i] = x[i];
for(int pass = 0; pass < n - 1; pass++)
for(int pos = 0; pos < n; pos++)
if(y[pass] > y[pos]) {
temp = y[pass];
y[pass] = y[pos];
y[pos] = temp;
}
for(int i = 0; i < n;){
j = i;
while (y[j] == y[i]) {
j++;
}
m[k] = y[i];
q[k] = j - i;
k++;
i = j;
}
int max = 0;
int modes_count = 0;
int modes_sum = 0;
for (int i=0; i < k; i++) {
if (q[i] > max) {
max = q[i];
modes_count = 1;
modes_sum = m[i];
} else if (q[i] == max) {
modes_count += 1;
modes_sum += m[i];
}
}
return modes_sum / modes_count;
}