如何基于坐标对角填充2D数组

时间:2010-06-30 22:12:26

标签: algorithm arrays math

我正在构建一个类似热图的矩形阵列接口,我希望“热”位置位于数组的左上角,而“冷”位置位于右下角。因此,我需要一个像这样对角填充的数组:

    0    1    2    3
  |----|----|----|----|
0 | 0  | 2  | 5  | 8  |
  |----|----|----|----|
1 | 1  | 4  | 7  | 10 |
  |----|----|----|----|
2 | 3  | 6  | 9  | 11 |
  |----|----|----|----|

实际上,我需要一个函数f(x,y),这样

f(0,0) = 0
f(2,1) = 7
f(1,2) = 6
f(3,2) = 11

(或者,当然,类似函数f(n),其中f(7)= 10,f(9)= 6等)。

最后,是的,我知道这个问题类似于hereherehere提出的问题,但是那里描述的解决方案只是遍历而不填充矩阵。

5 个答案:

答案 0 :(得分:4)

如果您被限制逐行遍历数组,则会出现有趣的问题。 我将矩形划分为三个区域。 左上角三角形右下角三角形长菱形

对于左上角三角形,可以使用通用算术系列1 + 2 + 3 + .. + n = n*(n+1)/2计算第一列(x = 0)中的值。具有相同x + y值的那个三角形中的字段位于相同的对角线中,并且该值是来自第一个列+ x的总和。

同样的方法适用于右下角三角形。但是,使用xy代替w-xh-y,其中w是宽度,h是矩形的高度。必须从数组中的最高值w*h-1中减去该值。

菱形中间有两种情况。如果矩形的宽度大于(或等于)高度,则矩形的左下角字段是菱形中具有最低值的字段,并且可以计算h-1之前的总和。从那里你可以想象菱形是一个矩形,其x值为x+y,y值为y,来自原始矩形。因此,计算新矩形中的剩余值很容易 在另一种情况下,当高度大于宽度时,可以使用该算术和计算x=w-1y=0处的字段,并且可以将菱形可想象为具有x值{{ 1}}和y值x

例如,可以通过预先计算值来优化代码。我认为所有这些案件都有一个公式。也许我以后会考虑它。

y-(w-x-1)

inline static int diagonalvalue(int x, int y, int w, int h) {
    if (h > x+y+1 && w > x+y+1) {
        // top/left triangle
        return ((x+y)*(x+y+1)/2) + x;
    } else if (y+x >= h && y+x >= w) {
        // bottom/right triangle
        return w*h - (((w-x-1)+(h-y-1))*((w-x-1)+(h-y-1)+1)/2) - (w-x-1) - 1;
    }

    // rhomboid in the middle
    if (w >= h) {
        return (h*(h+1)/2) + ((x+y+1)-h)*h - y - 1;
    }
    return (w*(w+1)/2) + ((x+y)-w)*w + x;
}

当然,如果没有这样的限制,那样的事情应该更快:

for (y=0; y<h; y++) {
    for (x=0; x<w; x++) {
        array[x][y] = diagonalvalue(x,y,w,h);
    }
}

答案 1 :(得分:1)

这个怎么样(有一个NxN矩阵):

count = 1;
for( int k = 0; k < 2*N-1; ++k ) {
  int max_i = std::min(k,N-1);
  int min_i = std::max(0,k-N+1);
  for( int i = max_i, j = min_i; i >= min_i; --i, ++j ) {
    M.at(i).at(j) = count++;
  }
}

答案 2 :(得分:0)

按照第3个示例中的步骤 - 这给出了索引(为了打印出切片) - 只需使用递增计数器设置值:

int x[3][3];
int n = 3;
int pos = 1;
for (int slice = 0; slice < 2 * n - 1; ++slice) {
    int z = slice < n ? 0 : slice - n + 1;
    for (int j = z; j <= slice - z; ++j)
        x[j][slice - j] = pos++;
}

答案 3 :(得分:0)

在M * N矩阵中,除了边界情况外,当你在所述示例中遍历时,这些值似乎增加了n,所以

f(0,0)=0
f(1,0)=f(0,0)+2
f(2,0)=f(1,0)+3

......依此类推至f(N,0)。然后

f(0,1)=1
f(0,2)=3

然后

f(m,n)=f(m-1,n)+N, where m,n are index variables

f(M,N)=f(M-1,N)+2, where M,N are the last indexes of the matrix

这不是决定性的,但它应该给你一些工作。请注意,您只需要每行中前一个元素的值以及几个起始值。

答案 4 :(得分:0)

如果你想要一个简单的函数,你可以使用递归定义。

H = height

def get_point(x,y)
  if x == 0
      if y == 0
        return 0
      else
        return get_point(y-1,0)+1
      end
  else
    return get_point(x-1,y) + H
  end
end

这利用了以下事实:任何值都是H +左侧项目的值。如果该项目已经位于最左侧的列中,那么您将找到位于其最右上角的单元格,并从那里向左移动,并添加1.

这是一个很好的机会使用dynamic programming,“缓存”或记忆你已经完成的功能。


如果您想要f(n)“严格”完成某些事情,您可以使用以下关系:

n = ( n % W , n / H )   [integer division, with no remainder/decimal]

从那里开始工作。


或者,如果你想要一个没有递归的纯数组 - 按行填充方法,你可以遵循以下规则:

  1. 如果您在该行的第一个单元格中,请“记住”第一行单元格中的项目(R-1)(其中R是当前行),并向其添加1。
  2. 否则,只需将H添加到上次计算的单元格(即左侧的单元格)。
  3. Psuedo-Code :(假设数组由arr[row,column]索引)

    arr[0,0] = 0
    
    for R from 0 to H
    
      if R > 0
        arr[R,0] = arr[0,R-1] + 1 
      end
    
      for C from 1 to W
    
        arr[R,C] = arr[R,C-1]
    
      end
    
    end