用std::set替换std::map并按索引搜索

Replacing std::map with std::set and search by index

本文关键字:std 索引 搜索 替换 set map      更新时间:2023-10-16

假设我们有一个具有较大对象和索引值的map。索引值也是大对象的一部分。

我想知道的是是否可以用set代替map,提取索引值。

创建一个set是相当容易的,它通过提取索引值来对比较两个较大对象的函子进行排序。

剩下的搜索索引值,这是不支持默认在set,我认为。

我正在考虑使用std::find_if,但我相信线性搜索,忽略了我们已经设置的事实。

然后我想到使用std::binary_search与比较较大对象和值的函子,但我认为它在这种情况下不起作用,因为它不会利用结构,并且会使用遍历,因为它没有随机访问迭代器。这是正确的吗?或者在set上是否有正确处理此调用的重载?

然后最后我在考虑使用boost::containter::flat_set,因为这有一个潜在的向量,因此大概应该能够很好地与std::binary_search一起工作?

但是也许有一种更简单的方法来做到这一点?

在你回答之前,只是使用一个地图,地图应该被使用-我实际上是使用一个矢量,手动排序(好std::lower_bound),并考虑用boost::containter::flat_set代替它,但似乎不容易做到这一点,所以我可能只是坚持与向量。

c++ 14将引入按键查找的功能,而不需要构造整个存储对象。可以这样使用:

#include <set>
#include <iostream>
struct StringRef {
    StringRef(const std::string& s):x(&s[0]) { }
    StringRef(const char *s):x(s) { std::cout << "works: " << s << std::endl; }
    const char *x;    
};
struct Object {
    long long data;
    std::size_t index;
};
struct ObjectIndexer {
    ObjectIndexer(Object const& o) : index(o.index) {}
    ObjectIndexer(std::size_t index) : index(index) {}
    std::size_t index;
};
struct ObjComp {
    bool operator()(ObjectIndexer a, ObjectIndexer b) const { 
        return a.index < b.index; 
    }
    typedef void is_transparent; //Allows the comparison with non-Object types.
};
int main() {
    std::set<Object, ObjComp> stuff;
    stuff.insert(Object{135, 1});
    std::cout << stuff.find(ObjectIndexer(1))->data << "n";
}

更一般地说,这些有多种方法索引数据的问题可以使用Boost.MultiIndex来解决。

使用boost::intrusive::set,可以直接利用对象的索引值。它的find(const KeyType & key, KeyValueCompare comp)函数具有对数复杂度。也有其他基于伸展树、AVL树、替罪羊树等的集合类型,它们可能会根据您的需求表现得更好。

如果在包含的对象类型中添加以下内容:

  • 小于只比较对象索引的操作符
  • 只比较对象索引的相等操作符
  • 一个构造函数,它接受你的索引类型,并使用索引的值初始化一个虚拟对象

然后你可以传递你的索引类型给find, lower_bound, equal_range等…它会按照你想要的方式运行。当您将索引传递给set的(或flat_set的)查找方法时,它将构造一个包含类型的虚拟对象以用于比较。

现在如果你的对象真的很大,或者构造起来很昂贵,这可能不是你想要的方式。