获取1-n之间不重复随机数的几种方法

获取1-n之间不重复随机数的几种方法

 

最近接到一个小任务,给定一个整数n,获取1-n之间不重复的n个随机数。于是我便动手写了写,发现实现不难,但是一般时间复杂度都比较高,于是思考了一下,又看了其他一些人的思路,最终总结了以下三种实现方式。

第一种:最常规的方式,flag标志位判重,这种方式是最容易想到的,也是时间复杂度很高的一种.

package com.wl.test3;

import java.util.Scanner;

/**
 * 给定一个整数n,生成1-n之间不同的n个随机整数
 * Math.random()-->[0.0,1.0)
 * @author Administrator
 *
 */
public class TestRandom {
    public static void getRandom(int n) {
        /** 生成的n个随机数数组 */
        int[] numbers = new int[n];
        /** 随机数的个数 */
        int count = 0;
        while (count < n) {
            /** 生成[1,n+1)之间的随机整数 */
            int number = (int) (Math.random() * n + 1);
            /** 标志位,用于判断生成的随机整数是否已经存在相同的 */
            boolean flag = true;
            /** 第count个整数与前边生成的count-1个数进行比较 */
            for (int i = 0; i < count; i++) {
                /** 若存在相同的,标志位置false,跳出循环,重新生成一个整数 */
                if (number == numbers[i]) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                numbers[count] = number;
                count++;
            }
        }
        for (int num : numbers) {
            System.out.println(num);
        }
    }
    @SuppressWarnings("resource")
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("请输入一个整数n:");
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        long start =System.currentTimeMillis();
        getRandom(n);
        long end =System.currentTimeMillis();
        System.out.println("共耗时:"+(end-start)+"毫秒");
    }
}

第二种:使用set集合判重,运行时间上要比第一种快些,但是因为set底层实现本身时间复杂度就要o(n),所以使用起来也并不是很理想。

package com.wl.test3;

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class TestRandom2 {
    public static void getRandom(int n,Set<Integer> set) {
        int size=0;
        while(size<n){
                int number = (int) (Math.random() * n + 1);
                set.add(number);
                size=set.size();
        }
        for(Integer num:set){
            System.out.println(num);
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("请输入一个整数n:");
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        Set<Integer> set=new HashSet<Integer>();
        long start=System.currentTimeMillis();
        getRandom(n,set);
        long end=System.currentTimeMillis();
        System.out.println("运行时间:"+(end-start)+"毫秒");
    }
}

第三种:使用两个数组,一个存储有序的可能生成的所有的随机数数值,一个存放最终生成的随机数。生成的随机数不再直接取,而是作为数组索引,在数组生成的随机索引的位置取相应元素,这样也能保证取得元素是随机的,而且生成的随机数范围逐渐减小,可以避免出现重复值,这种是时间复杂度最低的一种。

package com.wl.test3;

import java.util.Scanner;

public class TestRandom11 {
    public static void dis(int n) {
        /**存放1-n元素的数组,便于随机选取*/
        int[] b =new int[n];
        /**存放生成的随机数的数组*/
        int[] a=new int[n];
        /**生成的随机数的上界,即获取数组索引的上界*/
        int max=n;
        /**生成元素为1-n的数组*/
        for(int i=0;i<n;i++) {
            b[i]=i+1;
        }
        for(int i=0;i<n;i++) {
            /**随机生成一个数,作为获取数组元素的索引,实际取得随机数还是数组b中的元素*/
            int index=(int) (Math.random() * max );                                                               
            /**随机数作为数组b的索引获取该索引位置上的元素,赋给数组a,保证a中的元素是随机获取的*/
            a[i]=b[index];
            /**将数组b最后一个元素赋给该索引位置的元素*/
            b[index]=b[max-1];
            /**max递减,避免获取数组b中的最后一个元素,出现重复的现象*/
            max--;
        }
        for(int i=0;i<n;i++) {
            System.out.println(a[i]);
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("请输入一个整数n:");
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        long start =System.currentTimeMillis();
        dis(n);
        long end =System.currentTimeMillis();
        System.out.println("共耗时:"+(end-start)+"毫秒");
        
    }
}
比较:

1.生成100个随机数,数量不大,因此三种方式的运行时间也差别不大,大概有在2,3毫秒左右。

2.生成1000个随机数,数量增加,也不是很大时,第一二种方式,差别不大,大概分别是19,22毫秒左右,而第三种则有明显提升,13毫秒左右。

3.生成10000个随机数,数量比较大时,差别很大,第一种耗时617毫秒,第二种耗时109毫秒,第三种则耗时64毫秒,此时第一种方式可以很明显的看出速度很慢。

总结一下,在生成大量的随机数时,还是推荐使用第三种方式。

 

 

 

猜你喜欢

转载自www.cnblogs.com/lingFeimao/p/10592995.html