【问题标题】:C++ STL: Why is there no upper_bound equivalent that retrieves the greatest element smaller then a specific key?C ++ STL:为什么没有upper_bound 等效项可以检索小于特定键的最大元素?
【发布时间】:2013-03-03 18:30:59
【问题描述】:

通常,STL 是为速度而构建的。但是,map 和 set 数据结构上只有 upper_bound 和 lower_bound,没有操作来检索小于输入键 k 的最大键的条目。为什么是这样?我知道我可以简单地做一个lower_bound 并做一个--it 来检索它,但是根据数据结构,立即搜索正确的条目而不是搜索另一个然后返回一个可能更有效一步。

例如,std::map 使用红黑树,即二叉搜索树。如果upper_bound返回的元素是大于根的最小元素,那么--it必须走回根,查询O(log n)额外开销。

如果这是 Java,我会接受设计决策。然而,STL 是为最高速度而构建的,那么为什么忽略了这个操作呢?

说明: 我说的不是std::upper_bound 可以采用另一个比较器,而是std::mapstd::set 的方法。

【问题讨论】:

  • 你的意思是“简单地做一个lower_bound然后做一个--it”?
  • @JonathanWakely:我知道这一点。我在第二句话中写了这个。请正确阅读问题:)
  • 咳咳,请自行阅读。我读了,谢谢。你写了upper_bound,我问你的意思是lower_bound(这是第四句而不是第二句)
  • @JonathanWakely:大声笑,真的,我没有正确阅读您的评论。对不起,对不起 :)

标签: c++ stl binary-search-tree


【解决方案1】:

首先,要获得小于键的最大元素,您必须这样做:

auto it = m.lower_bound(k);
--it;

意思是找到不小于k的第一个元素,并向后移动一个元素。如果有一个函数来执行此操作,例如auto it = m.last_less_element(k);,那么该函数必须以完全相同的方式实现,即找到不小于@987654324的第一个元素@ 并后退一次。这是因为没有办法知道没有比k 更大但仍小于k 的元素,除非你找到不小于k 的第一个元素。因此,拥有这样的功能并没有性能提升,它只是一种语法快捷方式/便利。即便如此,与查找本身的成本相比,回退一次的成本也可以忽略不计。

其次,如果你想从开始到最后一个元素迭代小于键,那么你会这样做:

for(auto it = m.begin(); it != m.lower_bound(k); ++it) { /* ... */ };

换句话说,lower_boundupper_bound 函数的制作方式是标准迭代器范围的惯用方式,这非常重要。仅在这一点上,不包含像last_less_element 这样的特殊函数是合理的,因为它会在mapset 类的接口中引入反惯用函数,并且不会提高性能。所以,它会导致痛苦,但没有收获。

最后一点,二叉搜索树(如红黑树)主要用于查找操作,按顺序遍历具有边际优势。它们不是为按顺序遍历而简化的,如果这是您想要执行的主要操作,则不应使用它们。当主要操作是查找操作时,有序映射或集合很有用,偶尔需要按顺序遍历。在相反的情况下应考虑其他替代方案(例如,排序向量、树布局à la von Emde Boas 等)。

【讨论】:

  • 真可惜。我打错了整个问题:(。我在寻找last_element_not_greater而不是last_element_less。与last_element_less相比,另一个函数确实有比upper_bound + --it更有效的解决方案。因为有这里老问题的答案太多了,我为我的问题创建了一个新问题:C++ STL:为什么没有upper_bound 等效项可以检索不大于特定键的最大元素?
【解决方案2】:

因为您只需反转谓词即可使用 std::lower_bound 完成您想要的操作。

【讨论】:

  • std::map::lower_bound 不带谓词,而地图上的 std::lower_bound 很糟糕。
  • @jrok: lower_bound 确实有一个需要谓词的重载。而地图上的std::upper_boundlower_bound 一样糟糕,这似乎就是问题所在(在没有随机访问迭代器的容器上使用upper_bound)。如果您使用的是带有随机访问迭代器的容器,那么--it 将不是问题。
  • @MichaelBurr OP 没有谈论std::lower_bound,而是谈论this one(至少我是这样理解Q的)。
  • @MichaelBurr 我认为重点在于使用来自<algorithm> 的非成员版本与使用成员函数。
  • 当然,我说的是map和set的成员函数。我知道std::lower_bound 函数可以使用谓词。我澄清了我的问题。
猜你喜欢
  • 2019-01-31
  • 2013-01-19
  • 2019-09-14
  • 1970-01-01
  • 2015-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-24
相关资源
最近更新 更多