【问题标题】:C++ a multiple indexes mapC++ 多索引映射
【发布时间】:2021-07-12 01:47:23
【问题描述】:

我正在实现一个简单的搜索系统,其中所有数据都存储在正在运行的进程的内存中。

最初,我打算使用元组的映射来实现这一点。

map<tuple<int, string, ...>, string> dict

但是,它只有在所有密钥都已知且不丢失时才有效。

例如,比如说,我有, map, value> 字典;

如果没有 key2 或 key2 是“无关”,我无法搜索地图

C++ 中是否有任何标准库或函数可以做到这一点?

非常感谢任何帮助。

【问题讨论】:

  • 不,C++ 库中没有这样的东西。由于许多基本原因,在技术上不可能做任何事情,无论是使用地图还是 C++ 库中的任何其他关联容器。您将必须设计和实现自己的容器,该容器为每个键使用单独的映射/无序映射。
  • 诚实的问题,但是您是否考虑过使用关系数据库?这将使进行任意查询变得更加容易,并且它们旨在为您处理索引和存储。
  • 不,由于要求,它不打算使用数据库。

标签: c++ dictionary


【解决方案1】:
std::map<int, std::map<string, std::map< ... , string > ... > > dict;

您可以在任何步骤“不在乎”。您必须检查那里的每一个可能性。

你可以做一个组合爆炸来做所有 n!排序,并让所有内容都指向一个共享指针或类似的东西。

这并不便宜。

在每种可能性(n!)中排列参数,然后从每个增强选项(具有最小和最大状态)的元组映射到相同的共享数据 ptr。您现在可以执行将左侧或右侧视为最不重要的排序,并使用equal_range 不关心该键。

您可以改为使用四叉树或八叉树或 n 树结构之类的东西进行攻击。这会进行多维“排序”。让它与任意键一起工作会很有趣。

【讨论】:

  • 而不是在每种可能性中排列参数,也许可以考虑使用类似 map>>, map>>, map>> 等等。那么,假设我只指定了key1和key3(没有key2),我可以搜索key1和key3映射,然后比较vector>取交集
【解决方案2】:

这是我几年前碰巧研究过的一个有趣且重要的问题:

  • 问题在于,在给定 n 个键的情况下,能够有效地查询这些键的任意子集。
  • 在数据库术语中,这可以通过创建 m 索引来解决,这样每​​个键组合都被某个索引覆盖。问题描述here:索引数为C(n,floor(n/2)),其中 C(a,b) 是二项式系数a choose b。对于 n=5,所需索引的数量为 m=10。
  • 我设计了an algorithm 来确定实际索引是什么。在 n=5 且键为 abcd的情况下>, e, 你可以使用索引(acedb),(baedc),(bdaec),(bedca),(cbaed),(cdbae),(cebad),(daceb), (decab),(eadbc)。这里的一个关键方面是索引可以用于较短的键组合。例如,(acedb) 涵盖以下内容(按字母顺序重新排列):(a),(ac),(ace),(acde),(abcde)。这就是为什么您可以仅使用 10 个索引而不是 25-1=31 来覆盖任意组合的原因。
  • 现在,Boost.MultiIndex 可用于实际指定和使用这些索引。 example 有 4 个键,如果您愿意,可以轻松扩展到 5 个键。

【讨论】:

    【解决方案3】:

    你问:

    C++ 中是否有任何标准库或函数可以做到这一点?

    这个问题的答案是

    要求有点模糊,因为您似乎有一个特定的界面。你应该定义你的接口,以及你期望它们做什么。

    find()like 函数的实现可以用多索引数据结构来实现。大致:

    • 为所有记录创建一个容器(如set)。
    • 对于每个关键字段,创建一个map,将该关键字段中的值与set 记录中的迭代器set 相关联。
    • find 方法将遍历键 maps 的集合,并计算返回的迭代器 sets 的交集。

    【讨论】:

    • 这似乎与我在上一个解决方案中刚刚回答的想法相似。也就是为每个关键字段创建一个映射
    【解决方案4】:

    不在std 中,但有boost::multi_index,它允许您将数据的任意投影指定为键,并且您可以拥有任意数量的键。

    // your keys and value
    struct Datum {
        key1_t key1;
        key2_t key2;
        key3_t key3;
        // etc ...
        value_t value;
    };
    
    namespace bmi = boost::multi_index;
    
    // some unique types
    struct Key1 {};
    struct Key2 {};
    struct Key3 {};
    struct Key1Key2 {};
    struct Key1Key2Key3 {};
    
    using Dict = boost::multi_index_container<Datum, bmi::indexed_by<
        bmi::ordered_unique<bmi::tag<Key1>, bmi::key<&Datum::key1>>, // just key 1
        bmi::ordered_unique<bmi::tag<Key2>, bmi::key<&Datum::key2>>, // just key 2
        bmi::ordered_unique<bmi::tag<Key3>, bmi::key<&Datum::key3>>, // just key 3
        bmi::ordered_unique<bmi::tag<Key1Key2>, bmi::key<&Datum::key1, &Datum::key2>>, // key 1 then key 2
        bmi::ordered_unique<bmi::tag<Key1Key2Key3>, bmi::key<&Datum::key1, &Datum::key2, &Datum::key3>>, // key 1 then key 2 then key 3
    >;
    int main() {
        Dict dict = /* stuff */
    
        key1_t key1 = /* stuff */
        key2_t key2 = /* stuff */
        key3_t key3 = /* stuff */
    
        auto it1 = dict.get<0>().find(key1); // select which by position
        auto it2 = dict.get<Key2>().find(key2); // or by the tag types 
        auto it5 = dict.get<Key1Key2Key3>().find({ key1, key2, key3 }); // multiple keys
    }
    

    【讨论】:

    • 看起来不错,但是从您的代码看来,我需要指定所有的键组合?我的意思是,如果我有 10 个(甚至更多)键,那就太多了。
    猜你喜欢
    • 2015-05-06
    • 1970-01-01
    • 2020-08-29
    • 2018-08-31
    • 1970-01-01
    • 1970-01-01
    • 2013-07-25
    • 2012-12-03
    • 2017-03-11
    相关资源
    最近更新 更多