微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

std::map 可以在迭代器中有效地拆分为两个 std::map 吗?

如何解决std::map 可以在迭代器中有效地拆分为两个 std::map 吗?

假设我有一个包含数据的 std::map<int,std::string> myMap

1. Red
2. Blue
3. Green
5. Fuchsia
6. Mauve
9. Gamboge
10. Vermillion

还有一个 std::map<int,std::string>::iterator it 指向元素

5. Fuchsia

我想做类似(编造)的事情

std::map<int,std::string> myHead = eject(myMap,myMap.begin(),it);

这将导致 myMap 包含

5. Fuchsia
6. Mauve
9. Gamboge
10. Vermillion

myHead 包含

1. Red
2. Blue
3. Green

我可以通过做类似的事情来实现这一点

std::map<int,std::string> myHead;
myHead.insert(myMap.begin(),it);
myMap.erase(myMap.begin(),it);

但这至少在某些情况下似乎不是最理想的,例如如果我选择一个点,以至于我只是从子树上分裂出来。 (我承认我实际上并没有仔细考虑这里算法复杂性的实际细节,但是如果我们想象一个值类型复制成本非常高的情况,那么很明显,上面的一般情况下不可能是最优的.)

问题:有没有办法让 std::map 以最佳方式执行此操作,或者我是否必须编写自己的二叉搜索树来访问实现这一目标的内部结构?

解决方法

如果我们说的是渐近复杂性,对于大多数自平衡树类型,您可以在 O(log n) 时间内完成此操作,使用两个通俗称为 splitjoin 的操作。对此有广泛的Wikipedia article

您无法使用 std::map 获得这种复杂性,您需要推出自己的或第三方的自平衡树实现。如果您需要经常执行此操作,这是非常值得的。使用标准库可以获得的最佳结果是 O(n),它可能会慢很多数量级。

您可以在 C++11 中的 O(n) 中这样做:

template<class K,class T,class C,class A>
std::map<K,T,C,A> eject(
    std::map<K,A>& my_map,std::map<K,A>::iterator begin,A>::iterator end,) {
    std::map<K,A> result;
    while (begin != end) {
        auto next = std::next(begin);
        // C++11
        result.insert(result.end(),std::move(*begin));
        my_map.erase(begin);
        // C++17 (avoids move and destruct)
        // result.insert(result.end(),my_map.extract(begin));
        begin = next;
    }
    return result;
}        
,

有提取,但它对节点而不是节点范围进行操作。

而且您可以有效地组合地图。

但是没有有效的(比 O(n) 更快)基于范围的提取。

,

您可以使用move iterators,如下

int main(){
    auto my_map = std::map<int,std::string>{
        {1,"Read"s},{2,"Blue"s},{3,"Green"s},{5,"Fuchsia"s},{6,"Mauve"s},{ 9,"Gamboge"s },{10,"Vermillion"s}
    };
    auto it = my_map.begin();
    std::advance(it,3);
    auto head_map = std::map{
        std::make_move_iterator(my_map.begin()),std::make_move_iterator(it)
    };
    auto tail_map = std::map{
        std::make_move_iterator(it),std::make_move_iterator(my_map.end())
    };
    std::cout << "The Head\n";
    for (auto [key,value]: head_map){
        std::cout << key << ":" << value << " ";
    }
    std::cout << "\n\nThe Tail\n";
    for (auto [key,value]: tail_map){
        std::cout << key << ":" << value << " ";
    }
}

Demo

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。