计算 std::set 中低于给定值的元素
Count elements lower than a given value in a std::set
我需要找出有多少元素低于 std::set
中的给定元素。
我认为正确使用的函数是 std::lower_bound
,其中 returns 是指向大于或等于给定元素的第一个元素的迭代器....所以此迭代器的索引是我在找什么...但我无法从迭代器中找到索引:
#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 有效 perfectly。
看起来运算符 - 对 std::set::iterator
无效。为什么?
那么,您如何轻松地(不调用 std::previous
或 std::next
直到达到边界...这效率不高)找到给定迭代器在容器中的位置?如果不能,那么我可以使用什么替代方法来查找给定元素的索引...?
Looks like operator- is not valid for a std::set::iterator. Why?
事实上,std::set::iterator::operator-()
的实现不能以恒定的复杂度存在,因为元素在内存中不连续。
Then, how can you easily (without calling std::previous or std::next until bound is reached...this would not be efficient) find the position of a given iterator in the container?
你不能,std::set::iterator
不是 RandomAccessIterator. See std::distance()
文档:
Complexity
Linear.
If you can't, then what alterantive can I use to find the index of a given element...?
我建议在不必计算迭代器距离的情况下对元素进行计数: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;
}
您可以为此使用以下代码:
#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;
}
因为 std::set::iterator
是 BidirectionalIterator 我们不能减去它,除非我们使用减量运算符。不过,我们可以做的只是遍历集合并计算迭代次数,直到我们达到的数字大于我们正在寻找的数字。
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
does not have O(log N) complexity since we are not using a RandomAccessIterator。当使用非 RandomAccessIterator 时,它具有线性复杂度。
扩展所有现有答案 - 您始终可以编写自己的 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);
}
进行下限搜索的正确方法是使用 std::set
's own lower_bound
function,它专门设计用于处理这种排序的、关联的、非随机访问的容器。
所以,而不是这个:
std::lower_bound( mySet.begin(), mySet.end(), 2 );
使用这个:
mySet.lower_bound(2);
这是容器大小的对数,比 好得多(它不知道比较器的排序,因此必须访问所有节点,因此是线性的) .
但是,你也必须从开始到下界使用std::distance
,这不仅是线性的,而且在实践中也必然是"slow"(由于非随机访问) .
似乎是最优的,因为您不想简单地找到下限,而是找到它与容器 "start" 的距离。
我需要找出有多少元素低于 std::set
中的给定元素。
我认为正确使用的函数是 std::lower_bound
,其中 returns 是指向大于或等于给定元素的第一个元素的迭代器....所以此迭代器的索引是我在找什么...但我无法从迭代器中找到索引:
#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 有效 perfectly。
看起来运算符 - 对 std::set::iterator
无效。为什么?
那么,您如何轻松地(不调用 std::previous
或 std::next
直到达到边界...这效率不高)找到给定迭代器在容器中的位置?如果不能,那么我可以使用什么替代方法来查找给定元素的索引...?
Looks like operator- is not valid for a std::set::iterator. Why?
事实上,std::set::iterator::operator-()
的实现不能以恒定的复杂度存在,因为元素在内存中不连续。
Then, how can you easily (without calling std::previous or std::next until bound is reached...this would not be efficient) find the position of a given iterator in the container?
你不能,std::set::iterator
不是 RandomAccessIterator. See std::distance()
文档:
Complexity
Linear.
If you can't, then what alterantive can I use to find the index of a given element...?
我建议在不必计算迭代器距离的情况下对元素进行计数: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;
}
您可以为此使用以下代码:
#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;
}
因为 std::set::iterator
是 BidirectionalIterator 我们不能减去它,除非我们使用减量运算符。不过,我们可以做的只是遍历集合并计算迭代次数,直到我们达到的数字大于我们正在寻找的数字。
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
does not have O(log N) complexity since we are not using a RandomAccessIterator。当使用非 RandomAccessIterator 时,它具有线性复杂度。
扩展所有现有答案 - 您始终可以编写自己的 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);
}
进行下限搜索的正确方法是使用 std::set
's own lower_bound
function,它专门设计用于处理这种排序的、关联的、非随机访问的容器。
所以,而不是这个:
std::lower_bound( mySet.begin(), mySet.end(), 2 );
使用这个:
mySet.lower_bound(2);
这是容器大小的对数,比
但是,你也必须从开始到下界使用std::distance
,这不仅是线性的,而且在实践中也必然是"slow"(由于非随机访问) .