计算一个点的希尔伯特值以用于希尔伯特 R-树?

Posted

技术标签:

【中文标题】计算一个点的希尔伯特值以用于希尔伯特 R-树?【英文标题】:Calculate the Hilbert value of a point for use in a Hilbert R-Tree? 【发布时间】:2010-09-11 11:56:57 【问题描述】:

我有一个应用程序,其中 Hilbert R-Tree (wikipedia) (citeseer) 似乎是一个合适的数据结构。具体来说,它需要对经历大量更新的数据集进行相当快速的空间查询。

然而,据我所知,对于这个数据结构的算法的描述甚至没有提到如何实际计算必要的希尔伯特值;这是沿Hilbert Curve 到该点的距离。

那么对于如何计算这个有什么建议吗?

【问题讨论】:

【参考方案1】:

有趣的问题!

我用谷歌搜索了一下,好消息是,我找到了 Hilbert Value 的实现。

潜在的坏消息是,它在 Haskell 中......

http://www.serpentine.com/blog/2007/01/11/two-dimensional-spatial-hashing-with-space-filling-curves/

它还提出了一个 Lebesgue 距离度量,您可以更轻松地计算。

【讨论】:

谢谢,这看起来正是我一直在努力寻找的东西(Haskell 很好:)【参考方案2】:

下面是我的java代码改编自Xian Lu和Gunther Schrack的论文“编码和解码希尔伯特顺序”中的C代码,发表在软件:实践和经验卷。 26 页 1335-46 (1996)。

希望这会有所帮助。欢迎改进!

迈克尔

/**
 * Find the Hilbert order (=vertex index) for the given grid cell 
 * coordinates.
 * @param x cell column (from 0)
 * @param y cell row (from 0)
 * @param r resolution of Hilbert curve (grid will have Math.pow(2,r) 
 * rows and cols)
 * @return Hilbert order 
 */
public static int encode(int x, int y, int r) 

    int mask = (1 << r) - 1;
    int hodd = 0;
    int heven = x ^ y;
    int notx = ~x & mask;
    int noty = ~y & mask;
    int temp = notx ^ y;

    int v0 = 0, v1 = 0;
    for (int k = 1; k < r; k++) 
        v1 = ((v1 & heven) | ((v0 ^ noty) & temp)) >> 1;
        v0 = ((v0 & (v1 ^ notx)) | (~v0 & (v1 ^ noty))) >> 1;
    
    hodd = (~v0 & (v1 ^ x)) | (v0 & (v1 ^ noty));

    return interleaveBits(hodd, heven);


/**
 * Interleave the bits from two input integer values
 * @param odd integer holding bit values for odd bit positions
 * @param even integer holding bit values for even bit positions
 * @return the integer that results from interleaving the input bits
 *
 * @todo: I'm sure there's a more elegant way of doing this !
 */
private static int interleaveBits(int odd, int even) 
    int val = 0;
    // Replaced this line with the improved code provided by Tuska
    // int n = Math.max(Integer.highestOneBit(odd), Integer.highestOneBit(even));
    int max = Math.max(odd, even);
    int n = 0;
    while (max > 0) 
        n++;
        max >>= 1;
    

    for (int i = 0; i < n; i++) 
        int bitMask = 1 << i;
        int a = (even & bitMask) > 0 ? (1 << (2*i)) : 0;
        int b = (odd & bitMask) > 0 ? (1 << (2*i+1)) : 0;
        val += a + b;
    

    return val;

【讨论】:

这只是二维的,对吧?任意维度会很酷。 是的,它是二维的。有关处理更高维度的参考,请参阅@Entong(下)的帖子 这个实现只适用于 r 如果我的坐标是双精度值怎么办?【参考方案3】:

见uzaygezen。

【讨论】:

【参考方案4】:

上面的代码和 java 代码适用于 2D 数据点。但对于更高的维度,你可能需要查看 Jonathan Lawder 的论文:J.K.Lawder. Calculation of Mappings Between One and n-dimensional Values Using the Hilbert Space-filling Curve.

【讨论】:

【参考方案5】:

我想出了一种更有效的方式来交错位。它可以在Stanford Graphics Website 找到。我包含了一个我创建的版本,它可以将两个 32 位整数交织成一个 64 位长。

public static long spreadBits32(int y) 
    long[] B = new long[] 
        0x5555555555555555L, 
        0x3333333333333333L,
        0x0f0f0f0f0f0f0f0fL,
        0x00ff00ff00ff00ffL,
        0x0000ffff0000ffffL,
        0x00000000ffffffffL
    ;

    int[] S = new int[]  1, 2, 4, 8, 16, 32 ;
    long x = y;

    x = (x | (x << S[5])) & B[5];
    x = (x | (x << S[4])) & B[4];
    x = (x | (x << S[3])) & B[3];
    x = (x | (x << S[2])) & B[2];
    x = (x | (x << S[1])) & B[1];
    x = (x | (x << S[0])) & B[0];
    return x;


public static long interleave64(int x, int y) 
    return spreadBits32(x) | (spreadBits32(y) << 1);

显然,BS 局部变量应该是类常量,但为了简单起见,保留这种方式。

【讨论】:

在原始版本中,它们不会对 16 位输入进行 16 位移位,因此您不需要在扩展版本中对 32 位输入进行 32 位移位。如果你左移 32 位,然后屏蔽掉高 32 位,你将总是留下零,所以这个第一个移位和屏蔽操作实际上是 x=x|0,一个无操作。【参考方案6】:

迈克尔,

感谢您的 Java 代码!我对其进行了测试,它似乎工作正常,但我注意到位交错函数在递归级别 7 处溢出(至少在我的测试中,但我使用了 long 值),因为“n”值是使用最高 OneBit( )-函数,它返回值而不是最高一位的位置;所以循环不必要地进行了许多交错。

我只是把它改成下面的sn-p,之后就正常了。

int max = Math.max(奇数,偶数); 诠释 n = 0; 而(最大> 0) n++; 最大值 >>= 1;

【讨论】:

谢谢@Tuska。我(很晚)编辑了代码以包含您的修复。【参考方案7】:

如果您需要具有快速删除/插入功能的空间索引,请查看 PH-tree。它部分基于四叉树,但速度更快,空间效率更高。在内部,它使用 Z 曲线,其空间特性比 H 曲线稍差,但 更容易计算。

论文:http://www.globis.ethz.ch/script/publication/download?docid=699

Java 实现:http://globis.ethz.ch/files/2014/11/ph-tree-2014-11-10.zip

另一个选项是 X-tree,这里也有: https://code.google.com/p/xxl/

【讨论】:

【参考方案8】:

建议:空间查询的一种简单高效的数据结构是多维二叉树。

在传统的二叉树中,只有一个“判别式”;用于确定您是选择左分支还是右分支的值。这可以认为是一维的情况。

在多维二叉树中,有多个判别式;连续级别使用不同的判别式。例如,对于二维空间数据,您可以使用 X 和 Y 坐标作为判别式。连续级别将使用 X、Y、X、Y...

对于空间查询(例如查找矩形内的所有节点),您从根开始对树进行深度优先搜索,并在每个级别使用判别式来避免向下搜索不包含节点的分支给定矩形。

这使您可以在每个级别将搜索空间减半,从而非常有效地在海量数据集中查找小区域。 (顺便说一句,这种数据结构对于部分匹配查询也很有用,即省略一个或多个判别式的查询。您只需在省略判别式的级别上搜索两个分支。)

关于这种数据结构的一篇好论文:http://portal.acm.org/citation.cfm?id=361007 这篇文章有很好的图表和算法描述:http://en.wikipedia.org/wiki/Kd-tree

【讨论】:

kd-tree 是一个漂亮而简单的结构,我认为它在 5 维和少于 1.000.000 个条目左右之前都可以正常工作。正如我刚刚在上面发布的那样,对于更多数据和更多维度,还有其他结构,例如 PH-tree、X-tree 等,它们的扩展性更好。

以上是关于计算一个点的希尔伯特值以用于希尔伯特 R-树?的主要内容,如果未能解决你的问题,请参考以下文章

是否有用于增量生成希尔伯特点曲线的恒定时间算法?

希尔伯特按分治算法排序?

B+树概念学习

将希尔伯特值映射到 3D 点

克里斯汉密尔顿的紧凑希尔伯特代码 - 计算紧凑希尔伯特指数

javascript实现插入排序(直接插入排序和希尔排序)