我不想要这个:
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)增量。
我希望它更清楚。
你知道一种聪明的编码方式吗?
编辑:按此顺序测试矩阵点对于解决此问题非常重要。
答案 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)
想象一下立方体站在它的角落。它可以被飞机切割。每个平面与立方体的交点是三角形或六边形。交叉点处的坐标的总和对于该交叉点的每个点是相同的。我们称之为一个级别。
0级是微不足道的 - 它只是一个顶点。
1级包含三个顶点。它的螺旋路径包含两条线:向右一步,向下一步。
2级包含6个顶点。螺旋路径:向右两步,两步到底,一步到顶。
等级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
确定我们在当前方向上传递了多少步。 currentEdge
和nextEdge
显示了方向(我们从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;
}