【问题标题】:std::lower_bound on std::vector with reverse iterators yields a wrong result带有反向迭代器的 std::vector 上的 std::lower_bound 会产生错误的结果
【发布时间】:2014-08-05 09:27:19
【问题描述】:

最近我发现需要计算给定区间之外的元素。

例如,如果我有一个排序向量 { 10, 20, 30 } 和另一个排序向量 { 15, 25 },它们的边界定义了区间。我想数“10”和“30”(范围内只有 20)。为此,我使用 std::vector 和 std::lower_bound,一次向前扫描向量,一次向后扫描。

代码如下:

    int t[] = { 15, 25 };
int c[] = { 10, 20, 30 };

std::vector<int> tt(t, t + 2);
std::vector<int> cc(c, c + 3);

auto lower = std::lower_bound(cc.begin(), cc.end(), tt.front(), [](int a, int b){ return a < b; });
auto upper = std::lower_bound(cc.rbegin(), cc.rend(), tt.back(), [](int a, int b){ return a > b; });

size_t beforeCount = lower - cc.begin();
size_t afterCount = upper - cc.rbegin();

我希望 'lower' 和 'upper' 都指向同一个元素:20。

我在这方面花了一些时间,有人发现这里有问题吗? 我真的很想使用 STL。

谢谢你, 亚历克斯

【问题讨论】:

  • 你在重塑equal_range吗?代码看起来合法。 *lower*upper都是20,beforeCountafterCount都是1。是什么让你觉得有问题?
  • 你的问题是什么?您当前的输出是什么,您的预期输出是什么?
  • “我希望 'lower' 和 'upper' 都指向同一个元素:20。” --- 他们有。
  • 你为什么要使用 STL?只写一个简单的循环..
  • @nwp:谢谢,确实看起来我可以使用 equal_range 实现相同的效果,但我仍然必须调用它两次,因为我的范围由多个值描述。我在这里使用 equal_range 没有看到任何附加值,我可能遗漏了什么吗?

标签: c++ vector stl


【解决方案1】:

我认为您对迭代器的区别和迭代器指向的值感到困惑。

您的程序正在按照您的想法执行,请参阅here

beforeCountafterCount 都等于 1。它们是迭代器,不是任何向量元素的值,它们只是指向向量中值的指针。

要打印相应的元素,只需:

std::cout << cc[beforeCount] << std::endl;
std::cout << cc[afterCount] << std::endl;

输出:

20

20

注意:

你可以在没有中间数组的情况下初始化你的向量:

std::vector<int> tt { 15, 25 };
std::vector<int> cc  { 10, 20, 30 } ;

【讨论】:

  • quantdev,谢谢您的回答。我不认为我混淆了迭代器和迭代器指向的值。我看到 beforeCount 和 afterCount(对我来说很神奇)都等于 1。但是我不明白为什么“上”不指向 20,而是指向 30。我希望它指向 20。顺便说一句,请注意“ std::cout
  • 顺便说一句,我正在使用 VS2012,但仍然无法按照您建议的方式初始化向量(已经尝试过)。也许你能知道为什么? VS2012 应该实现完整的 C++11 规范
  • 我认为我的错误是在调试器中查看'upper',它指向值'30'。 *upper 产生 20。我不太理解为什么,也许它的调试器让我感到困惑?
  • 我不确定您在调试器中查看的内容,但对我(unix)来说,它给出了正确的结果。
  • “它指向值 '30'。*upper 产生 20。我不太理解为什么”。那是因为反向迭代器没有像您期望的那样实现。如果您检查cc.rbegin(),您会看到它“指向”垃圾,而不是最后一个元素。事实上它指向同一个地方cc.end()。必须这样,否则你无法实现rend()。其他一切都随之而来。
【解决方案2】:

我发现有时很难对反向迭代器进行推理。您可以避免使用它们,如下所示:

auto first = std::lower_bound(cc.begin(), cc.end(), tt.front());
auto second = std::upper_bound(first, cc.end(), tt.back());

size_t beforeCount = first - cc.begin();
size_t afterCount = cc.end() - second;

这与equal_range 非常相似,因此实际上我们可以将其重写如下(尽管在过去有非标准实现w.r.t.异构比较器的MSVC 上可能会很麻烦):

typedef std::pair<int, int> Pr;
struct Cmp {
    bool operator()(int x, const Pr &y) { return x < y.first; }
    bool operator()(const Pr &x, int y) { return x.second < y; }
};
auto pr = std::equal_range(cc.begin(), cc.end(), Pr(15, 25), Cmp());

size_t beforeCount = pr.first - cc.begin();
size_t afterCount = cc.end() - pr.second;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-08
    • 2017-05-22
    • 2012-02-05
    • 2017-07-27
    • 2021-06-07
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    相关资源
    最近更新 更多