繁体   English   中英

在 C++ 中获取数组中数字频率的最快方法是什么?

[英]What is the fastest way to get the frequency of numbers in an array in C++?

我的方法创建了一个 std::map<int, int> 并通过遍历数组一次来用数字及其频率填充它,但我想知道是否有更快的方法而不使用 map。

std::unordered_map<int,int>也可以计算频率,但其operator[]具有复杂性( cppreference ):

平均情况:恒定,最坏情况:大小呈线性。

相比

容器大小的对数。

带有std::map

当最大数较小时,可以使用数组,直接计数:

 for (const auto& number : array) counter[number]++;

诚然,这一切都已经在评论中说了,所以我还要补充一点:你需要衡量。 复杂性仅与渐近运行时有关,而对于给定的输入大小, std::map实际上可以更快。

注意: ValueType, DifferenceType被定义为

template <std::input_iterator I>
using ValueType = typename std::iterator_traits<I>::value_type;

template <std::input_iterator I>
using
DifferenceType = typename std::iterator_traits<I>::difference_type;

如果数组是sorted ,您可以使用std::equal_range来查找等于x的元素范围。 使用您编写的概念:

// I2 is homomorphic to std::pair<I, unsigned>
// [first, last) is partially ordered with respect to I::value_type
// return value is d_first + |{x | x in [first, last)}|
// R is a relation over I, compare element using R
template <std::random_access_iterator I, std::forward_iterator I2,
std::relation<bool, ValueType<I>> R = std::less<ValueType<I>>>
requires(std::regular<ValueType<I>> &&
std::is_constructible_v<ValueType<I2>, I, DifferenceType<I>>)

I2 frequency_sorted(I first, I last, I2 d_first, R r = R())
{
  while(first != last)
  {
    auto [left, right] = std::equal_range(first, last, *first, r);
    *d_first = {left, std::distance(left, right)};
    ++d_first;
    first = right;
  }
  return d_first;
}

如果您的资源有限,您可以截断结果并拥有:

// I2 is homomorphic to std::pair<I, unsigned>
// [first, last) is partially ordered with respect to I::value_type
// return value is a pair, where the first element is 
// the starting point of subsequence [first, last) where such
// subsequence is unevaluated
// the second element is 
// - d_last if |{x | x in [first, last)}| >= d_last - d_first
// - d_first + |{x | x in [first, last)}| if otherwise
template <std::random_access_iterator I, std::forward_iterator I2,
std::relation<bool, ValueType<I>> R = std::less<ValueType<I>>>
requires(std::regular<ValueType<I>> &&
std::is_constructible_v<ValueType<I2>, I, DifferenceType<I>>)

std::pair<I, I2>
frequency_sorted_truncate(I first, I last, I2 d_first, I2 d_last, R r = R())
{
  while(first != last && d_first != d_last)
  {
    auto [left, right] = std::equal_range(first, last, *first, r);
    *d_first = {left, std::distance(left, right)};
    ++d_first;
    first = right;
  }
  return {first, d_first};
}

这两个函数允许你传入任何关系,默认比较使用operator<

如果您的数组未排序,并且数组的大小足够大,那么对数组进行排序并使用算法可能是个好主意。 散列可能很诱人,但它会造成缓存未命中,并且可能不如您预期的那么快。 两种方法你都可以试试看哪一种比较快,欢迎告诉我结果。

我的编译器版本是g++ 11.2.11 ,我认为代码可以用C++ 20编译器编译。 如果您没有,只需将概念部分替换为typename ,我认为这样做您只需要一个C++ 17编译器(由于结构绑定)。

请告诉我是否可以改进我的代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM