【问题标题】:An ugly function finding the maximum std::set element less than a given key一个丑陋的函数找到小于给定键的最大 std::set 元素
【发布时间】:2021-09-08 17:31:40
【问题描述】:

当我编写一个有点奇怪的代码时,我有一种感觉,我可能误解了一些东西。 find_less 函数的实现是否比下面提供的更好?

#include <iostream>
#include <set>

using Set = std::set<int>;

Set set{ 0, 1, 3, 7, 9, 10 };

Set::iterator find_less(int val)
{
    auto i = set.lower_bound(val);

    if (i == set.begin())
    {
        return set.end();
    }

    return --i;
}

int main()
{
    auto i = find_less(5);

    if (i != set.end())
    {
        //outputs 3
        std::cout << *find_less(5) << std::endl;
    }
    
    return 0;
}

std::setlower_boundupper_bound 函数查找大于(或等于)给定键的第一个元素,但它没有查找小于(或等于)给定键的元素?

EDIT1:

std::lower_bound(set.rbegin(), set.rend(), val)

但看起来它只对随机访问迭代器是对数的,请参阅https://en.cppreference.com/w/cpp/algorithm/lower_boundstd::set 和 std::multiset 迭代器不是随机访问,因此它们的成员函数 std::set::lower_bound (resp. std::multiset::lower_bound) 应该是首选。

【问题讨论】:

  • 您正在检查lower_bound 是否返回set.end(),但您可能应该检查它是否返回set.begin()*find_less(11) 将导致未定义的行为,*find_less(0) 也是如此。
  • @DrewDormann 更新了帖子。
  • 现在您已经更改了问题中的代码,*find_less(11)仍然导致未定义行为。它将取消引用 end 迭代器find_less(0) 现在将返回一个 小于给定键的迭代器。
  • 我对小于、等于、第一、最大值感到困惑……预期的输出是什么? 3 ? find_less(7) 的预期结果是什么?
  • 这些 cmets 可能会导致回答您的第二个“这不是很奇怪...”问题。 C++ 中的容器支持“结束后一个”迭代器,但不支持“开始前一个”迭代器。

标签: c++


【解决方案1】:

考虑所有潜在输入的简单解决方案可能是将end() 返回为唯一均值

集合中没有元素符合条件

auto find_less(const Set& set, int val)
{
    auto i = set.lower_bound(val);
    return (i == set.begin()) ? set.end() : std::prev(i);
}

我还更改了您的函数签名以允许提供一组,而不是总是搜索一个特定的全局变量。

【讨论】:

  • 是的好一点
【解决方案2】:

基本上,upper_bound 和 lower_bound 都是 forward 算法——它们从集合的开头(最低元素)开始,直到找到满足条件的元素(>= 一个值或> 一个值),返回一个迭代器到找到的元素(或结束)。因此,它们固有地找到满足谓词的第一个元素。如果要查找满足谓词的 last 元素,则需要反向搜索,但映射和集合不提供。

您的代码比它需要的要复杂一些——您不需要与 set.end() 进行比较,只需 set.begin();


如果你真的因为不得不编写一个“备份”辅助函数而烦恼,你可以使用一个带有 std::greater 的集合作为比较器:

using Set = std::set<int, std::greater<int>>;

然后直接使用lower_bound(或upper_bound)。

【讨论】:

  • 更正了代码。为什么地图和集合不提供它们?为什么不添加reverse_lower_boundreverse_uppder_bound
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-12
相关资源
最近更新 更多