Java 在每次通话中生成唯一的随机号码

Java 在每次通话中生成唯一的随机号码,java,arrays,collections,random,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 Array

在一次采访中,我被要求编写一个方法,该方法每次调用时都会生成唯一的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);
    }

}
import java.util.ArrayList;
导入java.util.Collections;
导入java.util.Scanner;
公共类随机数{
私有静态ArrayList arr=new ArrayList();
私有静态int k=-1;
公共随机数{
对于(int i=10000;i

编辑后:(编辑前不理解)-您可以将生成的数字放入
HashSet
中,然后随机检查集合是否包含新的数字(如果您多次使用它,速度会非常慢,但如果您不需要很多数字,我认为这是一个很好的解决方案

根据我的评论:在超过大约50%的数字后,我会创建一个剩余数字的集合来选择,与您的一样,但您应该在课堂上记录,在50%的结果使用率后,它可以冻结片刻,并为客户端提供设置此因子的能力


也许有更好的方法,这取决于生成的数字中必须包含“多少随机性”(例如序列生成器的数学方法)

您的方法确实是创建大量唯一值的理想方法,但是,如果您只创建少量的唯一值,则只需跟踪所使用的值以保证唯一性会更有效

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;
    }
    
}
import java.util.Collection;
导入java.util.HashSet;
导入java.util.Random;
公共类UniqueRandom{
静态随机rnd=新随机();
公共静态void main(字符串参数[]){
Collection alreadyChosen=new HashSet();

for(int i=0;i似乎非常简单。一个更简单、内存使用更少的解决方案是只创建一个集合来保存所有您想要的数字,如下所示:

Random random = new Random();
Set<Integer> randomNumbers = new HashSet<Integer>(10);
while(randomNumbers.size() < 10)
    randomNumbers.add( new Integer(random.nextInt(89999) + 10000) );
这将保证集合属性的唯一性,并大大提高内存使用率

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

  • 为了避免两次返回相同的值,您需要跟踪已经生成的数字。这可能会非常消耗内存
  • 您最终会用完数字。您可以跟踪返回的数字(或仍然可用的数字)并识别是否用完数字,而不是继续搜索未使用的随机数字
生成的数字可以在集合中跟踪(集合)。这意味着每个数字的开销为32位(当跟踪可用或生成的数字时)加上收集开销。另一种可能是使用布尔数组并标记已使用的插槽。同样,这是一种开销,因为布尔值通常存储为32位值。
但是有一种更便宜的存储布尔值的方法:将布尔值压缩为整数中的压缩位。这就是
java.util.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();
    }
}
公共类随机数{
私有最终随机=新随机();
使用的私有最终位集=新位集();
私人最终整数最小值=10000;
私人最终整数最大值=99999;
私有最终整数可用=最大-最小+1;
公共静态void main(字符串[]args){
RandomNumbers RandomNumbers=新的RandomNumbers();
对于(int i=0;i<100;i++){
System.out.println(randomNumbers.nextRandom());
}
}
public int nextRandom()抛出NoTouchElementException{
while(numbersavable>0){
int rnd=min+random.nextInt(max-min+1);
如果(!used.get(rnd)){
已使用。设置(rnd);
可用数量--;
返回rnd;
}
}
抛出新的NoTouchElementException();
}
}

如果您只需要10个值,您可以保留一个已选择值的集合,并检查随机值是否不在其中。对于更多的值来说,这变得越来越可怕,但10可能是很好的。对于这样的集合,Arraylist的复制当然可以,但某些类型的集合(如哈希集)可能要多得多efficient@sp00n这个问题本身与我们无关uniqueness@sp00m我看了那篇文章,但我的问题是关于这种方法的内存浪费。我只需要int/整数。这个方法可以多次调用,直到所有的5位数都结束。我只是通过调用10次来展示一个例子s来显示ememry损耗。因此,我会选择一个可能结果总体的因子。在超过大约50%的数字后,我会创建一个剩余数字的集合来选择,与您的相同(并且您可以对现有集合进行垃圾处理)。编辑答案,并将其转换为整数,返回4位数字和3位数字。@AnujKumarJha已调整为仅返回5位唯一数字。如果您使用了所有随机数字,方法将无限循环,您可以检查
alreadyChosen.size()
如果有机会找到一个新的。或者更好:一旦
alreadyChosen
包含50%的所有数字,切换到未选择的数字列表,每次弹出一个数字,直到列表为空。速度更快,内存消耗减半。@killer\PL如果我真的写这个,我会写它,这样它就改变了它在(比如)10000次调用之后,使用s方法,但所有这些对于SO答案来说都太复杂了。我已经把这些要点说得更清楚了,但是假设您事先知道需要多少ID,这确实很好,这应该是正确的答案。在我的VM中(Linux上的Oracle 1.7 64位)探查器显示
位集
的内存消耗量小于50K,而
哈希集
位集
都提供了摊销常量查找/插入时间。
位集
private static int number = 10000; public int getNextUniqueRandomNumber() { return number++; }
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();
    }
}