来自中心的3d数组遍历

时间:2016-05-13 15:36:08

标签: arrays algorithm 3d gpu

我正在尝试为具有统一维度n的3d数组找到遍历顺序。因此,遍历顺序应按其到立方体中心的距离递增(具有相等索引的单元格的顺序是任意的) 。 2d阵列的示例:

7 4 8
3 0 1
6 2 5

这基本上是Manhattan metric中的距离:

2 1 2
1 0 1
2 1 2

遍历相对于原点的相对坐标:

[ 0, 0]
[ 1, 0]
[ 0,-1]
[-1, 0]
[ 0, 1]
[ 1,-1]
[-1,-1]
[-1, 1]
[ 1, 1]

我知道解决这个问题的一些方法,例如预先计算所有索引并根据它们与原点的距离对它们进行排序。但是,由于此算法旨在在 GPU 上执行,因此存在一些限制:

  1. 没有递归(我知道解析递归的可能性 迭代算法 - 维护堆栈不是一个 在我的经验中适合的解决方案)
  2. 无离线计算(=计算CPU并将结果传输到GPU)。解决方案需要像以下一样灵活 可能
  3. 在搜索解决方案时,我偶然发现了这个问题,这正是我倾向于解决的问题,虽然包含了一个不符合指定要求的树结构,但已接受的答案:3D Array Traversal in Different Order

    我还想到了一种使用球面坐标创建索引的方法,遗憾的是这种方法不会产生正确的顺序。为3d数组生成给定遍历顺序的适当算法是什么?

    编辑:Stormwind为给定的问题提供了一个很好的替代描述:“[问题]实际上是关于将寻址从一个空间转换到另一个空间。在1维和2维之间转换很简单,就像1,2,3,......到(1,1),(1,2)(2,1)......但这更像是从升序的1维(或至少是正方形)转换为“上升的八面体分层“空间,当”上升“意味着”最内层第一“,此外还有每个层面上现有的(尽管是任意的)递增顺序。”

10 个答案:

答案 0 :(得分:7)

在思考了一段时间之后,我想出了一个想法,将3d数组表示为一系列带有方向的节点:+i-i+j,{{ 1}},-j+k

方法

对于二维数组,只有三个规则就足够了:

  1. 每个节点上的每次迭代都沿着它的轴向它移动,即节点-k将增加第二个索引,节点+j将减少第一个索引。
  2. 有两种节点:-iMain。主轴有一个索引Secondary。对0 Maini轴节点(我称之为jI)的每次迭代都会产生J节点顺时针旋转90度:
    • Secondary
    • +I -> -j
    • -J -> -i
    • -I -> +j
  3. 每个节点都有生命周期,每次迭代都会减少。对于+J -> +i的奇数值,节点的生命周期等于(n-1)/2(对于偶数值,请参见下面的代码)。在生命周期变为0之后,应该删除节点。
  4. 要启用第三维,应该应用另一条规则:

    1. 沿n轴方向(此处为深度)的第三类节点在每次迭代中生成kI轴的集合:
      • J
      • +K -> +I, -J, -I, +J
    2. 以下是它的外观:

      3D array

      通过这种方法,元素将按照Manhattan distance自动排序,如Arturo Menchaca解决方案。

      实施

      这是我所描述的python代码。有很多改进的空间,这只是一个概念证明。它没有排序,没有递归,我也没有看到任何离线计算。 它还包含一些测试。 Run

      -K -> +I, -J, -I, +J

      简化实施

      用于存储索引的助手类:

      NO = ( 0, 0, 0, 2, 0)
      Pi = (+1, 0, 0, 0, 0)
      PI = (+1, 0, 0, 0, 1)
      Pj = ( 0,+1, 0, 0, 0)
      PJ = ( 0,+1, 0, 0, 1)
      PK = ( 0, 0,+1, 0, 2)
      Mi = (-1, 0, 0, 1, 0)
      MI = (-1, 0, 0, 1, 1)
      Mj = ( 0,-1, 0, 1, 0)
      MJ = ( 0,-1, 0, 1, 1)
      MK = ( 0, 0,-1, 1, 2)
      #      i  j  k  ^  ^
      #               |  Id for comparison
      #               Lifetime index
      
      PRODUCE = {
          PI: [ Mj ], # +I -> -j
          MJ: [ Mi ], # -J -> -i
          MI: [ Pj ], # -I -> +j
          PJ: [ Pi ], # +J -> +i
          NO: [ NO ],
          Pi: [ NO ],
          Pj: [ NO ],
          Mi: [ NO ],
          Mj: [ NO ],
          PK: [ PI, MI, PJ, MJ ], # +K -> +I, -J, -I, +J
          MK: [ PI, MI, PJ, MJ ], # -K -> +I, -J, -I, +J
      }
      
      
      class Index:
          LastDistance = 0
          NumberOfVisits = 0
          MinIndex = 0
          MaxIndex = 0
          def __init__(self, i, j, k, lifetime, direction):
              self.globalLifetime = lifetime
              self.direction = direction
      
              # Assign parent's position
              self.i = i
              self.j = j
              self.k = k
      
              # Step away from parent
              self.lifetime = lifetime[direction[3]]
              self.step()
      
          def isLive(self):
              return self.lifetime > 0
      
          def visit(self):
              Index.NumberOfVisits += 1
              distance = self.distance()
              if distance < Index.LastDistance:
                 raise NameError("Order is not preserved")
              Index.LastDistance = distance
              Index.MinIndex = min(self.i, Index.MinIndex)
              Index.MinIndex = min(self.j, Index.MinIndex)
              Index.MinIndex = min(self.k, Index.MinIndex)
              Index.MaxIndex = max(self.i, Index.MaxIndex)
              Index.MaxIndex = max(self.j, Index.MaxIndex)
              Index.MaxIndex = max(self.k, Index.MaxIndex)
              print("[{}, {}, {}]".format(self.i, self.j, self.k))
      
          def step(self):
              # Move in your direction
              self.i += self.direction[0]
              self.j += self.direction[1]
              self.k += self.direction[2]
      
          def iterate(self):
              self.lifetime -= 1
      
          def produce(self, result):
              for direction in PRODUCE[self.direction]:
                  self.create(direction, result)
      
          def create(self, direction, result):
              index = Index(self.i, self.j, self.k, self.globalLifetime, direction)
              if index.isLive():
                  result.append(index)
      
          def distance(self):
              # Manhattan Distance
              return abs(self.i) + abs(self.j) + abs(self.k)
      
      def Traverse(N):
          TotalNumber = N*N*N
          halfA = halfB = (N-1)/2
          if N % 2 == 0:
              halfA = N/2
              halfB = N/2-1
      
          MinIndex = -min(halfB, halfA)
          MaxIndex = max(halfB, halfA)
      
          lifetime = (halfA, halfB, 0)
      
          SecondaryNodes = []
          MainNodes = []
          KNodes = []
      
          # visit center
          center = Index(0, 0, 0, lifetime, NO)
          center.visit()
      
          center.create(PI, MainNodes)
          center.create(MI, MainNodes)
          center.create(PJ, MainNodes)
          center.create(MJ, MainNodes)
          center.create(PK, KNodes)
          center.create(MK, KNodes)
      
          while len(SecondaryNodes) + len(MainNodes) + len(KNodes) > 0:
      
              # First - visit all side nodes
              temp = []
              for m in SecondaryNodes:
                  m.visit()
                  m.step()
                  m.iterate()
                  # Save node only if it is alive
                  if m.isLive():
                      temp.append(m)
      
              SecondaryNodes = temp
      
              # Second - visit all main nodes as they may produce secondary nodes
              temp = []
              for m in MainNodes:
                  m.visit() # 1 - Visit
                  m.produce(SecondaryNodes) # 2 - Produce second
                  m.step() # 3 - Step 
                  m.iterate() # 4 - Lose a life
                  if m.isLive():
                      temp.append(m)
      
              MainNodes = temp
      
              # Third - visit all K nodes as they may produce main nodes
              temp = []
              for m in KNodes:
                  m.visit()
                  m.produce(MainNodes)
                  m.step()
                  m.iterate()
                  if m.isLive():
                      temp.append(m)
      
              KNodes = temp
          if TotalNumber != Index.NumberOfVisits:
              raise NameError("Number of visited elements does not match {}/{}".format(Index.NumberOfVisits, TotalNumber))
          if MinIndex != Index.MinIndex:
              raise NameError("Minimal index is out of bounds {}/{}".format(Index.MinIndex, MinIndex))
          if MaxIndex != Index.MaxIndex:
              raise NameError("Maximal index is out of bounds {}/{}".format(Index.MaxIndex, MaxIndex))
      
      Traverse(6)
      

      以正确方向迭代class Index: def __init__(self, i, j, k, lifetime): self.i = i self.j = j self.k = k self.lifetime = lifetime def visit(self): print("[{}, {}, {}]".format(self.i, self.j, self.k)) 个节点的函数集:

      Main

      迭代第三维def StepMainPlusI(mainPlusI, minusJ, lifetime): result = [] for m in mainPlusI: if lifetime > 0: minusJ.append(Index(m.i, m.j-1, m.k, lifetime)) m.lifetime -= 1 m.i += 1 if m.lifetime > 0: result.append(m) return result def StepMainMinusJ(mainMinusJ, minusI, lifetime): result = [] for m in mainMinusJ: if lifetime > 0: minusI.append(Index(m.i-1, m.j, m.k, lifetime)) m.lifetime -= 1 m.j -= 1 if m.lifetime > 0: result.append(m) return result def StepMainMinusI(mainMinusI, plusJ, lifetime): result = [] for m in mainMinusI: if lifetime > 0: plusJ.append(Index(m.i, m.j+1, m.k, lifetime)) m.lifetime -= 1 m.i -= 1 if m.lifetime > 0: result.append(m) return result def StepMainPlusJ(mainPlusJ, plusI, lifetime): result = [] for m in mainPlusJ: if lifetime > 0: plusI.append(Index(m.i+1, m.j, m.k, lifetime)) m.lifetime -= 1 m.j += 1 if m.lifetime > 0: result.append(m) return result 节点的函数集:

      K

      def StepMainPlusK(mainPlusK, mainPlusI, mainMinusI, mainPlusJ, mainMinusJ, lifetimeA, lifetimeB): result = [] for m in mainPlusK: if lifetimeA > 0: mainPlusI.append(Index(+1, 0, m.k, lifetimeA)) mainPlusJ.append(Index(0, +1, m.k, lifetimeA)) if lifetimeB > 0: mainMinusI.append(Index(-1, 0, m.k, lifetimeB)) mainMinusJ.append(Index(0, -1, m.k, lifetimeB)) m.lifetime -= 1 m.k += 1 if m.lifetime > 0: result.append(m) return result def StepMainMinusK(mainMinusK, mainPlusI, mainMinusI, mainPlusJ, mainMinusJ, lifetimeA, lifetimeB): result = [] for m in mainMinusK: if lifetimeA > 0: mainPlusI.append(Index(+1, 0, m.k, lifetimeA)) mainPlusJ.append(Index(0, +1, m.k, lifetimeA)) if lifetimeB > 0: mainMinusI.append(Index(-1, 0, m.k, lifetimeB)) mainMinusJ.append(Index(0, -1, m.k, lifetimeB)) m.lifetime -= 1 m.k -= 1 if m.lifetime > 0: result.append(m) return result 为奇数且一半可能小于另一半时,这两个函数有两个不同的生命周期参数。我按标志划分了它们 - 负面导向的指数会降低一半。

      迭代n个节点的函数集:

      Secondary

      主要功能:

      def StepPlusI(plusI):
          result = []
          for m in plusI:
              m.i += 1
              m.lifetime -= 1
              if m.lifetime > 0:
                  result.append(m)
          return result
      
      def StepMinusI(minusI):
          result = []
          for m in minusI:
              m.i -= 1
              m.lifetime -= 1
              if m.lifetime > 0:
                  result.append(m)
          return result
      
      def StepPlusJ(plusJ):
          result = []
          for m in plusJ:
              m.j += 1
              m.lifetime -= 1
              if m.lifetime > 0:
                  result.append(m)
          return result
      
      def StepMinusJ(minusJ):
          result = []
          for m in minusJ:
              m.j -= 1
              m.lifetime -= 1
              if m.lifetime > 0:
                  result.append(m)
          return result
      

      实例Code

答案 1 :(得分:5)

Octant symmetry

立方矩阵中距离中心一定距离曼哈顿的单元形成一个八面体,它与穿过立方体中心的xy,xz和yz平面对称。

distance 3 in a 9x9x9 matrix

这意味着您只需要在立方体的第一个octant中找到构成八面体一面的单元格,然后镜像它们以获得其他7个八分圆中的单元格。因此,从中心(距离0)到角单元(最大距离= 3×n / 2),问题被简化为从对角线穿过立方体的第一个八分圆(其本身是立方体)。

distance 3 in the first octant

查找坐标的算法

从第一个八分圆中的(0,0,0)单元(即形成八面体的一个面,垂直于立方体的对角线的单元)中找到与某个曼哈顿距离的单元格,意味着找到坐标(x,y,z)与该距离相加的单元格。因此,在5x5x5八分圆的示例中,距离3处的单元格是具有坐标的单元格:

  

(3,0,0)(2,1,0)(1,2,0)(0,3,0)
  (2,0,1)(1,1,1)(0,2,1)
  (1,0,2)(0,1,2)
  (0,0,3)

你会注意到与距离分区的相似性(实际上,它是一个所谓的weak composition,有界长度为3)。

使用三个嵌套循环可以轻松找到这些组合;唯一的复杂因素是每个维度的距离被限制为n / 2,因此你必须跳过x和/或y的值,这些值对于z没有值,所以x,y和z与距离相加;这就是JavaScript代码示例中的min()max()以及C中的xminxmaxyminymax变量代码示例适用于。

在一个偶数大小的立方体中镜像细胞是直截了当的;在奇数大小的立方体中,单元在其坐标为零的维度中不被镜像(即,当单元位于对称平面中时)。这就是在代码示例中检查x,y或z是否等于零的原因。

并行编程

我对GPU编程知之甚少,但我认为你可以完全平行算法。对于外环的每次迭代(即对于每个距离),一旦计算出x的最小值和最大值,就可以并行运行具有不同x值的迭代。然后,对于x的每个值,一旦计算出y的最小值和最大值,就可以并行运行具有不同y值的迭代。最后,对于(x,y,z)的每个坐标集,可以并行运行与其他八分圆的镜像。

代码示例1(JavaScript)

(运行代码片段以查看9x9x9矩阵的内向外遍历,如图所示。)

function insideOut(n) {
    var half = Math.ceil(n / 2) - 1;
    for (var d = 0; d <= 3 * half; d++) {
        for (var x = Math.max(0, d - 2 * half); x <= Math.min(half, d); x++) {
            for (var y = Math.max(0, d - x - half); y <= Math.min(half, d - x); y++) {
                document.write("<br>distance " + d + " (&plusmn;" + x + ",&plusmn;" + y + ",&plusmn;" + (d - x - y) + ") &rarr; ");
                n % 2 ? mirrorOdd(x, y, d - x - y) : mirrorEven(x, y, d - x - y);
            }
        }
    }
    function mirrorEven(x, y, z) {
        for (var i = 1; i >= 0; --i, x *= -1) {
            for (var j = 1; j >= 0; --j, y *= -1) {
                for (var k = 1; k >= 0; --k, z *= -1) {
                    visit(half + x + i, half + y + j, half + z + k);
                }
            }
        }
    }
    function mirrorOdd(x, y, z) {
        for (var i = 0; i < (x ? 2 : 1); ++i, x *= -1) {
            for (var j = 0; j < (y ? 2 : 1); ++j, y *= -1) {
                for (var k = 0; k < (z ? 2 : 1); ++k, z *= -1) {
                    visit(half + x, half + y, half + z);
                }
            }
        }
    }
    function visit(x, y, z) {
        document.write("(" + x + "," + y + "," + z + ") " );
    }
}
insideOut(9);

代码示例2(C)

为简单起见,可以展开镜像功能。实际上,整个算法只包含3个嵌套循环和简单的整数计算。

void mirrorEven(unsigned int x, unsigned int y, unsigned int z, unsigned int h) {
    visit(h+x+1, h+y+1, h+z+1);
    visit(h+x+1, h+y+1, h-z);
    visit(h+x+1, h-y,   h+z+1);
    visit(h+x+1, h-y,   h-z);
    visit(h-x,   h+y+1, h+z+1);
    visit(h-x,   h+y+1, h-z);
    visit(h-x,   h-y,   h+z+1);
    visit(h-x,   h-y,   h-z);
}
void mirrorOdd(unsigned int x, unsigned int y, unsigned int z, unsigned int h) {
                     visit(h+x, h+y, h+z);
    if (          z) visit(h+x, h+y, h-z);
    if (     y     ) visit(h+x, h-y, h+z);
    if (     y && z) visit(h+x, h-y, h-z);
    if (x          ) visit(h-x, h+y, h+z);
    if (x      && z) visit(h-x, h+y, h-z);
    if (x && y     ) visit(h-x, h-y, h+z);
    if (x && y && z) visit(h-x, h-y, h-z);
}
void insideOut(unsigned int n) {
    unsigned int d, x, xmin, xmax, y, ymin, ymax, half = (n-1)/2;
    for (d = 0; d <= 3*half; d++) {
        xmin = d < 2*half ? 0 : d-2*half;
        xmax = d < half ? d : half;
        for (x = xmin; x <= xmax; x++) {
            ymin = d < x+half ? 0 : d-x-half;
            ymax = d > x+half ? half : d-x;
            for (y = ymin; y <= ymax; y++) {
                if (n%2) mirrorOdd(x, y, d-x-y, half);
                else mirrorEven(x, y, d-x-y, half);
            }
        }
    }
}

答案 2 :(得分:4)

[我在解决方案中使用Manhattan distance]

为简单起见,让我们开始假设奇数维([2N+1, 2N+1, 2N+1]

的3D数组

使用曼哈顿距离中心([0,0,0])与点之间的最大距离为3N[N,N,N],[N,N,-N], ...)

所以,基本上这个想法是找到一种方法来生成具有特定距离的所有坐标。然后从距离0开始到3N生成这些坐标。

要生成距离为[X,Y,Z]的坐标K,我们需要的是XYZ之间的所有数字-N 1}}和N使得ABS(X) + ABS(Y) + ABS(Z) == K。这可以通过以下方式完成:

FUNC COORDS_AT_DIST(K)
    FOR X = -MIN(N, K) TO MIN(N, K)
        FOR Y = -MIN(N, K - ABS(X)) TO MIN(N, K - ABS(X))
            LET Z = K - ABS(X) - ABS(Y)
            IF Z <= N
                VISIT(X, Y, Z)
                IF Z != 0
                    VISIT(X, Y, -Z)

然后,像这样使用这个函数:

FOR K = 0 TO 3N
    COORDS_AT_DIST(K)

此代码访问所有坐标,其中[-N,-N,-N][N,N,N]之间的值根据与[0,0,0]的距离排序。

现在,为了处理偶数维度,我们还需要一些额外的检查,因为维度L的坐标值介于[-(L/2-1),-(L/2-1),-(L/2-1)][L/2,L/2,L/2]之间。

这样的事情:

FUNC VISIT_COORDS_FOR_DIM(L)
    LET N = L/2               //Integer division
    FOR K = 0 TO 3N
        FOR X = -MIN(N - REM(L+1, 2), K) TO MIN(N, K)
            FOR Y = -MIN(N - REM(L+1, 2), K - ABS(X)) TO MIN(N, K - ABS(X))
                LET Z = K - ABS(X) - ABS(Y)
                IF Z <= N
                    VISIT(X, Y, Z)
                    IF Z != 0 && (REM(L, 2) != 0 || Z < N)
                        VISIT(X, Y, -Z)

为了清楚起见:

MIN(X, Y): Minimum value between X and Y
ABS(X): Absolute value of X
REM(X, Y): Remainder after division of X by Y

VISIT(X, Y, Z): Visit the generated coordinate (X, Y, Z)

VISIT_COORDS_FOR_DIM功能与L=3一起使用即可获得:

 1. [0, 0, 0]       DISTANCE: 0
 2. [-1, 0, 0]      DISTANCE: 1
 3. [0, -1, 0]      DISTANCE: 1
 4. [0, 0, -1]      DISTANCE: 1
 5. [0, 0, 1]       DISTANCE: 1
 6. [0, 1, 0]       DISTANCE: 1
 7. [1, 0, 0]       DISTANCE: 1
 8. [-1, -1, 0]     DISTANCE: 2
 9. [-1, 0, -1]     DISTANCE: 2
10. [-1, 0, 1]      DISTANCE: 2
11. [-1, 1, 0]      DISTANCE: 2
12. [0, -1, -1]     DISTANCE: 2
13. [0, -1, 1]      DISTANCE: 2
14. [0, 1, -1]      DISTANCE: 2
15. [0, 1, 1]       DISTANCE: 2
16. [1, -1, 0]      DISTANCE: 2
17. [1, 0, -1]      DISTANCE: 2
18. [1, 0, 1]       DISTANCE: 2
19. [1, 1, 0]       DISTANCE: 2
20. [-1, -1, -1]    DISTANCE: 3
21. [-1, -1, 1]     DISTANCE: 3
22. [-1, 1, -1]     DISTANCE: 3
23. [-1, 1, 1]      DISTANCE: 3
24. [1, -1, -1]     DISTANCE: 3
25. [1, -1, 1]      DISTANCE: 3
26. [1, 1, -1]      DISTANCE: 3
27. [1, 1, 1]       DISTANCE: 3

对于L=4

 1. [0, 0, 0]      DISTANCE: 0                    33. [1, -1, -1]    DISTANCE: 3
 2. [-1, 0, 0]     DISTANCE: 1                    34. [1, -1, 1]     DISTANCE: 3
 3. [0, -1, 0]     DISTANCE: 1                    35. [1, 0, 2]      DISTANCE: 3
 4. [0, 0, -1]     DISTANCE: 1                    36. [1, 1, -1]     DISTANCE: 3
 5. [0, 0, 1]      DISTANCE: 1                    37. [1, 1, 1]      DISTANCE: 3
 6. [0, 1, 0]      DISTANCE: 1                    38. [1, 2, 0]      DISTANCE: 3
 7. [1, 0, 0]      DISTANCE: 1                    39. [2, -1, 0]     DISTANCE: 3
 8. [-1, -1, 0]    DISTANCE: 2                    40. [2, 0, -1]     DISTANCE: 3
 9. [-1, 0, -1]    DISTANCE: 2                    41. [2, 0, 1]      DISTANCE: 3
10. [-1, 0, 1]     DISTANCE: 2                    42. [2, 1, 0]      DISTANCE: 3
11. [-1, 1, 0]     DISTANCE: 2                    43. [-1, -1, 2]    DISTANCE: 4
12. [0, -1, -1]    DISTANCE: 2                    44. [-1, 1, 2]     DISTANCE: 4
13. [0, -1, 1]     DISTANCE: 2                    45. [-1, 2, -1]    DISTANCE: 4
14. [0, 0, 2]      DISTANCE: 2                    46. [-1, 2, 1]     DISTANCE: 4
15. [0, 1, -1]     DISTANCE: 2                    47. [0, 2, 2]      DISTANCE: 4
16. [0, 1, 1]      DISTANCE: 2                    48. [1, -1, 2]     DISTANCE: 4
17. [0, 2, 0]      DISTANCE: 2                    49. [1, 1, 2]      DISTANCE: 4
18. [1, -1, 0]     DISTANCE: 2                    50. [1, 2, -1]     DISTANCE: 4
19. [1, 0, -1]     DISTANCE: 2                    51. [1, 2, 1]      DISTANCE: 4
20. [1, 0, 1]      DISTANCE: 2                    52. [2, -1, -1]    DISTANCE: 4
21. [1, 1, 0]      DISTANCE: 2                    53. [2, -1, 1]     DISTANCE: 4
23. [2, 0, 0]      DISTANCE: 2                    54. [2, 0, 2]      DISTANCE: 4
23. [-1, -1, -1]   DISTANCE: 3                    55. [2, 1, -1]     DISTANCE: 4
24. [-1, -1, 1]    DISTANCE: 3                    56. [2, 1, 1]      DISTANCE: 4
25. [-1, 0, 2]     DISTANCE: 3                    57. [2, 2, 0]      DISTANCE: 4
26. [-1, 1, -1]    DISTANCE: 3                    58. [-1, 2, 2]     DISTANCE: 5
27. [-1, 1, 1]     DISTANCE: 3                    59. [1, 2, 2]      DISTANCE: 5
28. [-1, 2, 0]     DISTANCE: 3                    60. [2, -1, 2]     DISTANCE: 5
29. [0, -1, 2]     DISTANCE: 3                    61. [2, 1, 2]      DISTANCE: 5
30. [0, 1, 2]      DISTANCE: 3                    62. [2, 2, -1]     DISTANCE: 5
31. [0, 2, -1]     DISTANCE: 3                    63. [2, 2, 1]      DISTANCE: 5
32. [0, 2, 1]      DISTANCE: 3                    64. [2, 2, 2]      DISTANCE: 6

此解决方案具有以下优点:不需要任何特殊的数据结构,甚至不需要数组。

另一个解决方案可能是你可以使用一个队列(用数组实现起来并不困难),而且从中心开始,3D布尔(或int)数组就像BFS一样。

首先,要定义什么是邻居,可以使用移动数组,例如:

  • 如果共享一个共同的一面(Manhattan distance),则两个单元格是邻居:

     DX = { 1, 0, 0, -1, 0, 0 }
     DY = { 0, 1, 0, 0, -1, 0 }
     DZ = { 0, 0, 1, 0, 0, -1 }
    
  • 如果共享共同边缘,则两个单元格是邻居:

     DX = { 1, 0, 0, -1, 0, 0, 1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0 }
     DY = { 0, 1, 0, 0, -1, 0, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0, -1 }
     DZ = { 0, 0, 1, 0, 0, -1, 0, 1, 1, 0, 1, 1, 0, -1, -1, 0, -1, -1 }
    
  • 如果共享一个共同的角落(Chebyshev distance),则两个单元格是邻居:

     DX = { 1, 0, 0, -1, 0, 0, 1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 1, 1, -1, -1, 1, -1 }
     DY = { 0, 1, 0, 0, -1, 0, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0, -1, 1, 1, -1, 1, -1, 1, -1, -1 }
     DZ = { 0, 0, 1, 0, 0, -1, 0, 1, 1, 0, 1, 1, 0, -1, -1, 0, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1 }
    

现在,使用队列,您可以从中心位置开始,然后添加邻居,然后添加邻居的邻居,依此类推。在每次迭代中,您都可以访问每个生成的位置。

这样的事情:

DX = { 1, 0, 0, -1, 0, 0 }
DY = { 0, 1, 0, 0, -1, 0 }
DZ = { 0, 0, 1, 0, 0, -1 }

VISIT_COORDS_FOR_DIM(L):
    LET N = L/2
    IF (REM(L, 2) == 0)
        N--

    V: BOOLEAN[L, L, L]
    Q: QUEUE<POINT3D>

    V[N, N, N] = TRUE
    ENQUEUE(Q, POINT3D(N, N, N))

    WHILE COUNT(Q) > 0
        P = DEQUEUE(Q)
        VISIT(P.X - N, P.Y - N, P.Z - N) //To Transform coords to [-N, N] range.

        FOR I = 0 TO LENGTH(DX) - 1
            LET X = P.X + DX[I]
            LET Y = P.Y + DY[I]
            LET Z = P.Z + DZ[I]

            IF IS_VALID_POS(L, X, Y, Z) && V[X, Y, Z] == FALSE
                V[X, Y, Z] = TRUE
                ENQUEUE(Q, POINT3D(X, Y, Z))

IS_VALID_POS(L, X, Y, Z)
    RETURN X >= 0 && X < L &&
           Y >= 0 && Y < L &&
           Z >= 0 && Z < L

使用过的功能:

REM(X, Y): Remainder after division of X by Y
ENQUEUE(Q, X): Enqueue element X in queue Q
DEQUEUE(Q): Dequeue first element from queue Q
COUNT(Q): Number of elements in queue Q 

VISIT(X, Y, Z): Visit the generated coordinate (X, Y, Z)

此解决方案具有以下优点:您可以使用移动数组定义两个位置是邻居。

答案 3 :(得分:3)

获得这个问题的有效算法的关键是看到它背后的几何。您要求的是为N的每个连续值求解Diophantine equation N = a ^ 2 + b ^ 2 + c ^ 2,以任何顺序枚举这样的解。这个方程的解是半径为N的球体上的积分点。所以从某种意义上说,你的问题是枚举球体。

首先,应该清楚的是,这里的难题是枚举坐标(a,b,c)的非负解。对于每个这样的坐标,从坐标平面周围的镜像对称有八个其他解,因为a ^ 2 =( - a)^ 2等(一般情况下。如果a,b,c中的一个或多个为零,则得到通过置换坐标使得a&lt; = b&lt; = c。进一步对称。这是枚举的简单部分。

球体枚举算法的本质是考虑两组近似于半径为N的球体的点:一组由具有范数的点组成,并且#34;略小于#34;比N和一个由他们的格子邻居组成的规范&#34;稍微大一些&#34;比N或等于N.&#34;略少于&#34;对于点(a,b,c),a ^ 2 + b ^ 2 + c ^ 2&lt; N,但是一个或多个点(a + 1,b,c),(a,b + 1,c)或(a,b,c + 1)具有范数&gt; = N.至于代码,你不需要代表&#34;稍微少一些&#34;组;它已被处理完毕。它足以创建一个更大的&#34;&#34;按照他们的标准排序。

算法的每一步都变为&#34;略大的&#34;为N + 1设置N为一。删除堆的最少元素,比如(a,b,c)。现在将具有更大范数的最近邻点添加到堆中,三个点(a + 1,b,c),(a,b + 1,c)和(a,b,c + 1)。其中一些人可能已经在那里;我会回过头来看看。将增量点添加到堆上时,需要它的规范。你做,但需要从头开始计算。依靠身份(a + 1)^ 2 - a ^ 2 = 2a + 1.换句话说,你不需要任何乘法运算来计算这些规范。根据您的GPU,您可以计算表达式a&lt;&lt; 1 + 1或者a + a + 1。

您还可以优化检查堆上的现有点。每个点有六个直接点阵邻居。具有最小范数的格子邻居将是第一个添加它的人。假设a&lt; b&lt; c表示点(a,b,c)。其规范最小的邻居是(a,b,c-1)。因此,当枚举点(a-1,b,c)时,点(a,b,c)已经在堆上;你甚至不需要检查它是否在那里。注意一些坐标相等的特殊情况。

此算法枚举球体,而不是立方体。很容易将注意力限制在具有最大索引D的立方体上。如果其中一个坐标等于D,则不要添加三个点,但要少一些。当没有更多有效的邻居点要添加时,枚举以点(D,D,D)结束。

此算法的性能应该非常快。它需要一个大小为O(N ^ 2)的堆。如果您事先枚举所有点,则需要存储O(N ^ 3)。此外,它不需要乘法,以进一步加速。

答案 4 :(得分:2)

如果它只是中心:有很多不同的有效订单。只需计算一个三维地图,按顺序排列元素。抵消原产地。制作地图:

for x,y,z -domain, domain
  map.add ( x,y,z, distance(x,y,z) ) 
map.sort ( distance ) 

然后在点x,y,z遍历

for ( i=0; i++ )
   visit ( map[i].xyz + x,y,z )

如果它是真正的距离而不是体素中心,则会变得更加困难。

答案 5 :(得分:2)

Manhatan距离顺序生成索引类似于子集和问题,因此只需计算最大距离(总和),然后分离轴以减少问题。这里 C ++ 示例:

int x,y,z,d,dx,dy,dz,D;
// center idx
int cx=n>>1;
int cy=n>>1;
int cz=n>>1;
// min idx
int x0=-cx;
int y0=-cy;
int z0=-cz;
// max idx
int x1=n-1-cx;
int y1=n-1-cy;
int z1=n-1-cz;
// max distance
x=max(x0,x1);
y=max(y0,y1);
z=max(z0,z1);
D=x+y+z;
// here do your stuff
#define traverse(x,y,z) { /* do something with the array beware x,y,z are signed !!!  */ }
// traversal
for (d=0;d<=D;d++)  // distance
 for (dx=d              ,x=-dx;x<=dx;x++) if ((x>=x0)&&(x<=x1)) // x axis separation
 for (dy=d-abs(x)       ,y=-dy;y<=dy;y++) if ((y>=y0)&&(y<=y1)) // y axis separation
    {
    dz=d-abs(x)-abs(y); // z axis have only 1 or 2 options
    z=-dz; if       (z>=z0)  traverse(x,y,z);
    z=+dz; if ((z)&&(z<=z1)) traverse(x,y,z);
    }
#undef traverse

您可以使用您想要的任何内容或功能替换traverse(x,y,z)宏。请注意x,y,z已签名,因此您需要使用(x+cx,y+cy,z+cz)来获取 C ++ 样式索引。

这可以处理booth偶数和奇数索引以及非立方体分辨率(如果你只是在前几个常量计算中将n转换为nx,ny,nz[0,0,0]也可以在任何地方(不在中心),因此很容易适用于我能想到的任何需求......

此处为n=5

的示例输出
[ 0, 0, 0] = 0
[-1, 0, 0] = 1
[ 0,-1, 0] = 1
[ 0, 0,-1] = 1
[ 0, 0, 1] = 1
[ 0, 1, 0] = 1
[ 1, 0, 0] = 1
[-2, 0, 0] = 2
[-1,-1, 0] = 2
[-1, 0,-1] = 2
[-1, 0, 1] = 2
[-1, 1, 0] = 2
[ 0,-2, 0] = 2
[ 0,-1,-1] = 2
[ 0,-1, 1] = 2
[ 0, 0,-2] = 2
[ 0, 0, 2] = 2
[ 0, 1,-1] = 2
[ 0, 1, 1] = 2
[ 0, 2, 0] = 2
[ 1,-1, 0] = 2
[ 1, 0,-1] = 2
[ 1, 0, 1] = 2
[ 1, 1, 0] = 2
[ 2, 0, 0] = 2
[-2,-1, 0] = 3
[-2, 0,-1] = 3
[-2, 0, 1] = 3
[-2, 1, 0] = 3
[-1,-2, 0] = 3
[-1,-1,-1] = 3
[-1,-1, 1] = 3
[-1, 0,-2] = 3
[-1, 0, 2] = 3
[-1, 1,-1] = 3
[-1, 1, 1] = 3
[-1, 2, 0] = 3
[ 0,-2,-1] = 3
[ 0,-2, 1] = 3
[ 0,-1,-2] = 3
[ 0,-1, 2] = 3
[ 0, 1,-2] = 3
[ 0, 1, 2] = 3
[ 0, 2,-1] = 3
[ 0, 2, 1] = 3
[ 1,-2, 0] = 3
[ 1,-1,-1] = 3
[ 1,-1, 1] = 3
[ 1, 0,-2] = 3
[ 1, 0, 2] = 3
[ 1, 1,-1] = 3
[ 1, 1, 1] = 3
[ 1, 2, 0] = 3
[ 2,-1, 0] = 3
[ 2, 0,-1] = 3
[ 2, 0, 1] = 3
[ 2, 1, 0] = 3
[-2,-2, 0] = 4
[-2,-1,-1] = 4
[-2,-1, 1] = 4
[-2, 0,-2] = 4
[-2, 0, 2] = 4
[-2, 1,-1] = 4
[-2, 1, 1] = 4
[-2, 2, 0] = 4
[-1,-2,-1] = 4
[-1,-2, 1] = 4
[-1,-1,-2] = 4
[-1,-1, 2] = 4
[-1, 1,-2] = 4
[-1, 1, 2] = 4
[-1, 2,-1] = 4
[-1, 2, 1] = 4
[ 0,-2,-2] = 4
[ 0,-2, 2] = 4
[ 0, 2,-2] = 4
[ 0, 2, 2] = 4
[ 1,-2,-1] = 4
[ 1,-2, 1] = 4
[ 1,-1,-2] = 4
[ 1,-1, 2] = 4
[ 1, 1,-2] = 4
[ 1, 1, 2] = 4
[ 1, 2,-1] = 4
[ 1, 2, 1] = 4
[ 2,-2, 0] = 4
[ 2,-1,-1] = 4
[ 2,-1, 1] = 4
[ 2, 0,-2] = 4
[ 2, 0, 2] = 4
[ 2, 1,-1] = 4
[ 2, 1, 1] = 4
[ 2, 2, 0] = 4
[-2,-2,-1] = 5
[-2,-2, 1] = 5
[-2,-1,-2] = 5
[-2,-1, 2] = 5
[-2, 1,-2] = 5
[-2, 1, 2] = 5
[-2, 2,-1] = 5
[-2, 2, 1] = 5
[-1,-2,-2] = 5
[-1,-2, 2] = 5
[-1, 2,-2] = 5
[-1, 2, 2] = 5
[ 1,-2,-2] = 5
[ 1,-2, 2] = 5
[ 1, 2,-2] = 5
[ 1, 2, 2] = 5
[ 2,-2,-1] = 5
[ 2,-2, 1] = 5
[ 2,-1,-2] = 5
[ 2,-1, 2] = 5
[ 2, 1,-2] = 5
[ 2, 1, 2] = 5
[ 2, 2,-1] = 5
[ 2, 2, 1] = 5
[-2,-2,-2] = 6
[-2,-2, 2] = 6
[-2, 2,-2] = 6
[-2, 2, 2] = 6
[ 2,-2,-2] = 6
[ 2,-2, 2] = 6
[ 2, 2,-2] = 6
[ 2, 2, 2] = 6

答案 6 :(得分:1)

每个点(a, b, c)都知道与原点的距离为sqrt(a*a + b*b + c*c)。我们可以将其定义为distance(a, b, c)

对于3D数组中的每个点,您可以使用distance作为订购条件将其插入min heap。为避免重新计算,请在堆中扩充点表示,以便在插入堆时包含该点的distance的缓存计算。

  

heap_element =(x,y,z,d)

  heap_compare(heap_element a,heap_element b)= a.d&lt; b.d

  对于3D阵列中的每个点(x,y,z)   · heap.add(heap_element(x,y,z,distance(x,y,z)))

现在,您可以从堆顶部抽出每个点来获取订单。

  

N = heap.size
  因为我在0..N
  · ordered [i] = heap.top
  · heap.pop

<子> †出于本算法的目的,使用实际距离并不重要。出于性能原因,您可以省略sqrt,并使用a*a + b*b + c*c作为堆排序条件的度量标准。

答案 7 :(得分:1)

在红宝石中,我只是按顺序从中心获得每个距离的所有点。

def get_points(side_len)
  side_len % 2 == 0 ? min_dist = 1 : min_dist = 0

  if side_len % 2 == 0
    min_dist = 1
    max_1d_dist = side_len / 2
  else
    min_dist = 0
    max_1d_dist = (side_len - 1) / 2
  end

  max_dist = 3 * max_1d_dist

  min_dist.upto(max_dist) do |dist|
    min_x_dist = [min_dist, dist - 2 * max_1d_dist].max
    max_x_dist = [dist - 2 * min_dist, max_1d_dist].min
    min_x_dist.upto(max_x_dist) do |x_dist|
      min_y_dist = [min_dist, dist - x_dist - max_1d_dist].max
      max_y_dist = [dist - x_dist - min_dist, max_1d_dist].min
      min_y_dist.upto(max_y_dist) do |y_dist|
        z_dist = dist - x_dist - y_dist
        print_vals(x_dist, y_dist, z_dist)
      end
    end
  end
end

def print_vals(x_dist, y_dist, z_dist)
  x_signs = [1]
  y_signs = [1]
  z_signs = [1]
  x_signs << -1 unless x_dist == 0
  y_signs << -1 unless y_dist == 0
  z_signs << -1 unless z_dist == 0

  x_signs.each do |x_sign|
    y_signs.each do |y_sign|
      z_signs.each do |z_sign|
        puts "[#{x_sign*x_dist}, #{y_sign*y_dist}, #{z_sign*z_dist}]"
      end
    end
  end
end

输出是:

2.1.2 :277 > get_points(1)
[0, 0, 0]

2.1.2 :278 > get_points(2)
[1, 1, 1]
[1, 1, -1]
[1, -1, 1]
[1, -1, -1]
[-1, 1, 1]
[-1, 1, -1]
[-1, -1, 1]
[-1, -1, -1]

2.1.2 :279 > get_points(3)
[0, 0, 0]
[0, 0, 1]
[0, 0, -1]
[0, 1, 0]
[0, -1, 0]
[1, 0, 0]
[-1, 0, 0]
[0, 1, 1]
[0, 1, -1]
[0, -1, 1]
[0, -1, -1]
[1, 0, 1]
[1, 0, -1]
[-1, 0, 1]
[-1, 0, -1]
[1, 1, 0]
[1, -1, 0]
[-1, 1, 0]
[-1, -1, 0]
[1, 1, 1]
[1, 1, -1]
[1, -1, 1]
[1, -1, -1]
[-1, 1, 1]
[-1, 1, -1]
[-1, -1, 1]
[-1, -1, -1]

答案 8 :(得分:0)

这是一种简单快速算法,可以使用曼哈顿距离横切3D数组。

每个维度中大小为n的3D数组应由坐标系表示,其原点位于数组的中间。对于要定义的中心,我们假设每个维度中的数组大小是奇数。每个元素都有一个三元坐标,如[x, y, z],每个坐标的最大值可以达到`(n / 2)-1。 (信息:添加的图片为2D以便更好地理解)

  1. 首先,我们可以通过仅考虑正八分圆(所有坐标都是正的)来简化这一点。所有其他元素都可以通过反射生成。
    enter image description here
  2. 在一个八分圆中,与中心具有相同距离的所有元素由具有等式x+y+z=distance的等式的平面定义。我们通过统一计算从0n-1的距离来实现这一目标。对于每个距离,我们寻找相应平面上的所有元素。
    enter image description here
  3. 当到达distance>(n/2)-1时,某些点将位于数组之外(coord > (n/2)-1之一)。所以我们必须将它们排除在结果之外。
    enter image description here
  4. 每个计算出的元素最多可以表示通过反射得到的8个元素(参见第1点)。您可以通过交替将每个坐标乘以-1来实现此目的。 [+/-x, +/-y, +/-z](如果全部为coords != 0,则为8种可能的组合)
    enter image description here
  5. 以下是我算法的代码架构:

    //rise the distance by one each iteration
    for(distance=0; distance<n-1; distance++) //loop distance from 0 to n-1
      for(i=0; i<=distance; i++) 
        x=i; //x ∈ [0, distance]
        for(j=0; j<=distance-x; j++) 
          y=j; //y ∈ [0, distance-x]
          z=distance-(x+y); //because distance=x+y+z
          //now we have to exclude all elements with one coord <= (n/2)-1
          if(x<=(n/2)-1 && y<=(n/2)-1 && z<=(n/2)-1)
            //[x,y,z] we found a valid element!
            //let's generate the 7 corresponding elements (up to 7)
            if(x!=0) //[-x,y,z]
            if(y!=0) //[x,-y,z]
            if(z!=0) //[x,y,-z]
            if(x!=0 && y!=0) //[-x,-y,z]
            if(x!=0 && z!=0) //[-x,y,-z]
            if(y!=0 && z!=0) //[x,-y,-z]
            if(y!=0 && y!=0 && z!=0) //[-x,-y,-z]
    

    以下是n=7的输出:

    Distance:0 [0,0,0] 
    Distance:1 [0,0,1] [0,0,-1] [0,1,0] [0,-1,0] [1,0,0] [-1,0,0] 
    Distance:2 [0,0,2] [0,0,-2] [0,1,1] [0,-1,1] [0,1,-1] [0,-1,-1] [0,2,0] [0,-2,0] [1,0,1] [-1,0,1] [1,0,-1] [-1,0,-1] [1,1,0] [-1,1,0] [1,-1,0] [-1,-1,0] [2,0,0] [-2,0,0] 
    Distance:3 [0,1,2] [0,-1,2] [0,1,-2] [0,-1,-2] [0,2,1] [0,-2,1] [0,2,-1] [0,-2,-1] [1,0,2] [-1,0,2] [1,0,-2] [-1,0,-2] [1,1,1] [-1,1,1] [1,-1,1] [1,1,-1] [-1,-1,1] [-1,1,-1] [1,-1,-1] [-1,-1,-1] [1,2,0] [-1,2,0] [1,-2,0] [-1,-2,0] [2,0,1] [-2,0,1] [2,0,-1] [-2,0,-1] [2,1,0] [-2,1,0] [2,-1,0] [-2,-1,0] 
    Distance:4 [0,2,2] [0,-2,2] [0,2,-2] [0,-2,-2] [1,1,2] [-1,1,2] [1,-1,2] [1,1,-2] [-1,-1,2] [-1,1,-2] [1,-1,-2] [-1,-1,-2] [1,2,1] [-1,2,1] [1,-2,1] [1,2,-1] [-1,-2,1] [-1,2,-1] [1,-2,-1] [-1,-2,-1] [2,0,2] [-2,0,2] [2,0,-2] [-2,0,-2] [2,1,1] [-2,1,1] [2,-1,1] [2,1,-1] [-2,-1,1] [-2,1,-1] [2,-1,-1] [-2,-1,-1] [2,2,0] [-2,2,0] [2,-2,0] [-2,-2,0] 
    Distance:5 [1,2,2] [-1,2,2] [1,-2,2] [1,2,-2] [-1,-2,2] [-1,2,-2] [1,-2,-2] [-1,-2,-2] [2,1,2] [-2,1,2] [2,-1,2] [2,1,-2] [-2,-1,2] [-2,1,-2] [2,-1,-2] [-2,-1,-2] [2,2,1] [-2,2,1] [2,-2,1] [2,2,-1] [-2,-2,1] [-2,2,-1] [2,-2,-1] 
    

    如果你使用欧几里得规范,你必须用sqrt(x*x+y*y+z*z)替换你的距离,你不能以一步为单位增加距离。但除此之外你可以非常相似。

答案 9 :(得分:0)

等到赏金比赛结束,不要干涉。但是我想指出,我能看到的所有答案非常可疑。这个问题有这样的说法:

&#34;此算法适用于 GPU &#34;

确实可以在GPU上进行有效的数字处理,但是这里的所有解决方案都提出了某种循环。这> 不是GPU如何工作

GPU并行执行。事实上,人们可以在GPU中循环,但随后它以极其孤立的方式发生。循环需要一个&#34;全局控制器&#34;,例如一个计数器,但GPU执行的重点是它使用多个核以无特定顺序执行。抓住&#34;是不可能的。一个核心的结果&#39;执行并将其用作另一个核心的参数。计算。这根本不是GPU的工作原理。

可以在GPU上计算多维数组,即使在高于3维的情况下也是如此。这只是单元寻址的问题,并且使用一维地址空间解决例如4维度并描述/访问相应数据是微不足道的。

不可能以特定的顺序逐个遍历单元格(像素,内存位置) - 对此无法控制。并且不可能增加,或具有循环,或具有内部循环。在GPU上,最后一个元素可能首先被执行。在GPU上,每个元素都完全自主。没有计算知道任何其他计算,因为它们之间没有通信。 GPU上每次计算的环境都是,如果它在世界上一个人

此主题中给出的答案均假设 CPU 逻辑。如果解决CPU上的问题,这是微不足道的。以二维为例,这里是5x5的绝对x,y坐标对,在中间调整为零:

┌───┬───┬───┬───┬───┐
│2 2│2 1│2 0│2 1│2 2│
├───┼───┼───┼───┼───┤
│1 2│1 1│1 0│1 1│1 2│
├───┼───┼───┼───┼───┤
│0 2│0 1│0 0│0 1│0 2│
├───┼───┼───┼───┼───┤
│1 2│1 1│1 0│1 1│1 2│
├───┼───┼───┼───┼───┤
│2 2│2 1│2 0│2 1│2 2│
└───┴───┴───┴───┴───┘

在每个单元格中添加对可以得到曼哈顿距离:

4 3 2 3 4
3 2 1 2 3
2 1 0 1 2
3 2 1 2 3
4 3 2 3 4

与此同时,我们可以建立一个索引系统(但这是一个问题的弱点,因为它没有状态地址空间):

 1  2  3  4  5
 6  7  8  9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25

我们可以平息两个距离:

dist = 4 3 2 3 4 3 2 1 2 3 2 1 0 1 2 3 2 1 2 3 4 3 2 3 4

和索引

index = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

N(或N * N或N * N * N)阵列的唯一曼哈顿距离如果N为奇数,则1和N-1之间的所有数字都先于0。对于5 * 5矩阵:

0 1 2 3 4

走过每个距离,看看距离等于&#34; dist&#34;。对于5 * 5:

0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 // dist = 0 at locations 13
0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 0 // dist = 1 at locations 8 12 14 18
0 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 0 // dist = 2 at locations 3 7 9 11 15 17 19 23
0 1 0 1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 0 // dist = 3 at locations 2 4 6 10 16 20 22 24
1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 // dist = 4 at locations 1 5 21 25

并根据这些位置构建一个数组。 IE浏览器。有一个ampty数组,作为它的第一个元素追加13,然后追加8 12 14 18,等等。最终的结果将是

13 8 12 14 18 3 7 9 11 15 17 19 23 2 4 6 10 16 20 22 24 1 5 21 25 

这是所需的顺序。通过使用除法,分钟和残差,可以很容易地将其重新排列到例如二维地址空间中。

但是,这种计算方法是GPU上的USELESS。它需要一个特定的执行顺序,而我们没有GPU

如果在GPU上解决遍历顺序,解决方案应该是

lookupcoordinates = fn(currentposition)

有可能描述fn,但问题太不完整了 - 需要更多细节,而不仅仅是在GPU&#34;上说&#34;。如何描述3d数组?它在什么记忆中?结果的广告空间是什么?等等。

我很高兴听到更多有关此问题的详细信息,以及对上述内容的更正。

与用户m69进行讨论的附录

一个(次要的)思想是在[维数]步骤中进行计算,其中来自先前维度的累积将用于下一个,直到例如3.可能数值行为在这样的情况下是有用的。一个案例。

如果仔细观察基础知识,人们可能会假设一个线性目标空间,这样它就是一个从1到[单元格数]的简单索引向量,例如10 * 10 * 10立方体就具有线性1000个索引的1D向量,从1到1000.以后总是可以将这些索引重新标记为方形或更多维格式。

在一维情况下,让我们假设我们有一个9元素数据&#34; cube&#34; (与9 * 1 * 1相同,如果是三维表示的话)。如下所示

x x x x x x x x x // Data
1 2 3 4 5 6 7 8 9 // Indexes
4 3 2 1 0 1 2 3 4 // Manhattan distances
5 4 6 3 7 2 8 1 9 // Pick order, starting from center

因此我们需要一个 fn ,其映射如下

┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐
│1 to 5│2 to 4│3 to 6│4 to 3│5 to 7│6 to 2│7 to 8│8 to 1│9 to 9│
└──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘

现在,如果查看结果的索引4,fn必须能够独立于任何其他索引解析结果= 3,即。 fn(4)= 3 。应该可以描述fn。应该可以首先得出结论:&#34; 4&#34;驻留在第2层(如果第0层是最里面的)。在那之后,应该可以得出结晶2的多样性细胞层(所有层有2个细胞),最后是否该细胞是第2层的第一个或第二个出现/元素。那将解析为3,即。对于结果[4],我们选择数据[3]。

现在,如果假设一个二维&#34;立方体&#34;大小为11 * 11(* 1),我们有这种情况:

0 1 2  3  4  5  6  7  8 9 10 // Unique Manhattan distances
1 4 8 12 16 20 20 16 12 8  4 // How many cells in each distance-layer?

我们注意到&#34;多少&#34;是相对对称的,对于10 * 10来说更加对称:

1  2  3  4  5  6  7  8   9 // Unique Manhattan distances
4  8 12 16 20 16 12  8   4 // How many cells in each distance-layer?
4 12 24 40 60 76 88 96 100 // Cumulative sum of "How many..."

注意&#34;累积金额&#34;!使用它,如果我们正在解决例如index = 55(可以在54之前或之后的任何时间发生,请记住!),我们可以得出结论,我们目前的目标是第5层,它包含20个元素,那些具有index = 40 ... 60。

这一层以40开头,我们现在为55.差异为15.也许可以描述偏移(x,y) - 来自&#34;第5层的坐标起源x,y)使用&#34; 15&#34;?我的猜测是我们刚进入第四象限。

3D相同吗?