【问题标题】:The best way to generate a randomised matrix in Java [closed]在 Java 中生成随机矩阵的最佳方法 [关闭]
【发布时间】:2020-08-11 21:10:09
【问题描述】:

所以我在我的程序中使用了一个偏好矩阵(二维数组),其中每个人将其他成员从最有利到最不利排列。个人将自己排在数组的最后。

例如:

{[1, 2, 3, 4, 5, 0],
 [2, 3, 4, 5, 0, 1],
 [3, 4, 5, 0, 1, 2],
 [4, 5, 0, 1, 2, 3],
 [5, 0, 1, 2, 3, 4],
 [0, 1, 2, 3, 4, 5]}

如何随机生成一个像上面这样的矩阵,其中最后一个元素代表用户的数字 0-n,其余 n-1 个元素是随机序列中的任意数字?

【问题讨论】:

  • 到目前为止你尝试过什么?另外,请定义“最佳”,因为它对不同的人可能意味着不同的东西。
  • 这其中的哪一部分你自己不知道怎么做?例如,您是否能够令人满意地生成单行?

标签: java arrays matrix random generate


【解决方案1】:

您可以使用Collections.shuffle(list) 来打乱任何列表,但奇怪的是,java API 没有Arrays.shuffle(arr),并且将int[] 转换为集合以便您可以将其提供给Collections.shuffle 效率相当低。

对于你拥有的这么大的集合,这真的无关紧要;只有当我们谈论 100,000 个或更多数字时,这才会成为一个问题。

因此,简单易读的方法是列出除个人索引之外的所有元素,将其随机排列,最后扔掉用户的索引,瞧:

public int[][] makeRandom(int n) {
  int[][] out = new int[n][];

  for (int i = 0; i < n; i++) { // for each person
    // make a list of their preferences
    List<Integer> list = new ArrayList<Integer>();
    for (int j = 0; j < n; j++) {
      // add everybody except yourself
      if (j != i) list.add(j);
    }
    Collections.shuffle(list); // randomize
    list.add(i); // add yourself
    // turn into an int array
    int[] arr = list.stream().mapToInt(Integer::intValue).toArray();
    // set the int array, representing person i's prefs.
    out[i] = arr;
  }

  return out;
}

如果您确实需要一种尽可能高效运行的算法,则必须创建java.util.Random 的新实例,并使用其.nextInt() 方法,以便应用Fisher-yates shuffle 算法你自己,就地,在现有的 int 数组列表上,甚至在你的洗牌过程中方便地跳过数组中的最后一个数字。那将是更多代码,需要更多复杂的 cmets。无论如何,请随意,但我会将其作为练习留给读者。

【讨论】:

    【解决方案2】:

    如何随机生成一个像上面那样的矩阵,其中最后一个元素代表用户的数字 0-n,其余 n-1 个元素是随机序列中的任意数字? 这是另一种方法。

    int n = 6;
    

    这定义了一个简单的 lambda 来

    • 有效地将用户的号码移动到数组的末尾
    • 打乱数组,不包括最后一个元素(用户编号)。
    BiFunction<int[],Integer,int[]> shuffle = (ar,ii)->{
        int len = ar.length-1;
        ar[len] = ar[ii];
        ar[ii] = len--;
        while (len >= 0) {
            int i = (int)(Math.random()*len);
            int t = ar[i];
            ar[i] = ar[len];
            ar[len--]=t;
        }
        return ar;
    };
        
    

    现在构建一个从0 to n 出发的数组。

    int[] arr = IntStream.range(0, n).toArray();
    

    时间到shuffle 数组和move 用户到 end 并创建最终的数组数组。

    int[][] darr = IntStream.range(0, n)
            .mapToObj(i -> shuffle.apply(arr.clone(), i))
            .toArray(int[][]::new);
    

    现在打印出来

    for (int[] a : darr) {
        System.out.println(Arrays.toString(a));
    }
    

    对于n = 6,打印

    [2, 4, 3, 1, 5, 0]
    [2, 4, 5, 0, 3, 1]
    [4, 5, 3, 0, 1, 2]
    [4, 0, 5, 1, 2, 3]
    [5, 3, 0, 2, 1, 4]
    [3, 0, 4, 2, 1, 5]
    
    

    【讨论】:

      【解决方案3】:

      编辑: 首先生成矩阵,其中每行中的数字为 0,1,2...n-1 之后在每个矩阵的行上调用 shuffle 方法。

      这里是短代码sn-p:

      public int[][] generateRandomMatrix(int rows,int cols){
              int[][] matrix = new int[rows][cols];
              for(int i=0;i<rows;i++) {
                  for(int j=0;j<cols;j++) {
                      matrix[i][j]=j;
                  }
                  shuffle(matrix[i]);
              }
              return matrix;
          }
          
      public void shuffle(int[] arrray){
              Random r = ThreadLocalRandom.current();
              int n = arrray.length;
              for (int i=0;i<n;i++){
                int index = r.nextInt(i + 1);
                int a = arrray[index];
                arrray[index] = arrray[i];
                arrray[i] = a;
              }
            }
      

      【讨论】:

      • 这个没用;问题涉及将每个子数组生成为仅包含一次所有数字,最后一个条目始终是固定值。你的可能会跳过数字并重复其他数字,因为随机是不会做的。这不是 OP 想要的。
      • 哦,我没听懂。我会更正我的代码
      猜你喜欢
      • 1970-01-01
      • 2010-11-12
      • 1970-01-01
      • 2020-05-18
      • 2016-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多