通过索引快速搜索,并将插入顺序保持在C 中

Fast search via index with keeping insertion order in C++

本文关键字:顺序 插入 索引 搜索      更新时间:2023-10-16

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

所以我首先考虑了STD :: MAP,但它不在乎插入顺序,它会根据密钥订购数据。一个我发现了BOOST :: MULTI_INDEX,该Index将保留插入顺序,并通过索引字段快速搜索数据(对于我的情况,这是ID(不是唯一!))。所以我做了这样的事情:

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计算机。

您几乎可以尝试使用boost::multi_index。问题在于,当您使用有序索引进行查找时,迭代也为。幸运的是,多指数提供了一个project机制来切换索引之间。如果我正确阅读文档:

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

我将使用与List<Item>配对的multimap<Key,List<Item>::Iterator>。我将使用地图进行查找,列表将按插入顺序保存项目。您将需要在所有插入/更新/删除方案中保持两个容器的最新时间。如果您可以在用例中阐述更好的选择。

此选项将为您提供日志(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

是的,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);
// ***