【问题标题】:Fastest data structure or algorithm for fast lookup on 2 keys用于快速查找 2 个键的最快数据结构或算法
【发布时间】:2014-10-21 05:44:29
【问题描述】:

在我的应用程序中,我存储了一组包含 2 个整数引用值的数据结构。

  • 内部引用 - 表示数据库中的对象。
  • 外部引用 - 外部世界如何引用对象。 (他们不能使用相同的值)。

我正在使用带有内部引用作为键的 std::map ,但这给我留下了一个问题,如果我必须通过外部引用查找,我必须潜在地遍历整个地图以找到正确的条目。由于此列表可能包含数千个条目,因此考虑起来很痛苦。

下面的代码是一个简单的例子。

#include <iostream>
#include <map>

class MyData
{
    public:
    MyData(int internal_id, int external_id)
        : internal_id_(internal_id), external_id_(external_id) 
    {}
    int internal_id_;
    int external_id_;
    /* more data members ... */
};

int main(int argc, char** argv)
{
    std::map<int, MyData*> datamap;

    /*
        Build the map structure with arbitrary values.
    */
    for(int i = 0; i < 100; ++i)
    {
        MyData* md = new MyData(i, (100 - i));
        std::cout << md->internal_id_ << " " << md->external_id_ << std::endl; 
        datamap.insert(std::make_pair(i, md));
    }

    /*
        Find with internal id 50 Cheap lookup O(log N) (I think)

    */
    std::map<int, MyData*>::iterator it1;
    if((it1 = datamap.find(50)) != datamap.end())
    {
        std::cout << "Found Mydata with internal id 50 external id is " << it1->second->external_id_ << std::endl;
    }

    /* 
        Find with external id 35. Expensive lookup O(N)
    */
    std::map<int, MyData*>::iterator it2;

    for(it2 = datamap.begin(); it2 != datamap.end(); ++it2)
    {
        if(it2->second->external_id_ == 35)
        {
            std::cout << "Found with external id 35 internal id is " << it2->second->internal_id_ << std::endl;
            break;
        }
    }

    /* remove from map and clean up allocated MyData objects ... */
}

我可以采取哪种方法来改进外部参考的查找?

我考虑过以下选项。

  • 2 个映射都指向同一个事物,但键入不同的值。
  • 一个简单的数据库(sqlite)。也许可以,但可能有点矫枉过正。
  • 维护另一个映射,将外部参考映射到内部参考。

其中第 3 个选项似乎是最理智的。有没有更好的选择?

【问题讨论】:

  • this is painful to consider 为什么要考虑而不是实际测量?
  • 为什么需要两个 id?谁决定他们?即 35 和 50 是从哪里来的?用户等?
  • 一个是指数据库中的对象(长期建立的系统不是我创建的),这就是我在从系统接收有关它的更新时识别该对象的方式。另一个是客户端应用程序如何从外部接口引用对象。
  • @PaulRooney 在那种情况下 3 可能是明智的,只是为了理智。

标签: c++ data-structures


【解决方案1】:
  • 如果其中任何一个键几乎是连续的(即通常使用连续的值,中间没有太多未使用的数字),那么数组 - 直接由该 id 索引 - 是最佳的,否则
  • 如果您要创建数字更高的新密钥,则可以将push_back 转换为vector 并使用std::binary_search 甚至interpolation search,否则
  • unordered_mapmap

与往常一样 - 要知道什么是最快的,请实施替代方案并进行衡量(但我已按照预期的性能顺序将它们列在上面)。

如果使用第一个或第三个选项,您可能希望将两个映射放入一个类中,以便在两者之间始终如一地进行插入和删除,并且仅在不需要时删除链接到的对象(您也可以使用共享来管理这个指针,但可能有点重量级 - 取决于您的需求。

【讨论】:

  • 实际上,如果您需要删除内部 id,您可以随时通过内部 id 查找,并从 MyData 获取外部 id。
  • @user3125280 好点 - 不能说我真的费心阅读代码,但它在 MyData 中,所以它挂在一起。干杯。
  • 谢谢大家,我会考虑这些答案并相应地支持/接受。
【解决方案2】:

只需将外部 id 映射到内部 id 就足够了。这样,在给定任何一个 id 的情况下,总是可以找到一个对象。如果您需要通过一个键删除某些内容,则找到它,确定它是另一个键,然后删除它及其外部键条目。

(这样您就不必更改现有的查找代码,只需添加新地图)

【讨论】:

    猜你喜欢
    • 2014-06-23
    • 1970-01-01
    • 1970-01-01
    • 2011-04-09
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 2011-02-02
    • 1970-01-01
    相关资源
    最近更新 更多