有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在每次调用时生成唯一的随机数

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

  1. # 1 楼答案

    看起来很简单。一个更简单、内存使用更少的解决方案是,只需创建一个集合,它将保存所有您想要的数字,如下所示:

    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);
    }
    

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

  2. # 2 楼答案

    影响:

    • 为了避免两次返回相同的值,您需要跟踪已经生成的数字。这可能会非常消耗内存
    • 最终你的数字会用完。您可以跟踪返回的数字(或仍然可用的数字)的数量,并识别数字是否用完,而不是继续搜索未使用的随机数

    生成的数字可以在集合中进行跟踪。这意味着每个号码有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();
        }
    }
    
  3. # 3 楼答案

    只是

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

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

    根据我的评论:在超过大约50%的数字后,我会创建一个剩余数字的集合,与你的一样,但你应该在课堂上记录,在50%的结果使用率后,它可以冻结片刻,并允许将此系数设置为客户端

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

  4. # 4 楼答案

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

    Random number generator

  5. # 5 楼答案

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

    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;
        }
        
    }
    

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

    需要考虑的注意事项

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