计算低于 std::set 中给定值的元素
Count elements lower than a given value in a std::set
我需要找到一个std::set
中有多少元素低于给定的元素。
我认为要使用的正确函数是std::lower_bound
它将迭代器返回到大于或等于给定元素的第一个元素......所以这个迭代器的索引就是我正在寻找的......但我无法从迭代器中找到索引:
#include <iostream>
#include <algorithm>
#include <set>
int main()
{
std::set<int> mySet;
mySet.insert( 1 );
mySet.insert( 2 );
mySet.insert( 3 );
mySet.insert( 4 );
std::set<int>::const_iterator found = std::lower_bound( mySet.begin(), mySet.end(), 2 );
if ( found != mySet.end() )
std::cout << "Value 2 was found at position " << ( found - mySet.begin() ) << std::endl;
else
std::cout << "Value 2 was not found" << std::endl;
}
这不会编译:
16:63: error: no match for 'operator-' (operand types are 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}' and 'std::set<int>::iterator {aka std::_Rb_tree_const_iterator<int>}')
16:63: note: candidates are:
In file included from /usr/include/c++/4.9/vector:65:0,
from /usr/include/c++/4.9/bits/random.h:34,
from /usr/include/c++/4.9/random:49,
from /usr/include/c++/4.9/bits/stl_algo.h:66,
from /usr/include/c++/4.9/algorithm:62,
from 3:
使用 std::vector 而不是 std::set 可以完美地工作。
看起来像运算符 - 对std::set::iterator
无效。为什么?那么,你怎么能轻松地(不打电话给std::previous
或std::next
直到达到绑定......这将没有效率)找到给定迭代器在容器中的位置?如果不能,那么我可以使用什么替代方法来查找给定元素的索引...?
进行下限搜索的正确方法是使用 std::set
自己的 lower_bound
函数,该函数专门设计用于处理这种排序的、关联的、非随机访问的容器。
所以,取而代之的是:
std::lower_bound( mySet.begin(), mySet.end(), 2 );
使用这个:
mySet.lower_bound(2);
这在容器的大小上是对数的,这比std::count_if
方法(不知道比较器的排序,因此必须访问所有节点,因此是线性的)要好得多。
但是,您还必须从起点到下限使用std::distance
,这不仅是线性的,而且在实践中必然是"慢"的(由于非随机访问)。
Nathan 的解决方案似乎是最佳的,因为您不想简单地找到下限,而是找到它与容器"起点"的距离。
看起来像运算符 - 对 std::set::iterator 无效。为什么?
事实上,std::set::iterator::operator-()
的实现不可能以恒定的复杂性存在,因为这些元素在内存中不是连续的。
然后,你怎么能轻松地(不调用std::p revious或std::next,直到达到界限......这将没有效率)找到给定迭代器在容器中的位置?
你不能,std::set::iterator
不是随机访问迭代器。请参阅std::distance()
文档:
复杂性
线性。
如果不能,那么我可以使用什么替代方法来查找给定元素的索引...?
我建议在不计算迭代器距离的情况下计算您的元素:std::count_if()
可以帮助我们:
#include <iostream>
#include <algorithm>
#include <set>
int main()
{
std::set<int> mySet;
mySet.insert( 1 );
mySet.insert( 2 );
mySet.insert( 3 );
mySet.insert( 4 );
const std::size_t lower_than_three = std::count_if(
std::begin(mySet)
, std::end(mySet)
, [](int elem){ return elem < 3; } );
std::cout << lower_than_three << std::endl;
}
演示
由于std::set::iterator
是一个双向迭代器,除非我们使用递减运算符,否则我们不能从中减去它。 不过,我们能做的就是走一遍并计算迭代次数,直到我们达到比我们正在寻找的数字更大的数字。
std::set<int> mySet;
// fill values
int counter = 0;
for (auto it = mySet.begin(), *it < some_value && it != mySet.end(); ++it)
{
if (e < some_value)
counter++;
}
这是一个最糟糕的mySet.size()
迭代,在处理双向迭代器时尽可能快。
另请注意,std::lower_bound
没有O(log N)复杂性,因为我们没有使用RandomAccessIterator。 当使用非随机访问迭代器时,它具有线性复杂性。
为此,可以使用以下代码:
#include <algorithm>
#include <set>
#include <iostream>
int main()
{
std::set<int> mySet;
mySet.insert( 1 );
mySet.insert( 2 );
mySet.insert( 3 );
mySet.insert( 4 );
std::set<int>::const_iterator found = std::lower_bound( mySet.begin(), mySet.end(), 2 );
std::size_t dist = std::distance(found, mySet.end());
std::cout << "Number of lower bound elements: " << dist << std::endl;
}
扩展所有现有答案 - 您可以随时编写自己的operator-
。
template<class T, class = typename
std::enable_if<
std::is_same<
typename T::iterator_category,
std::bidirectional_iterator_tag
>::value>::type>
typename std::iterator_traits<T>::difference_type operator-(const T& a, const T& b)
{
return std::distance(b, a);
}
- 对于set上的循环-获取next元素迭代器
- set::find 查找不存在的元素
- 是否有一个 std::set 函数来确定不超过数字 x 的最大元素?
- 如何从 std::set 绘制 n 个元素的样本
- 从 std::set 中删除元素,同时在 C++17 中迭代该元素
- 如何在对数时间内访问 c++ std::set 中的第 k 个元素?
- 语言的哪一部分禁止更改 std::set 的元素
- 如何在一对集合的向量中插入元素?vector<pair<int,set<string>>>
- 在 std::set 中查找 std::vector 的元素
- 创建 std::set 只复制一个元素,如何解决这个问题?
- 为什么 std::set 遍历所有元素的速度较慢?
- 为什么在查找元素时需要使用 set.find(x) != set.end()
- 直接访问 STL "set"元素
- 新元素将在std :: set中插入哪里
- std :: set and std :: unordered_set构造元素与emplace()如何
- 通过与不同类型的值进行自定义比较来查找 std::set 的元素
- 删除 std::set<Node *> 中的元素的正确方法
- 如何使用反向迭代器从“std::set”中删除元素
- 给定一个 std::set::iterator,获取一个指向下一个元素的迭代器
- 无法将 std::set 中的元素迭代器插入到 std::list