了解使用随机数填充数组(Big Java Ex 7.4)

时间:2016-08-04 14:29:54

标签: java arrays

问题陈述

  

编写一个程序,生成数字1到的随机排列   10.要生成随机排列,您需要使用数字1到10填充数组,以便阵列中没有两个条目具有相同的   内容。你可以通过调用Random.nextInt来强行完成   直到它产生一个尚未在数组中的值。相反,你   应该实施一种智能方法。制作第二个数组并填充它   数字1到10.然后随机选择其中一个,删除它,然后   将它附加到排列数组。重复10次。实现一个类   PermutationGenerator,方法为int [] nextPermutation

我在理解问题所说的内容方面遇到了一些麻烦。

我的解释是,我们需要将数字1-10放在数组中,给出一些随机数,范围从1到10。

我解决这个问题的方法是简单地添加一个数组并进行循环,然后检查下一个随机数是否已经在数组中。但是根据这个问题,这被视为"蛮力"

通过实施第二个阵列,我不确定我的书是什么意思。如果我赢得第二个阵列,我仍然需要检查阵列中是否有东西?

我的尝试 首先,我只是试图将10个随机数放入一个数组中,而忽略了它们必须区分的部分。继承人我有什么

private int[] arr;
private Random randNum;

public seq()
{
    randNum = new Random();
    arr = new int[10];
}

public int getRandNum()
{
    int newNum = randNum.nextInt(10)+1;
    return newNum;
}

public int [] filledArr()
{
    for (int i = 0 ; i<arr.length; i++)
    {
        arr[i] = getRandNum();
    }
    return arr;
}

问题在于,我必须拨打getRandNum() 10次才能获得10个不同的号码,然后拨打filledArr将其放入。这很难打字。有没有更好的办法?我想我也可以在主内部制作一个for循环,然后这样做?这看起来非常低效。

感谢任何建议

另一个 尝试

class seq
{
    private int[] arr;
    private int[] filledArr;
    private Random randNum;

    public seq()
    {
        randNum = new Random();
        arr = new int[10];
        filledArr = new int[10];
    }

    public int [] generateNewArr()
    {
        for(int i = 1; i< 11 ; i++)
        {
            filledArr[i] = i;
        }
        return filledArr;
    }

    public int [] newArr()
    {
        for(int i=1; i < 11 ; i++)
        {
            int newRandNum = //RANDOM NUMBER IN filledArr;
            arr[i] = newRandNum;
            // REMOVE that random number from filledArr
        }
    }

}

与ARRAYLISTS的关系

 import java.util.Random;
import java.util.ArrayList;
class seq
{
    private ArrayList<Integer> arrListOne;
    private ArrayList<Integer> arrListTwo;
    private Random num;
    public seq()
    {
        num = new Random();
        arrListOne = new ArrayList<Integer>(10);
        arrListTwo = new ArrayList<Integer>(10);
    }
    public ArrayList getFilledArr()
    {
        for(int i = 1; i < arrListOne.size()+1 ; i++)
        {
            arrListOne.add(i);
        }
        return arrListOne;
    }
    public ArrayList randNewArr()
    {
        for(int i = 0 ; i < 10 ; i++)
        {
        int randNum = num.nextInt(arrListOne.size())+1;
        arrListTwo.add(arrListOne.get(randNum));
        arrListOne.remove(arrListOne.get(randNum));
        }
        return arrListTwo;
    }

    public String toString()
    {
        String output = "The Randomized ArrayList is";
        output+=arrListTwo;
        return output;
    }
}

public class Sequence
{
    public static void main(String [] args)
    {
    seq seqObj = new seq();
    seqObj.getFilledArr();
    seqObj.randNewArr();
    System.out.println(seqObj.toString());
    }

}

6 个答案:

答案 0 :(得分:1)

  

这个问题是我必须调用getRandNum()10次以获得10个不同的数字,然后调用filledArr将其放入其中。这很难打字。还有更好的方法吗?

是的。

使用此:

public int [] filledArr()
{
    for (int i = 0 ; i < arr.length; i++)
    {
        arr[i] = randNum.nextInt(10)+1;
    }

return arr;
}

因此您的编码较少且结果相同。

答案 1 :(得分:1)

问题只是这样说:

  

制作一个数字为1-10的数组(不必随意排序)。然后   生成1-10之间的随机数并选择该数字并删除该索引   来自你之前创建的数组。

粗略的实施将是:

ArrayList nums = new ArrayList<Integer>(); // The arraylist with numbers from 1-10
for(int i = 1; i < 11; i++;)
    nums.add(i);

Random r = new Random();
int x = r.nextInt(10);

int[] finalNums = new int[2];
finalNums[0] = nums.get(x);
nums.remove(x); // Remove the number at this index so it won;t be picked up again

x = r.nextInt(9); // Since we removed one index from arraylist, so total elements are now nine instead of 10.
finalNums[1] = nums.get(x);
nums.remove(x);

那么区别是什么?在这种方法中,您确信它不会两次选择相同的数字。为什么?因为您在选择号码后立即删除该号码,因此不会再次接收号码。

修改

至于你在ArrayList中尝试询问你在main块中写了什么的尝试,你只需要按顺序调用你在课堂上创建的两个方法。它可以在主要块中:

public class Sequence
{
    // You need one main method atleast to run the code
    public static void main(String[] args){
        seq seqObj = new seq();
        System.out.println(seq.getRandomArray());
    }
}

或者您也可以在seq课程中调用这些方法&#39;构造:

public seq()
{
    randNum = new Random();
    arr = new int[10];
    filledArr = new int[10];
    this.getFilledArr();
    this.randNewArr();
}

另外需要注意的是,显示ArrayList输出的方法没问题。对您的代码稍作修正:

import java.util.Random;
import java.util.ArrayList;
class seq
{
    private ArrayList<Integer> arrListOne;
    private ArrayList<Integer> arrListTwo;
    private Random num;

    public seq()
    {
        num = new Random();
        arrListOne = new ArrayList<Integer>();
        arrListTwo = new ArrayList<Integer>();
        getFillerArr();
        randNewArr();
    }

    // You dont have to return ArrayList here
    public void getFilledArr()
    {
        for(int i = 1; i < 11 ; i++)
        {
            arrListOne.add(i);
        }
    }

    // You dont have to return ArrayList here
    public void randNewArr()
    {
        for(int i = 0 ; i < 10 ; i++)
        {
            int randNum = num.nextInt(arrListOne.size())+1;
            arrListTwo.add(arrListOne.get(randNum));
            arrListOne.remove(arrListOne.get(randNum));
        }
    }

    // A method that returns you random array list so you can easily use it following rules of encapsulation
    public ArrayList<Integer> getRandomArray() {
        return this.arrListTwo;
    }
}

public class Sequence
{
    public static void main(String[] args){
        seq seqObj = new seq();
        System.out.println(seq.getRandomArray());
    }
}

编辑#2:

对于negative bound exception的问题,这就是您的代码应该如何:

    public seq()
    {
        num = new Random();

        // Do not try to specify size of Array List here. THey don't have fixed size.
        arrListOne = new ArrayList<Integer>();
        arrListTwo = new ArrayList<Integer>();
        getFillerArr();
        randNewArr();
    }

    public void getFilledArr()
    {
        // Manually iterate for 10 elements.
        for(int i = 1; i < 11 ; i++)
        {
            arrListOne.add(i);
        }
    }

    public ArrayList randNewArr()
    {
        for(int i = 0 ; i < 10 ; i++)
        {
        // Do not add +1 here, actual array size is already 1 less than the size you get from #size() method.
        int randNum = num.nextInt(arrListOne.size());
        arrListTwo.add(arrListOne.get(randNum));
        arrListOne.remove(arrListOne.get(randNum));
        }
        return arrListTwo;
    }

说明:

arrListOne = new ArrayList<Integer>(10);

在这里,您尝试创建固定大小为10的数组列表?但ArrayLists没有固定的大小。所以这不会起作用。因此你的这个循环也失败了:

public ArrayList getFilledArr()
{
    for(int i = 1; i < arrListOne.size()+1 ; i++)
    {
        arrListOne.add(i);
    }
    return arrListOne;
}

(数组列表的大小为0,因此循环不会运行)。

因此,在获取随机数时会得到该异常。

PS:我很糟糕,自从我做java之后已经有一段时间了。不知何故,我在阅读该代码时忽略了它。

答案 2 :(得分:1)

提示:似乎你并没有理解所建议的“智能”方法;它应该按如下方式进行:

  1. 生成一个包含10个整数的数组,不是随机,只需将所有数字从1到10排序。 还生成一个空数组。

  2. 在循环中,从第一个数组中选取一个随机元素并将其移动到第二个数组。

  3. 你可以从这里继续吗?

    编辑:第三次尝试的主要问题是:

    int randNum = num.nextInt(arrListOne.size())+1;中,你似乎混淆了两件事,整数的值,以及它在数组中的位置。您想要在一个范围内随机选择的内容(从零开始)是位置,因此您应该编写 int randPos = num.nextInt(arrListOne.size());

    此外,类的结构不是很好,你应该使用nextPermutation()方法编写一个类,所有的数组/列表都应该存在于该方法中,唯一的state为作为类中的字段保存应该是随机生成器。我建议在这个结构中编码所有代码:

    public class PermGen {
    
        public final int SIZE = 10; 
        private final Random rand = new Random();
    
        /* returns a new permutation of elements from 1 to 10 (size) */
        public int[] nextPermutation() {
            // create the two lists/arrays here
            int[] res = new int[SIZE];
            List<Integer> list1 = new ArrayList<>(); // or LinkedList  
            // ... fill list1
            for( int i = 0; i < SIZE; i++ ) {
               // pick a random pos1 from list, move the element to res
               // ...
               res[i] = list1.remove(randpos); // move the element  
            } 
            return res;
        }
    }
    

答案 3 :(得分:1)

只是一个想法:

import java.util.ArrayList;
int LEN = 10;
ArrayList<Integer> oldArray = new ArrayList<Integer>();
for (int i = 0; i < LEN; i++)
   oldArray.add(i+1);
int[] newArray = new int[LEN];
for (int i = 0; i < LEN; i++) {
   int pos = (int)(Math.random() * oldArray.size());
   newArray[i] = oldArray.remove(pos);
}

不确定它是否符合标准(使用ArrayList和所有,但只是建议)

答案 4 :(得分:1)

因为这是一个家庭作业问题,显然,我不想给你实际代码,而是要描述它。 (因为你说过不是,我在上面添加了一个完整的答案,但决定也保留这个解释。)

基本上,你是“洗牌一副牌”。首先将数组初始化为顺序1..10。

现在,您可以通过从1..10开始在牌组中循环来“洗牌”牌组,随机选择大于等于(“在......前面或前面”)你的光标位置。 交换两张卡片。

这在功能上等同于“从另一个阵列中随机删除一张卡片”,但它利用了这样一个事实:“一堆混洗卡片”的增长率与“随机抽取的一堆排序卡片”完全相同收缩。因此,它只能在一个数组中完成。混洗部分位于光标后面; (最初)有序部分是在前或后。

一个传递中,你有一张非常洗牌的牌,据说不含重复牌。

答案 5 :(得分:1)

伪代码(不是Java)

$ mix test
.

Finished in 0.2 seconds
1 test, 0 failures

当这个版本的算法运行时,超出光标Card deck[], temp; int i, j; // fill the deck for (i = 0; i < 10; i++) deck[i] = i; // Shuffle 'em. Runs stern-to-stem because of 'rand()' for (i = 9; i > 0; i--) { // no need for (i == 0) ... j = rand(i); // returns value in the inclusive range [0..i] // it's just fine if (i == j) ... although it usually won't be ... temp = deck[i]; // set-aside the card in the cursor-position deck[i] = deck[j]; // replace it with the randomly-chosen card deck[j] = temp; // then put the original card where it can get picked } 位置的卡片就是洗牌,而i中的卡片是半排序的从中随机抽取的牌。 (这个池开始完全排序,但随着元素被交换进去,它变得没有排序,但是谁在乎。)

您将看到此算法在一个传递中的单个数组中工作,产生一个彻底改组的套牌,不包含重复项。该算法与使用两个数组的算法相同,但效率更高:数组就地改组,从不调整大小。

可以使用任何容器类(可调整大小或不可调整大小),但所选容器应该是一个底层实现,允许以相当的速度检索任何随机选择的元素,无论它在何处。例如,“链表”不是一个有效的选择。