在容器中查找纯虚拟类的对象

时间:2016-09-26 12:59:15

标签: c++ pure-virtual

要实现非重叠间隔的容器,我定义了以下内容:

set<unique_ptr<interval>> db;

确保定义了非重叠属性:

bool operator<(const unique_ptr<interval>& lhs, 
               const unique_ptr<interval>& rhs);

interval类有2个字段:startlast,因此我可以确定某些int是否属于某个interval实例的范围。

现在我想要在集合中搜索int n以查找包含它的区间。

我考虑使用unique_ptr<interval> dummy_interval创建first=last=n并搜索调用db.find(dummy_interval),但问题是类interval是纯虚拟的,所以我无法创建它的任何实例。

我怎样才能克服这个问题?

1 个答案:

答案 0 :(得分:1)

由于您有非重叠间隔,因此可以将std::lower_bound与自定义比较器一起使用:

template <typename It>
It find_interval(It first, It last, int value) {
    // See explanation below.
    auto it = std::lower_bound(first, last, value, 
                               [](const std::unique_ptr<interval>& i1, int value) {
                                   return i1->start < value;
                               });
    if (it != last && (*it)->start == value) {
        return it;
    }
    --it;
    // Change this to: (*it)->end > value ? it : last
    // ...if the upper bound of the interval are not included.
    return (*it)->end < value ? last : it;
}

std::lower_bound会找到不小于的第一个区间(即大于或等于)而不是值。由于我们正在与开始进行比较,我们有两种情况:

  • 该值是间隔的开始,在这种情况下,将返回间隔本身(第一个if);
  • 该值不是间隔的开始,在这种情况下将返回 next 间隔,因此我们需要递减it--it)。

由于我们只检查std::lower_bound中的开头,我们需要在返回之前检查结束。

std::lower_bound具有对数复杂度,上述调用有效,因为相对于我们提供的比较器(lambda),范围[first, last) 有序 - 我是假设db根据间隔的开始进行排序。

有关完整实施的信息,请参阅http://rextester.com/FBHYH63411

旁注:如果您不经常插入/删除间隔,最好使用已排序的std::vector

编辑:旧答案 - 您可能无法使用std::set::find来查找时间间隔,因为您在db中使用的比较器会比较两个interval,而不是intervalint,以及{ {1}}使用这个比较器(即使是“虚拟”间隔,你需要一个有效的关系,这可能很难获得)。

您需要更改结构并使用,例如Interval Tree以保持对数复杂度,或者使用非“专用”std::find线性复杂度:

std::set::find