【问题标题】:Fast search via index with keeping insertion order in C++通过索引快速搜索并保持 C++ 中的插入顺序
【发布时间】:2014-03-03 16:56:19
【问题描述】:

我需要一个能够快速搜索超过 100 万个项目并保持插入顺序的容器。

所以我首先想到了 std::map 但它并不关心插入顺序,它根据键对数据进行排序。 我发现 boost::multi_index 应该保留插入顺序并通过索引字段(在我的情况下是 id (not unique!))快速搜索数据。所以我做了这样的事情:

struct myData
{
    unsigned long id;
    unsigned long insertionOrder;

    myData (){};
    myData (unsigned long id_,unsigned long insertionOrder_):id(id_), insertionOrder(insertionOrder _)){}
    ~ myData (){};
};


typedef multi_index_container<
    myData, 
        indexed_by<    
            random_access<>,  // keep insertion order
            ordered_non_unique< member< myData, unsigned long, & myData::id> >
        > 
> myDataContainerType;

我可以毫无问题地将数据推送到容器中。假设我将 5 个项目插入到我的容器中,例如:

myDataContainer.push_back(myData(1002, 1));
myDataContainer.push_back(myData(1001, 2));
myDataContainer.push_back(myData(1005, 3));
myDataContainer.push_back(myData(1003, 4));
myDataContainer.push_back(myData(1000, 5));

问题是当我在容器中搜索项目 “1001” 时,iterator++ 返回 "1002" 并且 iterator— 返回 "1000"。所以它似乎并不关心插入顺序,也根据索引值对数据进行排序。

我希望 iterator++ : “1002”iterator-- : “1005” 的结果。我的意思是根据插入顺序的数据。

我做错了吗?如何通过索引值进行快速搜索并根据插入顺序检索数据。

我正在使用 Visual Studio 2008、Visual C++、Win 7 x64 计算机。

【问题讨论】:

    标签: c++ search boost containers boost-multi-index


    【解决方案1】:

    您的boost::multi_index 尝试已经快到了。问题是,当您使用有序索引进行查找时,迭代 是有序的。幸运的是,多索引提供了project 机制来在索引之间切换。如果我正确阅读了文档:

    auto ordered_iter = myMap.find(1001);
    auto iter = boost::multi_index::project<0>(ordered_iter);
    

    【讨论】:

    • 我不知道那种方法。我一定会试试这个。但问题是 ut 是否适用于 random_access?还是我必须实现另一个 orderd_unique 索引?
    • 它应该适用于multi_index提供的任何索引类型。
    【解决方案2】:

    我会使用 multimap&lt;Key,List&lt;Item&gt;::Iterator&gt;List&lt;Item&gt; 配对。我将使用地图进行查找,列表将按插入顺序保存项目。您需要在所有插入/更新/删除方案中使两个容器保持最新。如果您可以详细说明您的用例,可能会有更好的选择。

    此选项将为您提供 log(n) 查找,同时仍允许恒定时间删除索引和项目。这类似于我过去实现 LRU 缓存的方式。

    因问题而编辑

    typedef list<myData> DataLst;
    typedef DataLst::iterator LstIter; 
    typedef multimap<unsigned long, LstIter> mpType; 
    
    mpType BuildIndex(DataLst &lst)
    {
        mpType ret; 
        for (auto Item = begin(lst); Item != end(lst); Item++)
        {       
            ret.insert(make_pair(Item->id,Item));
        }
        return ret; 
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        DataLst myDataContainer; 
        myDataContainer.push_back(myData(1002, 1));
        myDataContainer.push_back(myData(1001, 2));
        myDataContainer.push_back(myData(1005, 3));
        myDataContainer.push_back(myData(1003, 4));
        myDataContainer.push_back(myData(1000, 5));
    
        auto myMap = BuildIndex(myDataContainer);
        auto iter = myMap.find(1001);
        cout << "The iter insert  = " << iter->second->insertionOrder << endl;
        cout << "The iter insert after = " <<  std::next(iter->second)->insertionOrder << endl;
        cout << "The iter insert before = " << std::prev(iter->second)->insertionOrder << endl;
        string foo; 
        cin >> foo; 
    }
    

    输出

    The iter insert  = 2
    The iter insert after = 3
    The iter insert before = 1
    

    【讨论】:

    • 感谢您的回答,但您能否提供一些具体的代码示例来说明您的意思?
    • 如果它不能与 multi_index 一起使用,我会尝试那个,真的很感谢。
    【解决方案3】:

    是的,Mark B 提供的内容完全正确。我只是想提交正确的语法,以便将来可能的访问者受益。

    我创建了一个 typedef:

    typedef myDataContainerType::nth_index<1>::type myDataContainerType_by_id;
    
    myDataContainerType myDataContainer;
    

    以及根据id查找数据并将索引更改为插入顺序的语法:

    myDataContainerType_by_id& idIndex = myContainer.get<1>();
    myContainerType_by_id::iterator itId = idIndex.find(fId);
    
    if (itId == idIndex.end())
        return 0;
    
    myDataContainerType::const_iterator itInsertionOrder = myDataContainer.project<0>(itId);
    
    // *** Alternative way to change index which works as well
    myDataContainerType::const_iterator itInsertionOrder2 = myDataContainer.iterator_to(*itId);
    // ***
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-10
      • 1970-01-01
      相关资源
      最近更新 更多