【问题标题】:How to get the iterator (or the value) for "previous" item for given key of std::multimap?如何为std :: multimap的给定键获取“上一个”项目的迭代器(或值)?
【发布时间】:2014-12-22 22:48:33
【问题描述】:

我想为我的std::multimap 获取 before 给定密钥的项目。

对于给定键之后的项目,我可以简单地使用std::multimap::upper_bound(它将返回键大于给定的元素)。但不幸的是,std::multimap::lower_bound 会返回带有“下或等于”键的元素。

样本取自http://www.cplusplus.com/reference/map/multimap/lower_bound/:

mymultimap.insert(std::make_pair('a',10));
mymultimap.insert(std::make_pair('b',121));
mymultimap.insert(std::make_pair('c',1001));
mymultimap.insert(std::make_pair('c',2002));
mymultimap.insert(std::make_pair('d',11011));
mymultimap.insert(std::make_pair('e',44));

itlow = mymultimap.lower_bound ('b');  // itlow points to b
itup = mymultimap.upper_bound ('d');   // itup points to e (not d)

当您将b 作为参数时,如何获取a 的迭代器(或值)?

【问题讨论】:

  • 嗯,只是减少迭代器??

标签: c++ std multimap


【解决方案1】:

您可以使用lower_bound,但您必须考虑两种极端情况:它返回begin(),它返回end()

auto itfound = mymultimap.lower_bound('b');
if (itfound == mymultimap.begin()) {
    // 'b', or something past 'b', is the first item
    // or the map is empty
    // what to do here?
}
else if (itfound == mymultimap.end()) {
    // there does not exist an item >= 'b'
    // what to do here? possibly std::prev(end()) ?
}
else {
    // ok cool, we found something in the middle
    // just back up
    --itfound;

    // do stuff with itfound here
}

【讨论】:

  • 为什么end 需要是一个特例?您应该能够像任何其他迭代器一样减少它。
  • @MarkRansom 如果逻辑上OP想要做一些不同的事情,如果没有这样的元素。在功能上,是的,你可以减少 end() 就好了。
  • 但是lower_bound 不会返回end,如果不存在确切的值,它会返回插入点。这只是end 如果键大于映射中最大的键。
  • 如果容器为空,begin 将匹配 end,这意味着您的第一个 if 检查中的代码可能有 UB,除非您还检查它是否等于 end
【解决方案2】:

继续使用lower_bound,然后减少您收到的迭代器(在检查以确保它不是begin 之后)。

itfound = mymultimap.lower_bound('b');
if (itfound != mymultimap.begin())
{
    --itfound;
    // do something with itfound
}

如果项目不在地图中,您可能需要稍微不同的逻辑,但这不应该是一个硬修改。

【讨论】:

  • 呵呵,我没想过要减少lower_bound。一旦我变红了,它看起来很明显......谢谢你,先生:)
【解决方案3】:

对于任何已排序的容器(即mapsetmultimapmultiset),我们知道以下内容:

  • lower_bound(key) 返回第一个条目 >= key
  • upper_bound(key) 返回第一个条目 > key

如果没有条目,每个函数也会返回end() >= /> key

所以我们有基于运算符 > 和 >= 的功能。我们可能会问,我们是否也可以拥有基于

要求第一个条目 key 有点微不足道(这是 begin() 或不在容器中)。然而,要求是最后一个这样的条目是有意义的。确实,您所要求的最后一个条目key。
为了完整起见,我们也会考虑最后一个条目 key。

假设我们有这样的函数,如果没有这样的入口,它们应该怎么做?我们也可以比返回end() 做得更糟——它是一个可测试的值,与任何成功案例都不同。它也与lower_boundupper_boundfind 以及<algorithm> 标头中的大量独立搜索功能一致。底线是end() 通常用于表示“没有这样的条目”,所以这对我们来说也应该足够好了。

正如 Barry 和 Mark 所指出的,调用 lower_bound(key) 然后递减会得到我们想要的,除非 lower_bound(key) == begin()。在这种情况下,第一个(因此是 [joint-] 最小的)条目 >= key,因此没有条目 key - 正是我们刚才说我们应该返回 end() 的场景。

对于查找最后一个条目 key 的情况,我们可以做同样的事情,但使用 upper_bound,当 upper_bound(key) == begin() 时再次返回 end() 表示“没有这样的条目”。

让我们分别调用这些函数lower_bound_decupper_bound_dec

// Find the last entry < key, returning end() if all entries are >= key
// Container can be any that implements lower_bound, e.g. std::map, std::multimap, std::set or std::multiset
template<typename Container, typename Key>
typename Container::const_iterator lower_bound_dec(const Container &container, const Key &key) {
    auto it = container.lower_bound(key);
    if (it == std::begin(container))
        it = std::end(container);
    else
        --it;
    return it;
}

// Find the last entry <= key, returning end() if all entries are > key
// Container can be any that implements upper_bound, e.g. std::map, std::multimap, std::set or std::multiset
template<typename Container, typename Key>
typename Container::const_iterator upper_bound_dec(const Container &container, const Key &key) {
    auto it = container.upper_bound(key);
    if (it == std::begin(container))
        it = std::end(container);
    else
        --it;
    return it;
}

我们还可以定义基于迭代器的函数,它镜像std::lower_boundstd::upper_bound,并且可以使用双向 迭代器对任何排序范围进行操作:

// Find the last entry < key, returning end() if all entries are >= key
// last must be reachable from first, and all entries in sorted order between them
template<typename Iterator, typename Key>
Iterator lower_bound_dec(Iterator first, Iterator last, const Key &key) {
    auto it = container.lower_bound(first, last, key);
    if (it == first)
        it = last;
    else
        --it; // requires bidirectional iterators
    return it;
}

upper_bound(first, last, key) 和带有比较器的表格作为练习留给读者/任何想通过编辑获得代表的人! :)

TL/DR: 使用 lower_bound 然后递减,需要注意的是“递减”begin() 会产生 end() 表示“没有这样的条目”。

【讨论】:

    猜你喜欢
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 2014-05-03
    • 2021-09-15
    • 1970-01-01
    相关资源
    最近更新 更多