部分多键映射的数据结构?

2024-03-10

我的数据由映射到值的键组成,如下所示:

---------------------
Key          | Value
---------------------
(0, 0, 0, 0) | a
(0, 0, 0, 1) | b
(0, 1, 0, 1) | c
(0, 1, 1, 0) | d
....

我正在寻找一种可以有效地对键执行搜索查询的数据结构,其中查询可以是完整或部分指定键。例如:

(0, 0, 0, 1) -> a
(0, *, *, *) -> [a, b, c, d]
(0, 1, *, *) -> [c, d]

The idea that I've right now is to implement this using a regular tree, similar to this: tree Leaves nodes represent the values and non-leaves nodes are parts of the key (i.e. w,x,y and z nodes are first, second, third and forth part of the key, respectively.). A simple BFS algorithm could be used to answer any query. But the problem is that this tree is growing exponentially with each new part of the key.

什么数据结构/算法更适合解决这个问题?请注意,关键部分可以是数字或字符串。


数组。对真的!您将没有空间开销,没有“指针追逐”开销,并且计算索引只需要一点位数学,而处理器在这方面确实相当擅长。

假设您获得部分密钥作为mask and bits哪里的mask通配符位为 0,其他位为 1,并且bits通配符为 0,非通配符为任意值。

收集具有与该模式匹配的键的所有项目的算法是:

int key = bits;
do {
    yield items[key];
    key = (key | mask) + 1 & ~mask | bits;
} while (key != bits);

That key = (key | mask) + 1 & ~mask | bits这部分看起来很有趣,这就是它的工作原理。

The |(按位或)使所有非通配符为 1。这可确保增量继续携带非通配符的位。添加之后,本应“固定”的位被破坏(如果进位通过它们,则为 0,否则为 1),因此必须将它们屏蔽掉(& ~mask),然后设置回正确的值(| bits)。运算符的优先级使得它基本上可以在没有括号的情况下编写。您也可以将其写为

key = (((key | mask) + 1) & (~mask)) | bits;

这适用于任何类型的模式。如果您只需要“最后 x 位是可变的”,您可以进行一些优化:

int wildcards = 0;
int invmask = ~mask;
do {
    yield items[wildcards++ | bits];
} while (wildcards & invmask);

That just runs from 0 to 2number-of-wildcards and then puts in the fixed bits in the top.

非二进制密钥

In the simplest non-binary case, the parts of the key are still some integral number of bits, that is, they range from 0 to 2n-1. You can use exactly the same code in that case, but the interpretation of the mask is different: instead of having a single 0 bit for a wildcard or a single 1 bit for a non-wildcard, it would have some other number of bits (corresponding to the width in bits of a key-part).

对于非二的幂,需要更多的技巧。问题在于,为了满足关键部分小于某个值的约束,必须比正常情况更早地生成进位。

例如,如果所有关键部分都可以是 0、1 或 2(但不能是 3),则可以执行以下操作(未测试):

int key = bits;
int increment = (0x55555555 & ~mask) + 1;
do {
    yield items[key];
    int temp = (key | mask) + increment & ~mask;
    int fix = (temp | (temp >> 1)) & 0x55555555;
    key = temp - fix | bits;
} while (key != bits);

额外的increment是 1 加上“最接近的 2 次方与关键部分最大值之差”的掩码,在本例中,每个关键部分都是 1,因此每个“槽”(槽)中都有一个 1是 2 位宽,这是在这种情况下它们可以达到的最窄宽度)。它仅在通配符位置具有那些“偏移量”。

偏移关键部分,使其最高允许值映射到“全一”,确保进位通过它们传播。然而,这意味着它们通常处于无效状态(除非它接收到进位并变为零)。那么烦人的部分就来了:必须撤消偏移only对于没有归零的关键部分。

所以有fix它计算不为零的关键部分的掩码。如果关键部分更宽,那就更烦人了,如果关键部分的尺寸不一样,那就更糟糕了。

然后最后一部分,key = temp - fix | bits,撤消偏移并将非通配符放回原位。该减法不会破坏任何内容,因为仅从至少为 1 的 2 位组中减去 1,因此进位永远不会留下关键部分。

当然,这种索引方式确实浪费了一些空间,与二次幂的情况不同,因为数组中存在您永远无法索引的“洞”。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

部分多键映射的数据结构? 的相关文章

  • 生成二叉树的所有从根到叶的分支

    抱歉 如果这是一个常见问题 但我还没有找到适合我的特定问题的答案 我正在尝试实施一个walk方法将二叉树从根节点遍历到每个叶节点 每当到达叶节点时都会生成根到叶路径 例如 遍历表示为的二叉树 a b d c 会产生 a b c a d 我的
  • 如何在文件系统中存储图像

    目前 我已将图像 最大 6MB 作为 BLOB 存储在 InnoDB 表中 随着数据大小的增长 夜间备份变得越来越慢 阻碍了正常性能 因此 二进制数据需要进入文件系统 指向文件的指针将保存在数据库中 数据具有树状关系 main site u
  • 实施二分查找有哪些陷阱? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 二分查找比看起来更难实现 虽然二分搜索的基本思想相对简单 但细节可能出人意料地棘手 Donald Knuth 新的二分搜索实现中最有可
  • 在java中使用BUBBLE SORT对二维字符串数组进行排序

    类似的问题已经被问过 但从来没有关于二维字符串数组 因此在尝试了很长时间之后我找不到我想要的 我正在尝试使用 BubbleSort 对 java 中的 2D 字符串数组进行排序 作为输入 我收到一个二维字符串数组 一个表 以及您应该排序的
  • 解开 Knuth 的结:如何重构意大利面条式代码?

    这个问题的灵感来自如何将流程图转化为实施 https stackoverflow com questions 36647765它询问如何通过算法消除goto代码中的语句 这answer https stackoverflow com a 3
  • n 或 nlog(n) 比常数时间或对数时间更好吗?

    在 Coursera 上的普林斯顿教程中 讲师解释了遇到的常见增长顺序函数 他说 线性和线性算术运行时间是 我们努力的目标 他的推理是 随着输入大小的增加 运行时间也会增加 我认为这是他犯了错误的地方 因为我之前听过他提到线性增长顺序对于高
  • 有没有时间复杂度为O(N)的排序算法?

    大多数排序算法的复杂度为 O NN 或 O NlogN 来实现结果 但是 对于特定的输入集 有些算法的复杂度为 O N 我想知道是否有一种排序算法在所有情况下都具有 O N 的复杂度 如果您只能比较 检查两个项目是否为 正在排序的值 那么您
  • Prim 的迷宫生成算法:获取相邻单元格

    我基于 Prim 算法编写了一个迷宫生成器程序 该算法是 Prim 算法的随机版本 从充满墙壁的网格开始 选择一个单元格 将其标记为迷宫的一部分 将单元格的墙壁添加到墙壁列表中 While there are walls in the li
  • 归并排序中的递归:两次递归调用

    private void mergesort int low int high line 1 if low lt high line 2 int middle low high 2 line 3 mergesort low middle l
  • 高效列出目录中的所有子目录

    请参阅迄今为止所采取的建议的编辑 我正在尝试使用 WinAPI 和 C 列出给定目录中的所有目录 文件夹 现在我的算法又慢又低效 使用 FindFirstFileEx 打开我正在搜索的文件夹 然后我查看目录中的每个文件 使用 FindNex
  • 如何计算排列? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一个关于 Java 排列的问题 Suppose I have five different elements in an arra
  • 选择一组数字以达到最小总数的算法

    给定 一组数字n 1 n 2 n 3 n x 还有一个数字M 我想找到最好的组合 n a n b n c n gt M 该组合应达到达到或超过 M 所需的最小值 没有其他组合可以提供更好的结果 将在 PHP 中执行此操作 因此可以使用 PH
  • 从 1 到 20 亿,像 (23,29) 这样相差 6 的连续素数对的数量

    如何在考虑时间复杂度的情况下从 1 到 20 亿 使用任何编程语言且不使用任何外部库 找到像 23 29 这样相差 6 的连续素数对的数量 尝试过埃拉托色尼筛 但获得连续素数是一个挑战 使用了生成器 但时间复杂度非常高 代码是 def ge
  • 生产代码中的 LRU 实现

    我有一些 C 代码 需要使用 LRU 技术实现缓存替换 目前我知道两种实现LRU缓存替换的方法 每次访问缓存数据时使用时间戳 最后比较替换时的时间戳 使用缓存项的堆栈 如果最近访问过它们 则将它们移动到顶部 因此最后底部将包含 LRU 候选
  • AStar-名称解释

    我正在寻找 AStar A 算法为何被称为 AStar 的解释 所有类似的 最短路径问题 算法通常都以其开发者的名字命名 那么 AStar 代表什么 有称为 A1 和 A2 的算法 后来证明A2是最优的 实际上也是可能的最好算法 所以他给它
  • 使用到达时间差对信号进行三边测量

    我在寻找或实现寻找信号源的算法时遇到一些麻烦 我的工作目标是找到声音发射器的位置 为了实现这一点 我使用了三个麦克风 我正在使用的技术是多点定位这是基于到达时间差 The 到达时间差使用发现每个麦克风之间互相关接收到的信号 我已经实现了算法
  • 找到一个数是素数,为什么检查到n/2更好。避免n后半部分的数字的原因是什么

    要检查一个数是否是素数 最简单的方法是尝试将这个数除以 2 到 n 如果任何操作得到余数为 0 那么我们就说给定的数不是素数 但最好只进行划分和检查直到 n 2 我知道更好的方法是直到 sqrt n 我想知道跳过后半部分的原因 假设我们是否
  • 欧拉项目 45

    我还不是一名熟练的程序员 但我认为这是一个有趣的问题 我想我应该尝试一下 三角形 五边形 六边形 数字由以下生成 公式 三角形 T n n n 1 2 1 3 6 10 15 五边形 P n n 3n 1 2 1 5 12 22 35 六角
  • 优先连接,Matlab 中的复杂网络

    大家好 我现在正在 MATLAB 中研究优先附件模型 在理解以下内容时遇到一些困难 假设我一开始有 4 个节点 连接如下 time 0 1 lt gt 2 3 lt gt 4 在下一个时间步骤中 我添加一个节点和 4 个连接 然后添加另一个
  • 压缩很多小字符串的算法?

    我正在寻找一种压缩小 ASCII 字符串的算法 它们包含大量字母 但也可以包含数字和很少的特殊字符 它们很小 平均约为 50 100 字节 最多 250 个字节 例子 Android show EditText setError above

随机推荐