std :: unordered_map - 如何随时“跟踪”最大/最小键

时间:2014-01-22 08:53:29

标签: c++ boost c++11 unordered-map boost-multi-index

我有std::unordered_map<int, int>。 我不想使用树或其他任何其他结构导致延迟要求。 但是在任何时候我都需要知道当前的最大键和最小键。 我怎样才能做到这一点?分布不均匀,而是经常删除和插入max和min。因此,我需要比“只删除当前最大/最小值时扫描整个地图以获得新的最大值/分钟”更聪明的东西。

我不想使用任何其他结构。我想使用std::unordered_map

upd 根据答案创建了这样的结构:

struct OrderBookItem {
    int64_t price;
    int32_t lots;
};

typedef multi_index_container
    <OrderBookItem, indexed_by<

    hashed_unique<
    BOOST_MULTI_INDEX_MEMBER(OrderBookItem,int64_t,price)
    >,

    ordered_unique<
    BOOST_MULTI_INDEX_MEMBER(OrderBookItem,int64_t,price),
    std::greater<int64_t>
    >

    >> OrderBookContainer;

2 个答案:

答案 0 :(得分:7)

无法满足您的确切要求std::unordered_map速度很快(即O(1)插入/删除/查找),因为它没有对其元素进行排序。这意味着找到最小值/最大值需要O(N)

std::map支付的订购价格(插入/删除/查找(包括查找最小/最大))全部变为O(log N)

如果您不介意使用Boost,可以查看Boost.MultiIndex库。这允许您同时通过多个接口访问您的数据。它是一个极其通用和高性能的库,也可用于MRU缓存数据结构(它还结合了快速访问和订购跟踪)。

您的主std::unordered_map接口由hashed_unique索引提供,您可以在其中使用identity函数对象(由Boost.MultiIndex提供)。您的辅助界面将模仿std::set。这允许在O(1)时间内找到*begin()*rbegin()的最小/最大值。

您可以通过添加ordered_unique索引和用户定义的MyOrder函数对象来计算您想要用来订购它们的标准。小代码示例(到处省略boost::命名空间)

using MyContainer = multi_index_container<
    Item,
    indexed_by<
        hashed_unique<identity<Item>>, // O(1) erasure/lookup, O(log N) insertion
        ordered_unique<MyOrder<Item>>  // track minimum/maximum in O(log N)
    >
>;

在幕后,Boost.MultiIndex大致将std::set<Value>实现为std::unordered_map<Key, set<Value>::iterator>。这意味着查找和删除都是O(1)。擦除可以是O(1),因为unordered_map::erase(value)将迭代器返回到setstd::set<Value>::erase(iterator)O(1)

但是,插入仍为O(log N),因为您无法避免在更短的时间内找到有序序列中新插入值的等级。

std::map相比,查找/擦除成本每个元素空间开销只有几个指针

答案 1 :(得分:-1)

你可以写一个包装器。这样,您可以获得每次插入/删除并保留最小/最大值。

#pragma once

#include <unordered_map>

using std::unordered_map;

class my_unordered_map
{
public:
    void insert(int key, int value)
    {
        _map[key] = value;
        if (_max < value)
            _max = value;
        if (_min> value)
            _min = value;
    }
    int get(int key)
    {
        auto it = _map.find(key);
        if (it != _map.end())
            return it->second;
        return 0; // or some error handling here.
    }
    int getMin()
    {
        return _min;
    }
    int getMax()
    {
        return _max;
    }
    // more functionality here.
private:
    unordered_map<int, int> _map;
    int _min = 0;
    int _max = 0;
};