在每次通话时生成唯一的随机数

时间:2013-09-25 12:26:02

标签: java arrays collections random

在一次采访中,我被要求提供一种方法,每次调用它时都会生成唯一的5位数随机数。例如:如果我调用方法得到22222,那么在下次通话中我不应该得到22222。

我写了一个代码如下:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

public class RandomNumberGen {


    private static ArrayList arr=new ArrayList();
    private static int k=-1;
    public RandomNumberGen(){
        for (int i=10000;i<99999;i++){
            arr.add(i);
        }
        Collections.shuffle(arr);
    }
    public static void main(String[] args) {
        for(int m=0;m<10;m++){
            try {
                System.out.println(new RandomNumberGen().randomNumbermethod());
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }


    }
    public Integer randomNumbermethod() throws Exception{
        k++;
        if(k>=arr.size()){
            throw new Exception("No more number available");
        }else return (Integer) arr.get(k);
    }

}

答案被接受但我被要求现在避免记忆浪费。  我的问题在这里,因为你可以看到我只使用了10个数字。所以arraylist占用的剩余空间是一个记忆 - 浪费。有一种方法我可以实现同样的事情而不需要额外的记忆。     我的意思是在某种程度上使用哪个唯一编号可以在每个调用中生成,这样就不会浪费这么多内存。

5 个答案:

答案 0 :(得分:6)

private static int number = 10000;
public int getNextUniqueRandomNumber() {
   return number++;
}

Random number generator

答案 1 :(得分:6)

意义:

  • 为了不再返回两次相同的值,您需要跟踪您已生成的数字。这可能非常耗费内存。
  • 你最终用完了数字。您可以跟踪您返回的数量(或者仍有多少数字)而不是继续搜索未使用的随机数,并确认您是否用完了数字。

可以在集合(设置)中跟踪生成的数字。这意味着每个数字的开销为32位(当跟踪可用或生成的数字时)加上收集开销。另一种可能性是使用布尔数组并标记已使用的插槽。同样,这是一个开销,因为布尔值通常存储为32位值。
但是有一种更便宜的方式来存储布尔值:作为整数的打包位。这就是java.util.BitSet所做的,所以每个布尔值都会占用一位。

使用BitSet解决方案并跟踪可用的数量:

public class RandomNumbers {

    private final Random random = new Random();
    private final BitSet used = new BitSet();
    private final int min = 10000;
    private final int max = 99999;
    private final int numbersAvailable = max - min + 1;

    public static void main (String[] args) {

        RandomNumbers randomNumbers = new RandomNumbers();
        for (int i = 0; i < 100; i++) {
            System.out.println(randomNumbers.nextRandom());
        }
    }

    public int nextRandom () throws NoSuchElementException {

        while (numbersAvailable > 0) {
            int rnd = min + random.nextInt(max - min + 1);
            if (!used.get(rnd)) {
                used.set(rnd);
                numbersAvailable--;
                return rnd;
            }
        }
        throw new NoSuchElementException();
    }
}

答案 2 :(得分:5)

只需

(int)(Math.random()*89999)+10000

编辑后:(编辑前没有理解) - 你可以将生成的数字放在HashSet中,然后随机检查一下是否包含新编号(如果你多次使用它会很慢,但是我如果你不需要很多数字,我认为这是一个很好的解决方案。

从我的评论中:在大约50%的数字出来之后,我会创建一个剩余数字的集合,与你的相同,但是你应该在课堂上记录,它可以在50%的结果使用后冻结片刻并给出能够将此因素设置为客户。

根据“生成数字中必须有多少随机性”(例如序列生成器的数学方法),可能是更好的方法

答案 3 :(得分:4)

看起来很简单。一个更简单的解决方案,内存使用量更少,只需创建一个包含所需数字的集合,如下所示:

Random random = new Random();
Set<Integer> randomNumbers = new HashSet<Integer>(10);
while(randomNumbers.size() < 10)
    randomNumbers.add( new Integer(random.nextInt(89999) + 10000) );

并查看所有内容:

for(Integer randomNumber : randomNumbers){
    System.out.println(randomNumber);
}

这将保证集合属性的唯一性,并大大提高您的内存使用率。

答案 4 :(得分:1)

您的方法确实非常适合创建大量唯一值,但是如果您只创建少量唯一值,那么简单地跟踪使用的值以保证唯一性会更有效

import java.util.Collection;
import java.util.HashSet;
import java.util.Random;

public class UniqueRandom {

    static Random rnd=new Random();

    public static void main(String args[]){
        Collection<Integer> alreadyChosen = new HashSet<Integer>();
        for(int i=0;i<10;i++){
            System.out.println(getNextUniqueRandom (alreadyChosen));
        }
    }


    public static int getNextUniqueRandom(Collection<Integer> alreadyChosen){
        if (alreadyChosen.size()==90000){ //hardcoded 5 figure numbers, consider making a variable
             throw new RuntimeException("All 5 figure IDs used");
        }


        boolean unique=false;
        int value=0;
        while(unique==false){
            value=rnd.nextInt(90000)+10000;
            unique=!alreadyChosen.contains(value);
        }
        alreadyChosen.add(value);
        return value;
    }

}

当只需要一小部分可用范围时,这种方法非常有效,但随着碰撞变得更加普遍,这种方法变得越来越慢。您应该选择的确切实现在很大程度上取决于您需要获得多少值。

需要考虑的注意事项

  • 如前所述,随着更多值的增加,这将变得非常缓慢 选择,应该向最终用户明确,甚至更好;在这么多电话之后改变算法