【问题标题】:Traversal of an n-dimensional spacen维空间的遍历
【发布时间】:2012-04-19 16:23:38
【问题描述】:

我正在尝试编写一个算法,它可以让我遍历 n 维空间内的所有所需点,以找到函数 f(x) 的最小值,其中 x 是大小为 n 的向量。

显然,搜索 2-d 或 3-d 空间相当简单,您可以这样做:

for(int i = 0; i < x; i++) {
    for(int j = 0; j < y; j++) {
        //and so on for however many dimensions you want

不幸的是,对于我的问题,空间的维数不是固定的(我正在为统计程序中的许多函数编写一个通用的最小值查找器),所以我必须为我想要的每个 n 值编写循环使用 - 最终可能会相当大。

我一直在努力弄清楚如何使用递归来做到这一点,但我不太清楚解决方案 - 尽管我确信那里有一个。

解决方案不必是递归的,但它必须是通用且高效的(嵌套循环中最内层的行会被调用很多......)。

我表示要搜索的音量的方式是一个二维数组:

double[][] space = new double[2][4];

这将表示一个 4d 空间,其中每个维度的最小和最大边界分别位于数组的位置 0 或 1。例如:

dim         0   1   2   3
    min(0):-10  5  10  -0.5
    max(1): 10 55  99   0.2

有什么想法吗?

【问题讨论】:

  • 我其实不是新手,我只是从很久以前就丢失了我的帐户:P
  • 如何处理带小数的范围,即-0.50.2?此外,您需要在内部循环中处理哪些数据?点数组?
  • 但是,我不认为我的大脑在递归方面工作得不是很好(可能是缺乏练习)所以还没有尝试任何东西 - 只是盯着我的车库墙试图想象它。
  • 您可以从例如:这个问题,因为它是一个等价的问题:stackoverflow.com/questions/8804852/…(我无耻地宣传它,因为我在那里有公认的答案......)提出了一个递归和迭代的解决方案。
  • mellamokb:我使用分辨率函数生成每个维度所需的步长。我实际上不会使用 int i = 0;我

标签: java algorithm search recursion multidimensional-array


【解决方案1】:

大致思路如下:

interface Callback {
   void visit(int[] p); // n-dimensional point
}

// bounds[] - each number the limits iteration on i'th axis from 0 to bounds[i]
// current - current dimension
// callback - point
void visit(int[] bounds, int currentDimension, int[] p, Callback c) {
   for (int i = 0; i < bounds[currentDimension]; i++) {
        p[currentDimension] = i;
        if (currentDimension == p.length - 1) c.visit(p);
        else visit(bounds, currentDimension + 1, p, c);
   }
}

/// now visiting
visit(new int[] {10, 10, 10}, 0, new int[3], new Callback() {
   public void visit(int[] p) {
        System.out.println(Arrays.toString(p));
   }
});

【讨论】:

  • 那应该是currentDimension + 1,而不是currentDimension++,那么它就可以完美运行。否则 +1
  • 我收回了。此解决方案存在一些杂项问题,我冒昧地通过编辑修复了这些问题,希望没问题。
  • 这可能是你能得到的最好的了。你的解决方案大约需要50 ms 平均我从{0,0,0,0} 运行到{50,50,50,50}:ideone.com/oxJDe。通过摆脱这里的递归,我使它变得更快(大约40 ms):ideone.com/uJ4jn
  • 感谢您修复我的解决方案。只是在逃跑时输入了几分钟 :) 是的,如果我最初输入 currentDimension++,那显然是错误的。它也应该是 == p.lenght -1。
  • 啊,但是将真实索引映射到固定整数范围很容易。这太棒了。
【解决方案2】:

我会坚持使用reucrsion,并使用Object作为参数,并使用dim的额外参数,并在达到相关数组的深度1时将其强制转换[在我的示例中,它是一个int[]]

public static int getMin(Object arr, int dim) {
    int min = Integer.MAX_VALUE;
    //stop clause, it is 1-dimensional array - finding a min is trivial
    if (dim == 1) { 
        for (int x : ((int[])arr)) {
            min = Math.min(min,x);
        }
    //else: find min among all elements in an array of one less dimenstion.
    } else { 
        for (Object o : ((Object[])arr)) { 
            min = Math.min(min,getMin(o,dim-1));
        }
    }
    return min;
}

示例:

public static void main(String[] args) {
    int[][][] arr = { { {5,4},{2}, {35} } , { {2, 1} , {0} } , {{1}}};
    System.out.println(getMin(arr, 3));
}

将产生:

0

这种方法的优点是不需要对数组进行任何处理 - 您只需按原样发送它,并将维度作为参数发送。
缺点 - 类型 [un] 安全,因为我们将 Object 动态转换为数组。

【讨论】:

    【解决方案3】:

    另一种选择是从 0 迭代到 x*y*z*...,就像在二进制和十进制表示之间转换数字时所做的那样。这是一个非递归解决方案,因此您不会遇到性能问题。

    ndims = n;
    spacesize = product(vector_sizes)
    int coords[n];
    
    for (i = 0; i < spacesize; i++) {
        k = i;
        for (j = 0; j < ndims; j++ ) {
             coords[j] = k % vector_sizes[j];
             k /= vector_sizes[j];
        }
        // do something with this element / these coords
    }
    

    【讨论】:

    • This is a non-recursive solution, so you won't run into performance issues. 这不是一个真正相关的声明。递归解决方案实际上可能更有效,因为它们不必不断重新填充内部数组,并且递归级别永远不会比维数更深。另外,由于值都是双精度值,因此您的解决方案会遇到舍入错误的问题。
    • 您将调用 spacesize 许多函数(完整的树),然后通过复制或指针传递坐标(Eugenes 解决方案中的 p)。你会做更多的工作。
    • 如果你有 coords[j] = stepfunction(k, vector_sizes[j]) 和双坐标,就不会有舍入误差。
    • 例如,我针对@Eugene 的解决方案对您的解决方案进行了一些分析。从{0,0,0,0} 运行到{50,50,50,50},您的解决方案大约需要650 ms,而@Eugene 需要大约50 ms。如果您不相信我,请查看ideone.com/oxJDeideone.com/nUdrl,它们是我对具有输出和时序的两种解决方案的工作实现。
    • 有趣。我没想到。
    【解决方案4】:

    n 维数组可以展平为一维数组。您需要对这些事情进行数学运算:

    • 计算所需的一维数组的大小。
    • 找出从 n 维索引转换回一维索引所需的公式。

    这就是我要做的:

    • 将 n 维数组大小和索引表示为 int[]。因此,5x7x1​​3x4 4 维数组的大小表示为 4 元素数组 `{ 5, 7, 13, 4 }'。
    • n 维数组表示为一维数组,其大小是每个维度大小的乘积。因此,5x7x1​​3x4 数组将表示为大小为 1,820 的平面数组。
    • n 维索引通过乘法和加法转换为平面数组中的唯一索引。因此,5x7x1​​3x4 数组中的索引 被转换为3 + 2*5 + 6*5*7 + 0*5*7*13 == 223。要访问该 4 维索引,请访问平面数组中的索引 223。
    • 您还可以从平面数组索引向后转换为 n 维索引。我将把它留作练习(但它基本上是在做 n 模计算)。

    【讨论】:

    • java 支持锯齿状数组。不会因为这些而失败吗? [即:{{1,2,3},{1}}]
    • @amit:我打算评论你的回答。 OP 不是在寻找锯齿状数组。他们正在寻找搜索整个 n 维网格空间。
    • 那么这个解决方案很合适。 IMO,您应该为其添加明确的指示,以供将来的读者使用。
    【解决方案5】:

    功能不就是:

    Function loopDimension(int dimensionNumber)
        If there is no more dimension, stop;
        for(loop through this dimension){
             loopDimension(dimensionNumber + 1);
        }
    

    【讨论】:

      【解决方案6】:

      这会遍历值列表(整数)并选择每个列表的最小值:

      import java.util.*;
      /**
          MultiDimMin
      
          @author Stefan Wagner
          @date Fr 6. Apr 00:37:22 CEST 2012
      
      */
      public class MultiDimMin
      {
          public static void main (String args[])
          {
              List <List <Integer>> values = new ArrayList <List <Integer>> ();
              Random r = new Random ();
              for (int i = 0; i < 5; ++i)
              {   
                  List<Integer> vals = new ArrayList <Integer> ();            
                  for (int j = 0; j < 25; ++j)
                  {   
                      vals.add (100 - r.nextInt (200));   
                  }
                  values.add (vals);
              }
              showAll (values);
              List<Integer> res = multiDimMin (values);
              show (res);
          }
      
          public static int minof (List <Integer> in)
          {
              int res = in.get (0);
              for (int v : in)
                  if (res > v) res = v;
              return res;
          }
      
          public static List<Integer> multiDimMin (List <List <Integer>> in)
          {
              List<Integer> mins = new ArrayList <Integer> ();
              for (List<Integer> li : in) 
                  mins.add (minof (li));
              return mins; 
          }
      
          public static void showAll (List< List <Integer>> lili)
          {
              for (List <Integer> li : lili) {
                  show (li);
                  System.out.println ();
              }
          }   
      
          public static void show (List <Integer> li)
          {
              for (Integer i: li) {
                  System.out.print (" " + i);
              }
              System.out.println ();
          }   
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-15
        • 2021-12-28
        • 1970-01-01
        • 1970-01-01
        • 2017-07-20
        • 2012-05-07
        相关资源
        最近更新 更多