C ++ Bimap Left unordered_map右排序的可变多图

时间:2016-07-13 11:27:20

标签: c++ boost data-structures stl bimap

我需要为我的项目实现以下数据结构。我有

的关系
const MyClass* 

uint64_t

对于我想要保存连接到它的计数器的每个指针,它可以随时间改变(实际上只增加)。这没问题,我可以简单地将它存储在std :: map中。问题是我需要快速访问具有最高值的指针。

这就是为什么我得出结论使用boost :: bimap。我的项目定义如下:

typedef boost::bimaps::bimap<
        boost::bimaps::unordered_set_of< const MyClass* >,
        boost::bimaps::multiset_of< uint64_t, std::greater<uint64_t> >
> MyBimap;
MyBimap bimap;

这样可以正常工作,但我是否正确,我无法修改插入一次的uint64_t?文档说multiset_of是常量,因此我不能在bimap中更改pair的值。

我该怎么办?在这个bimap中更改一个键值的正确方法是什么?或者这个问题是否有更简单的数据结构?

1 个答案:

答案 0 :(得分:0)

这是一个简单的手工解决方案。

在内部,它保存一个映射来存储由对象指针索引的计数,以及另一组多个迭代器,按其下降的计数顺序排序。

每当修改计数时,都必须重新编制索引。我已经完成了这个零碎的工作,但您可以根据要求进行批量更新。

请注意,在c ++ 17中,对于集合和映射有一个建议的splice操作,这将使重新索引非常快。

#include <map>
#include <set>
#include <vector>

struct MyClass { };


struct store
{

    std::uint64_t add_value(MyClass* p, std::uint64_t count = 0)
    {
        add_index(_map.emplace(p, count).first);
        return count;
    }

    std::uint64_t increment(MyClass* p)
    {
        auto it = _map.find(p);
        if (it == std::end(_map)) {
            // in this case, we'll create one - we could throw instead
            return add_value(p, 1);
        }
        else {
            remove_index(it);
            ++it->second;
            add_index(it);
            return it->second;
        }
    }

    std::uint64_t query(MyClass* p) const {
        auto it = _map.find(p);
        if (it == std::end(_map)) {
            // in this case, we'll create one - we could throw instead
            return 0;
        }
        else {
            return it->second;
        }
    }

    std::vector<std::pair<MyClass*, std::uint64_t>> top_n(std::size_t n)
    {
        std::vector<std::pair<MyClass*, std::uint64_t>> result;
        result.reserve(n);
        for (auto idx = _value_index.begin(), idx_end = _value_index.end() ;
             n && idx != idx_end ;
             ++idx, --n) {
            result.emplace_back((*idx)->first, (*idx)->second);
        }
        return result;
    }

private:
    using map_type = std::map<MyClass*, std::uint64_t>;
    struct by_count
    {
        bool operator()(map_type::const_iterator l, map_type::const_iterator r) const {
            // note: greater than orders by descending count
            return l->second > r->second;
        }
    };
    using value_index_type = std::multiset<map_type::iterator, by_count>;

    void add_index(map_type::iterator iter)
    {
        _value_index.emplace(iter->second, iter);
    }

    void remove_index(map_type::iterator iter)
    {
        for(auto range = _value_index.equal_range(iter);
            range.first != range.second;
            ++range.first)
        {
            if (*range.first == iter) {
                _value_index.erase(range.first);
                return;
            }
        }

    }

    map_type _map;
    value_index_type _value_index;
};