【问题标题】:Search with a mask使用蒙版搜索
【发布时间】:2011-09-28 20:32:46
【问题描述】:

有大量具有以下类型的条目:

typedef struct {
    int value;
    int mask;
    int otherData;
} Entry;

我想尽快根据提供的int key; 在这个数组中找到一个条目。需要输入以确保(key & mask) == value

这样的数组组织最好的方式是什么,对应的算法是什么处理呢?

编辑:对数组组织没有限制;它是静态的,可以在查找之前准备好。 valuemask 可以有任意值。

Edit2:valuemask 可能有任意值,但数组中的条目数约为 10000。因此,可以提前计算某些“模式”。

查找次数很大。

【问题讨论】:

  • 是否保证给定键的数组中只有一个条目?
  • 对key和mask有什么限制吗?没有某种限制,只有线性搜索才有意义
  • 补充:阵列组织没有限制。因此,例如可以对其进行排序。
    找到第一个适用的条目就足够了
  • 请添加一些额外的约束或告诉我们是否没有任何约束。您是否使用了一组有限的掩码?您是否经常搜索相同的面具?找到匹配元素的概率高吗? ...
  • 从数组中丢弃任何不符合(value & mask) == value 的条目开始,因为它们永远不会匹配。

标签: c++ c algorithm search mask


【解决方案1】:

如果掩码中的零位数量很少,您可以为掩码中的每个“无关”位复制条目。例如,如果value=0mask=0xfffe,那么您将在表中为key=0key=1 输入一个条目。对于value=0mask=0xfeef,在表中输入4 个条目:key=0x0000key=0x0010key=0x0100key=0x0110。现在您可以对条目进行排序并使用二分搜索,或者使用二分搜索结构,例如std::map

【讨论】:

    【解决方案2】:

    每个位都是独立的,因此在预处理阶段 [*] 您可以将每个条目分类 32 次(或者您的 int 有多大)次。每个分类存储2个集合:当key为0时匹配到那个位,当key为1时匹配到。

    也就是说,如果该位的 value == 1 和 mask == 0,则该分类根本不会存储该条目,因为它不匹配 key 的任何值(实际上,无论你使用什么方案,这样的条目应该在任何预处理阶段被删除,所以 no 分类应该存储一个条目,即使有一点是这样的)。如果两个都为 0,则存储到两个集合中。否则存储到两个集合之一。

    然后,给定您的密钥,您想找到 32 个集合的快速交集。

    根据原始数组的大小,存储每个集合的最佳方式可能是一个巨大的位数组,指示数组中的每个条目是否在集合中。然后可以一次一个字地找到交集 - & 共 32 个字,每个位数组一个字。如果结果为 0,请继续。如果结果为非 0,则您有一个匹配项,结果中设置的位会告诉您哪个条目是匹配项。当然,这在数组的大小上仍然是线性的,事实上,您正在执行 31 个& 操作来检查 32 个条目是否匹配,这与通过原始数组进行简单的线性搜索大致相同。但是比较和分支较少,而且您查看的数据压缩程度更高,因此您可能会获得更好的性能。

    或者可能有更好的方法来做交叉口。

    如果键倾向于被重复使用,那么您应该将查找结果缓存在从键到条目的映射中。如果可能的键数量相当少(也就是说,如果可能的输入明显少于 2^32 个键,并且/或者您有大量可用内存),那么您的预处理阶段可能只是:

    1. 依次获取每个条目
    2. 找出匹配的可能键
    3. 将其添加到这些键的映射中

    [*] 如果不进行任何预处理,显然您所能做的就是检查每个数组成员,直到找到匹配项或检查完所有内容。

    【讨论】:

    • 您也不需要将 32 个集合划分为每个密钥位 - 您可以对密钥位进行分组。例如,如果将密钥位分组为 2,则每组 2 个密钥位对应 4 个集合,因此只需计算 16 个集合的交集。将密钥位分组为 8 可能是最好的权衡 - 您总共有 1024 个集合,密钥的每个字节对应选择 256 个集合中的一个,然后您计算 4 个集合的交集。
    【解决方案3】:

    如果mask 对于每个条目任意变化,我看不到太多 替代线性搜索。如果存在重大限制 mask,这样只有几个值是可能的,最好是 对mask 的每个值使用某种map,进行线性搜索 找到包含您要查找的值的第一个 map。 或者,如果masks 只涉及几位,则可能值得 使用multimap,按value 排序,并用and 屏蔽所有 masks,并以 key 为索引处理相同,然后是线性 使用完整的key 进行搜索以找到完全匹配的内容。

    【讨论】:

      【解决方案4】:
      • 如果您有一个条目键映射,那么这将非常容易。

      • 如果您的数组是按键排序的,那么您可以通过一些小的努力进行字典二分搜索。 [实际上,也许不是!]

      • 事实上,您只需要遍历数组,直到找到所需的内容。也就是从头到尾迭代,找到就停止。

      顺便说一句,这是一个很好的例子,说明数据结构的选择如何影响算法的可用性。如果你一开始就选择了错误的数据结构,你就不能只用算法来解决问题!

      【讨论】:

      • 我无法关注你.. 这应该如何使用像 b101 这样的位掩码?
      • @yi_H:您知道如何进行比较,因为您在问题中向我们展示了!依次将比较应用到每个数组元素,直到它显示非常成功
      • 那是 Serge.. 我问你字典二进制搜索如何使用这样的位掩码
      • @yi_H:哦,对不起;把你误认为是那里的 OP。事后看来,也许二分搜索并不那么容易。
      【解决方案5】:

      线性搜索当然可以,但如果您需要使用相同键进行多次查找,您可以尝试先根据(key & mask) 对范围进行排序。如果您只有几个固定键,您可以尝试使用boost.multi_index,每个键值都有一个索引。

      【讨论】:

        【解决方案6】:

        由于您没有额外的信息(例如,数组已排序),您需要线性搜索 - 遍历数组并检查条件 - 伪代码:

        for( size_t index = 0; index < arraySize; index++ ) {
           if( ( array[index].mask & key ) == array[index].value ) ) {
              return index;
           }
        }
        return -1;
        

        【讨论】:

          猜你喜欢
          • 2020-05-13
          • 2012-12-26
          • 1970-01-01
          • 2022-11-23
          • 1970-01-01
          • 2012-03-24
          • 2016-07-07
          • 2011-01-04
          • 1970-01-01
          相关资源
          最近更新 更多