【问题标题】:Determine order of set iterators确定集合迭代器的顺序
【发布时间】:2018-01-10 12:47:32
【问题描述】:

我有两个迭代器(比如it1 和it2)到同一个std::set<int>。它们是通过lower_bound 和upper_bound 获得的,因此它们不能安全地取消引用(它们可以等于end())。 有没有一种简单安全的方法来判断哪个先行?

我可以打电话给std::distance(it1, it2) 和std::distance(it2, it1),但这似乎没有帮助,因为如果it1 != it2 那么其中一个电话是UB。我可以测试*it1 < *it2,但前提是没有迭代器指向end()。最后,我可以先测试结束迭代器,然后对值进行上述比较。

是否有一个纯粹基于迭代器而不涉及值的优雅解决方案,即取消引用?我愿意最多使用 c++14 并且可能会提升。

EDIT(响应 cmets): 我使用集合是因为​​我想要快速查找和插入,特别是比线性复杂度快得多。排序后的向量是一种可能的替代方案,它可以轻松解决问题,但插入和删除是线性时间操作。

【问题讨论】:

  • lower_bound 和 upper_bound 返回的迭代器将始终定义一个有效范围:[lower, upper)。你不需要检查它。如果两者相等,则范围为空,就像任何其他范围一样。
  • 除非你的意思是你有类似auto [it1, it2] = set.equal_range(value); if (rand()%2) swap(it1, it2);的东西
  • 迭代器不是来自相同值的下界和上界,并且逻辑有些涉及,因此迭代器可以按任何顺序排列。不过,我当然可以跟踪传递给绑定函数的值...
  • “有没有优雅的解决方案”是的,改变逻辑,所以迭代器总是按顺序排列
  • 明显的解决方案是使用排序向量而不是std::set<>,但没有足够的细节来说明这种解决方案是否可行

标签: c++ iterator set


【解决方案1】:

在我看来,最好的方法是修复你的代码逻辑并让[it1,it2) 始终是一个有效范围;如果事实证明这是不可能的(但怎么可能呢?),您可以使用类似

// O(N), forward iterators, it1, it2 should belong to range
template<class Iter>
bool precedes_or_is_equal( Iter it1, Iter it2, Iter end )
{
  while( it1 != end && it1 != it2 ) ++it1;

  return it1 == it2;
}

【讨论】:

  • 不错的解决方案,但它比取消引用更昂贵
  • @Slava 你是完全正确的,但你需要将值类型运算符与给定的 set 比较器匹配 ... ymmv;如前所述,最好的方法是简单地修复操作未显示的代码
  • 感谢您的建议,但我首先使用集合来避免线性复杂性。很抱歉没有显示完整的代码,但在我看来,这个问题本身就很有趣。由于集合是一棵树,应该可以在对数时间内解决问题,但显然这对于​​标准提供的接口是不可能的。
  • @tglas 问题在于,根据问题要求,我们不能取消引用迭代器;否则,只需直接使用“set”比较器就可以实现恒定时间解决方案...
  • @Massimiliano:唯一不能取消引用的迭代器是结束迭代器,所有其他迭代器都可以。因此首先测试 end() 然后取消引用工作。但是由于集合是底层的(rb 或 avl)树,问题应该(在完美的世界中)仅使用迭代器就可以在对数时间内解决。
猜你喜欢
  • 2015-04-28
  • 1970-01-01
  • 2013-01-02
  • 1970-01-01
  • 2012-07-07
  • 2015-08-11
  • 2010-09-16
  • 1970-01-01
  • 2015-09-07
相关资源
最近更新 更多