简体   繁体   中英

Traversing a 2D or 3D array/matrix on its boundary only

I know how to traverse every element of a 2D array, using array[i % n, i / n] when i=0 < n*m for an,m array. Is there a handy formula to traverse the boundary elements of a 2D array only?

for example, for 2D, given a matrix

在此处输入图片说明

only 'a' is traversed. Wish i could illustrate for 3d but hope this clears it up

Assuming clockwise or anticlockwise traversal, Maybe something like, for 1st index:

for n = 5, m = 3.
 0 1 2 3 4
11       5
10 9 8 7 6

For i = 0 to 2m + 2n - 5
[ max( i - max( i - (n-1), 0) - max( i - (m+n-2), 0 ), 0) ]

column index first increase from 0 to n-1
Then it stays constant at n-1 upto i = n+m-2
Then it decreases along with i to 0 upto i = 2n + m - 3
Then again it stays constant at 0 upto 2n + 2m - 5.

The graph is:

  n-1_________
    /         \
   /           \
  /             \__________
 0   n-1   n+m-2 2n+m-3  2n+2m-5

For second index: The graph is:

        _______
       /       \
      /         \
 ____/           \
 0   n n+m  2n+m 2n+2m

You can form similar expression using i.

This is what I came up with for 2D: (it's Java, but to convert to C#, you should only have to replace System.out.print and Math.ceil with the C# equivalents)

int n = 5, m = 3;
for (int i = 0; i < 2*(m+n); i++)
{
   int x1 = i/(m+2*n),
       x2 = (i%(m+n))%n,
       x3 = (int)Math.ceil(((m+i)%(m+n)) / m / (1.0*n));

   System.out.print(x1*(n-1) + x2 * x3 + " ");

   int y1 = i/(m+n) - i/(m+2*n),
       y2 = x2,
       y3 = (int)Math.ceil((i%(m+n)) / n / (1.0*m));

   System.out.println(y1*(m-1) + y2 * y3);
}

The above can of course be written as a single statement that accesses the array if you wish.

Note that, because of (i%(m+n))%n , this only works if n > m . The simplest work-around for this is probably to stick this into a function that takes 4 parameters x,y,m,n , which can easily be swapped depending on whether m or n is larger.

Output:

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

Live demo .

As you can see, it does repeat 4 corner cells, if that's okay.

Let's see what each xi looks like (without the Math.ceil and /(1.0*m) or /(1.0*n) ):

 i   x1 x2 x3   y1 y2 y3
 0    0  0  1    0  0  0
 1    0  1  1    0  1  0
 2    0  2  1    0  2  0
 3    0  3  2    0  3  0
 4    0  4  2    0  4  0
 5    0  0  0    0  0  1
 6    0  1  0    0  1  1
 7    0  2  0    0  2  1
 8    0  0  1    1  0  0
 9    0  1  1    1  1  0
10    0  2  1    1  2  0
11    0  3  2    1  3  0
12    0  4  2    1  4  0
13    1  0  0    0  0  1
14    1  1  0    0  1  1
15    1  2  0    0  2  1

The Math.ceil and /(1.0*m) or /(1.0*n) is just there to change x3 and y3 to 1 where they're > 1 (which will happen if the applicable limit ( m or n ) is greater than the other limit ( n or m ).

The above table can then be used to get the desired traversal by multiplying the first with the limit-1 and adding the product of the second and the third, as can be seen in the print statements in the code.

Figuring out that the above table would be useful, how to generate it and how to use it was just a matter of playing around a bit.

Yeah, I'm not figuring that out for 3D.

As you can see, something slightly longer is way more readable:

int n = 5, m = 3;
int x = 0, y = 0;
int xInc = 1, yInc = 0;
while (true)
{
   System.out.println(x + " " + y);
   // got to right, go down
   if (x == n-1 && xInc == 1)
   {
      xInc = 0;
      yInc = 1;
   }
   // got to bottom, go left
   else if (y == m-1 && yInc == 1)
   {
      xInc = -1;
      yInc = 0;
   }
   // got to left, go up
   else if (x == 0 && xInc == -1)
   {
      xInc = 0;
      yInc = -1;
   }
   // got to top, stop
   else if (y == 0 && yInc == -1)
   {
      break;
   }
   x += xInc;
   y += yInc;
}

Output:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM