在XKCD comic 195中,使用Hilbert curve建议了互联网地址空间地图的设计,以便来自类似IP地址的项目将聚集在一起。
给定一个IP地址,如何在这样的地图上计算其2D坐标(在0到1的范围内)?
答案 0 :(得分:14)
这非常简单,因为希尔伯特曲线是分形的,也就是说,它是递归的。它通过水平和垂直平分每个方块,将其分成四个部分来工作。因此,您从左侧开始一次取两位IP地址,并使用它们来确定象限,然后继续使用接下来的两位,使用该象限而不是整个方块,依此类推,直到您拥有耗尽了地址中的所有位。
每个方格的曲线的基本形状是马蹄形的:
0 3 1 2
其中数字对应于前两位,因此确定遍历顺序。在xkcd地图中,此正方形是最高级别的遍历顺序。可能旋转和/或反射,这种形状出现在每个2x2的正方形。
确定“马蹄铁”在每个子方格中的定向方式取决于一条规则:0
方的0
角位于较大方块的角落。因此,必须按顺序遍历与0
对应的子方格
0 1 3 2
并且,查看整个前一个方块并显示四位,我们得到以下形状用于广场的下一个分区:
00 01 32 33 03 02 31 30 10 13 20 23 11 12 21 22
这就是广场总是在下一个级别划分的方式。现在,继续,只关注后两位,根据这些位的马蹄形状如何定向,定义更详细的形状,并继续进行类似的划分。
为了确定实际坐标,每两位确定实数坐标中的一位二进制精度。因此,在第一级,如果地址的前两位具有,则[0,1]
坐标中的二进制点之后的第一位(假设x
范围内的坐标)为0
值0
或1
,否则为1
。同样,如果前两位的值为y
或0
,则1
坐标中的第一位为2
。要确定是否在坐标中添加0
或1
位,您需要检查该级别的马蹄形方向。
b
后缀并将整数视为位数组,但将其更改为正确的C应该不会太难。
在代码中,pos
是方向的3位整数。前两位是方形中0
的x和y坐标,第三位指示1
是否具有与0
相同的x坐标。 pos
的初始值为011b
,表示0
的坐标为(0, 1)
,1
的坐标与0
具有相同的x坐标。 ad
是地址,被视为2位整数的n
- 元素数组,从最高位开始。
double x = 0.0, y = 0.0;
double xinc, yinc;
pos = 011b;
for (int i = 0; i < n; i++) {
switch (ad[i]) {
case 0: xinc = pos[0]; yinc = pos[1]; pos[2] = ~pos[2]; break;
case 1: xinc = pos[0] ^ ~pos[2]; yinc = pos[1] ^ pos[2]; break;
case 2: xinc = ~pos[0]; yinc = ~pos[1]; break;
case 3: xinc = pos[0] ^ pos[2]; yinc = pos[1] ^ ~pos[2];
pos = ~pos; break;
}
x += xinc / (1 << (i+1)); y += yinc / (1 << (i+1));
}
我用几个8位前缀对它进行了测试,并根据xkcd地图正确放置它们,所以我有点相信代码是正确的。
答案 1 :(得分:5)
基本上你会使用位对,MSB到LSB来分解数字。这对位告诉您位置是在左上(0)左下(1)右下(2)还是右上(3)象限,当您在数字中移动时,该比例变得更精细。
此外,您需要跟踪“方向”。这是用于您所在规模的绕组;初始绕组如上(UL,LL,LR,UR),并且根据您最终进入的象限,下一个缩小的绕组是(当前绕组旋转-90,0,0,+ 90)
所以你可以积累抵消:
假设我从0,0开始,第一对给我一个2,我将偏移量偏移到0.5,0.5。右下方的绕组与我的初始绕组相同。下一对减小了比例,因此我的调整长度为0.25。
这对是3,所以我只翻译我的x坐标,我是.75,.5。绕组现在旋转,我的下一个缩小将是(LR,LL,UL,UR)。现在规模是.125,依此类推,直到我的地址用完为止。
答案 2 :(得分:0)
我希望根据wikipedia code for a Hilbert curve,您可以跟踪当前位置(作为(x,y)坐标)并在访问n个单元格后返回该位置。那么缩放到[0..1]的位置将取决于Hilbert曲线在完成时的高度和宽度。
from turtle import left, right, forward
size = 10
def hilbert(level, angle):
if level:
right(angle)
hilbert(level - 1, -angle)
forward(size)
left(angle)
hilbert(level - 1, angle)
forward(size)
hilbert(level - 1, angle)
left(angle)
forward(size)
hilbert(level - 1, -angle)
right(angle)
不可否认,这将是一个强力解决方案,而不是封闭形式的解决方案。