std::unordered_map - 如何随时"track"最大/最小键

std::unordered_map - how to "track" max/min key at any time

本文关键字:最大 track 何随时 unordered map std      更新时间:2023-10-16

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

我不想使用任何其他结构。我想使用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;

无法满足您的确切要求std::unordered_map是快速的(即 O(1) insertion/擦除/擦除/lookup),因为它没有订购其元素。这意味着找到最小/最大值需要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()的形式找到最小/最大值。

您可以通过使用用户定义的MyOrder功能对象添加ordered_unique索引来计算您想使用的任何标准来订购它们。小型代码示例(到处省略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::unordered_map<Key, set<Value>::iterator>将其大致以std::set<Value>的形式实现。这意味着查找和擦除都是O(1)。擦除可以是O(1),因为unordered_map::erase(value)将迭代器返回到set中,而std::set<Value>::erase(iterator)O(1)

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

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

您可以编写包装器。这样,您将获得所有插入/删除,并可以保留最小/最大值。

#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;
};