循环通过3d矩阵连续增加每个方向?

时间:2015-02-16 10:44:05

标签: java loops matrix

我不想要这个:

    for (int k=0; k<X; k++) {
        for (int j=0; j<X; j++) {
            for (int i=0; i<X; i++) {
                // do something
            }
        }
    }

编辑:上面的代码snipet会将程序发送到以下几点: (000)(001)(002)(003)(004) 然后(对于X = 5) (010)(011)(012)(013)(014) 然后 (020)(021)......

这对我的程序来说是浪费时间,因为我相信通过这个顺序测试,我会更快地得到结果: (0,0,0)(1,0,0)(1,1,0)(0,1,0)(0,1,1)(0,0,1)(1,0,1)等... 一种看待它的方法是通过矩阵递增,试图在每一步获得最小距离(0,0,0)增量。

我希望它更清楚。

你知道一种聪明的编码方式吗?

编辑:按此顺序测试矩阵点对于解决此问题非常重要。

6 个答案:

答案 0 :(得分:2)

您需要按距离增加的顺序获取元素。 “距离”可以评估为d=sqrt(x*x+y*y+z*z),或者更有效地评估为d=x*x+y*y+z*z(因为平方根是单调的)

static int sumsq(int[] a){
    return IntStream.of(a).map(i -> i * i).sum();
}

您只需列出所有索引组合,然后按增加sumsq顺序排序。在java 8中:

int n = 5;
int n3 = n * n * n;
int[][] r = IntStream.range(0, n3)  //0,1,2...124
        .mapToObj(i -> new int[]{i%n, i/n%n, i/n/n%n}) //(0,0,0),(1,0,0),(2,0,0)...
        .sorted((a1, a2) -> sumsq(a1) - sumsq(a2)) //(0,0,0),(1,0,0),(0,1,0)...
        .toArray(i -> new int[n3][]);

您可以使用以前的java版本更长时间地重写它。通过3d矩阵迭代将是:

for (int i = 0; i < n3; ++i) {
    System.out.format("(%d,%d,%d)\n", r[i][0], r[i][1], r[i][2]);
}

5x5x5是相对较小的3d数组,因此如果您需要多次迭代或每次迭代都是繁重操作,则可能需要进行此类优化。然后列出所有索引组合并对其进行排序与​​其他作业相比应该可以忽略不计。数组r只应计算一次; n=5需要不到秒。

答案 1 :(得分:1)

我没有完整的解决方案,只有一些想法,你可以尝试。基本上,你想要的是一个3D flood fill算法,你可以根据到起点的距离选择下一个点(较小的距离更好)。

从算法的2D版本开始,看它是如何工作的,然后添加第三个维度。对于测试,您需要一个矩阵,它可以为每个坐标加上快速距离算法保持真/假。如果sqrt()太慢,请尝试Manhattan Distance,如果所有坐标都是整数(没有小数位),有时就足够了。

答案 2 :(得分:1)

您可以使用Iterator

public class Point3D {

    // NOT the way to do it but done like this for sumplicity.
    int x, y, z;

    public Point3D(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public Point3D(Point3D p) {
        this(p.x, p.y, p.z);
    }

    public Point3D add(Point3D p) {
        return new Point3D(x + p.x, y + p.y, z + p.z);
    }

    public String toString() {
        return "{" + x + "," + y + "," + z + "}";
    }
}

public class Point3DIterator implements Iterator<Point3D> {

    final Point3D start;
    final List<Point3D> steps;
    int i = 0;
    Point3D next;

    public Point3DIterator(Point3D start, List<Point3D> steps) {
        this.start = start;
        this.steps = steps;
        this.next = start;
    }

    @Override
    public boolean hasNext() {
        if (next == null) {
            if (i < steps.size() - 1) {
                next = start.add(steps.get(++i));
            }
        }
        return next != null;
    }

    @Override
    public Point3D next() {
        Point3D n = next;
        next = null;
        return n;
    }

}

public void test() {
    // The traversal order.
    List<Point3D> steps = Arrays.asList(new Point3D(0, 0, 0), new Point3D(1, 0, 0), new Point3D(1, 1, 0), new Point3D(0, 1, 0), new Point3D(0, 1, 1), new Point3D(0, 0, 1), new Point3D(1, 0, 1));
    // The iterator.
    Iterator<Point3D> i = new Point3DIterator(new Point3D(10, 10, 10), steps);
    while (i.hasNext()) {
        System.out.println(i.next());
    }
}

您还可以添加Iterable

public class Around implements Iterable<Point3D> {

    final List<Point3D> steps;
    final Point3D center;

    public Around(Point3D center, int d) {
        this.center = center;
        steps = new ArrayList<>(24);
        for (int x = -d; x <= d; x++) {
            for (int y = -d; y <= d; y++) {
                for (int z = -d; z <= d; z++) {
                    if (x != 0 || y != 0 || z != 0) {
                        steps.add(new Point3D(x, y, z));
                    }
                }
            }
        }
    }

    @Override
    public Iterator<Point3D> iterator() {
        return new Point3DIterator(center, steps);
    }

}

public void test() {
    for (Point3D p : new Around(new Point3D(10, 10, 10), 2)) {
        System.out.println(p);
    }
}

答案 3 :(得分:1)

我不确定这种方法对你来说是最好的,但你可以试试这个:

// let X be your matrix length in every direction
// we iterate through the sum of the indexes in the matrix
for (int k = 0; k <= 3 * (X - 1); k++) {
    // now we distribute this value k through the 3 indexes in every way
    // possible (taking care not to surpass the matrix length)
    int limitOne = k < X ? k : X - 1; // limit for the first index
    for (int j = 0; j <= limitOne; j++) {
        int limitTwo = (k - j) < X ? k - j : X - 1;// limit for the
                                                    // second index
        for (int i = 0; i <= limitTwo; i++) {
            // the third index is calculated by extracting the other 2
            // indexes so we need to make sure it isn't too big
            if (k - (j + i) < X) { // limit for the third index

                // do something with yourMatrix[j][i][k-(j+i)]
                // System.out.println("Index: " + j + " " + i + " "
                // + (k - (j + i)));
            }
        }
    }
}

对于不同的索引:

int[][][] yourMatrix = new int[2][3][3];
// note that we need the length to be constant through the indexes
int x = yourMatrix.length;
int y = yourMatrix[0].length;
int z = yourMatrix[0][0].length;
// we iterate through the sum of the indexes in the matrix
for (int k = 0; k <= 3 * (x + y + z - 3); k++) {
    // now we distribute this value k through the 3 indexes in every way
    // possible (taking care not to surpass the matrix length)
    int limitOne = k < x ? k : x - 1; // limit for the first index
    for (int j = 0; j <= limitOne; j++) {
        int limitTwo = (k - j) < y ? k - j : y - 1; // limit for the
                                                    // second index
        for (int i = 0; i <= limitTwo; i++) {
            if (k - (j + i) < z) { // limit for the third index

                // do something with yourMatrix[j][i][k-(j+i)]
                System.out.println("Index: " + j + " " + i + " "
                        + (k - (j + i)));

            }
        }
    }
}

索引的输出示例:

Index: 0 0 0
Index: 0 0 1
Index: 0 1 0
Index: 1 0 0
Index: 0 0 2
Index: 0 1 1
Index: 0 2 0
Index: 1 0 1
Index: 1 1 0
Index: 0 1 2
Index: 0 2 1
Index: 1 0 2
Index: 1 1 1
Index: 1 2 0
Index: 0 2 2
Index: 1 1 2
Index: 1 2 1
Index: 1 2 2

如果你寻找“对角线”距离,那么你可以使用类似的东西,但更改一些更合适的限制。虽然您甚至可能需要添加其他循环...

答案 4 :(得分:1)

螺旋顺序

想象一下立方体站在它的角落。它可以被飞机切割。每个平面与立方体的交点是三角形或六边形。交叉点处的坐标的总和对于该交叉点的每个点是相同的。我们称之为一个级别。

Cube levels

0级是微不足道的 - 它只是一个顶点。

1级包含三个顶点。它的螺旋路径包含两条线:向右一步,向下一步。

Level 1

2级包含6个顶点。螺旋路径:向右两步,两步到底,一步到顶。

Level 2

等级3:右边三步,底部三步,顶部两步,右边一步。

Level 3

在立方体5x5x5中,我们有1个角顶点,5个三角形,然后是4个六边形,然后是5个三角形,再次以最后一个角点顶点结束。

以下是以螺旋顺序打印第一个三角形坐标的算法。六边形算法可以用相同的方式编写。

Each level coordinates sum equals to the level.
Level 0: ( 0, 0, 0 )
Level 1: ( 1, 0, 0 ) - decrement value at 0 and increment value at 1 to get next vertex coordinates
         ( 0, 1, 0 ) - decrement 1 and increment 2 to get next coordinates
         ( 0, 0, 1 )
Level 2: ( 2, 0, 0 ) - dec 0, inc 1 to get next line
         ( 1, 1, 0 ) - dec 0, inc 1
         ( 0, 2, 0 ) - dec 1, inc 2
         ( 0, 1, 1 ) - dec 1, inc 2
         ( 0, 0, 2 ) - dec 2, inc 0
         ( 1, 0, 1 )
Level 3: ( 3, 0, 0 ) - dec 0, inc 1
         ( 2, 1, 0 ) - dec 0, inc 1
         ( 1, 2, 0 ) - dec 0, inc 1
         ( 0, 3, 0 ) - dec 1, inc 2
         ( 0, 2, 1 ) - dec 1, inc 2
         ( 0, 1, 2 ) - dec 1, inc 2
         ( 0, 0, 3 ) - dec 2, inc 0
         ( 1, 0, 2 ) - dec 2, inc 0
         ( 2, 0, 1 ) - dec 0, inc 1
         ( 1, 1, 1 )

你能看到模式吗?

每个级别的模式都会重复几次。

Level 1: pattern 1 then pattern 2
Level 2: pattern 1 twice then pattern 2 twice, then pattern 3
Level 3: pattern 1 thrice then pattern 2 thrice, then pattern 3 twice, then pattern 1 again

所以我们得到:

Level 1: 1, 1
Level 2: 2, 2, 1
Level 3: 3, 3, 2, 1
Level 4: 4, 4, 3, 2, 1
Level 5: 5, 5, 4, 3, 2, 1

应用这些模式可以得到正确的螺旋顺序。

import java.util.Arrays;
import java.util.Iterator;

public class CoordsPrinter {
  public static final int COORDS_CNT = 3;

  public static class CoordsIterator implements Iterator< int[] > {
    private final int maxLevel;
    private final int coords[];
    private int currentLevel;
    private int currentTurn;
    private int currentStep;
    private int currentEdge;

    public CoordsIterator( int max ) {
      this.maxLevel = max;
      coords = new int[ COORDS_CNT ];
    }

    @Override
    public boolean hasNext() {
      return currentLevel <= maxLevel;
    }

    @Override
    public int[] next() {
      int ret[] = coords.clone();
      int stepsQuantity = currentTurn == 0 ? currentLevel : currentTurn == currentLevel ? 2 : currentLevel - currentTurn + 1;
      int nextEdge = currentEdge + 1;
      if ( nextEdge == COORDS_CNT )
        nextEdge = 0;
      coords[ currentEdge ]--;
      coords[ nextEdge ]++;
      currentStep++;
      if ( currentStep >= stepsQuantity ) {
        currentTurn++;
        currentStep = 0;
        if ( currentTurn > currentLevel ) {
          currentLevel++;
          currentTurn = 0;
          currentEdge = 0;
          Arrays.fill( coords, 0 );
          coords[ 0 ] = currentLevel;
        } else
          currentEdge = nextEdge;
      }
      return ret;
    }
  }

  public static class CoordsIterable implements Iterable< int[] > {
    private final int maxLevel;

    public CoordsIterable( int max ) {
      this.maxLevel = max;
    }

    @Override
    public Iterator< int[] > iterator() {
      return new CoordsIterator( maxLevel );
    }
  }

  public static void main( String args[] ) {
    for ( int coords[] : new CoordsIterable( 5 ) )
      System.out.println( Arrays.toString( coords ) );
  }
}

currentLevel确定三角形的等级。 currentTurn确定我们改变螺旋方向的次数。 currentStep确定我们在当前方向上传递了多少步。 currentEdgenextEdge显示了方向(我们从currentEdge移至nextEdge)。

答案 5 :(得分:0)

我使用的代码:

public Space getNextFreeSpace() {

    double distanceToOrigin = 0;
    double smallestDistanceYet=100;
    Space nearestFreeSpace = new Space(); // = originSpace
    for (int k = 0; k<5; k++) {
        for (int l = 0; l<5; l++) {
            for (int m = 0; m<5; m++) {

                if (workingMatrix[k][l][m] == 0) { // That space is free, let's check the 6 directions around it
                    distanceToOrigin = Math.sqrt(k*k+l*l+m*m);
                    if (distanceToOrigin<smallestDistanceYet) {
                        smallestDistanceYet = distanceToOrigin;
                        nearestFreeSpace = new Space(k, l, m, isPair(k, l, m));
                    }
                }
            }
        }
    }
    return nearestFreeSpace;
}