java生成抽样随机数的多种算法

本章先讲解Java随机数的几种产生方式,然后通过示例对其进行演示。

概述:

这里你是不是会说,生成随机数有什么难的?不就是直接使用Java封装好了的random就行了么?当然对于一般情况下是OK的,而且本文要说明的这些算法也是基于这个random库函数的。

本文主要是针对抽样这一行为进行的,而抽样本身有一个隐含的规则就是不要有重复数据。好了,有了这些说明。你可以先尝试着用一些自己的想法来实现不重复地生成随机数。

算法尝试:

一些好的算法出现,往往伴随着一些不那么好的算法。但是对于效果不太好的算法,它们普遍有一个共性,方便理解和实现。下面是通过一个循序渐进的方式来作一个简单地说明。

第一次尝试:朴素随机算法

这个算法很好理解,就是随机!每一次产生一个随机数,并加入集合。

 private void simpleRandom(int start, int end, int count) {
    System.out.println("朴素随机算法:");
    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < count; i++) {
      int random = NumberUtils.randomInteger(start, end);
      buffer.append(i == 0 ? ("[" + random) : (", " + random));
    }
    buffer.append("]");
    System.out.println(buffer);
  }

第二次尝试:检查存在性随机算法

我们知道上面的方法有一个问题,就是可能会有重复数据。于是,我们就想到,在生成一个随机数的时候进行检查一下这个数是不是已经存在了,如果存在了就重新生成。

private void checkRandom(int start, int end, int count) {
    System.out.println("检查存在性随机算法:");
    StringBuffer buffer = new StringBuffer();
    List<Integer> save = new ArrayList<>();
    for (int i = 0; i < count; i++) {
      int random = NumberUtils.randomInteger(start, end);
      if (exits(save, random)) {
        i--;
        continue;
      } 

      save.add(random);
      buffer.append(i == 0 ? ("[" + random) : (", " + random));
    }
    buffer.append("]");
    System.out.println(buffer);
  }

第三次尝试:元素移除随机算法

上面的算法已经解决了数据重复的问题。不过,有一个很糟糕的问题就是可能我们要花费很长的时间来生成抽样随机数(这个要看脸了。。。。)。

不过,这里我们有了新想法。那就是在一个集合中去随机一个数,当这个被选中的时候就remove掉,那么下次再随机的时候是不是就不会再随机到这个数了?这样就很好地解决了随机数的重复问题。代码如下:

 private void removeRandom(int start, int end, int count) {
    System.out.println("元素移除随机算法:");
    StringBuffer buffer = new StringBuffer();
    List<Integer> numbers = initList(start, end);
    for (int i = 0; i < count; i++) {
      int random = NumberUtils.randomInteger(count - i);
      buffer.append(i == 0 ? ("[" + numbers.get(random)) : (", " + numbers.get(random)));
      numbers.remove(random);
    } 

    buffer.append("]");
    System.out.println(buffer);
  }

第四次尝试:状态转移随机算法

在我之前的很多博客中,就有一些是算法中的状态转移过程。而状态的转移也是我最喜欢的算法之一。下面的图-1中标注了随机数的取值范围,序列中的橙色数字是结果中的随机序列。最下方的序列中有一些虚线的箭头,代表了状态的转移。

图-1 基于状态转移的抽样随机数生成算法

实现代码:

 private void statusRandom(int start, int end, int count) {
    System.out.println("状态转移随机算法:");
    StringBuffer buffer = new StringBuffer();
    int[] status = new int[end + 1];
    for (int i = 0; i < count; i++) {
      int random = NumberUtils.randomInteger(start, end);
      System.err.println(random);
      if (status[random] == 0) {
        buffer.append(i == 0 ? ("[" + random) : (", " + random));
        status[random] = random == end ? start : (random + 1); // 不可能有在start之前的数字
      } else {
        // 状态转移
        int index = random;
        do {
          index = status[index];
        } while (status[index] != 0); 

        buffer.append(i == 0 ? ("[" + index) : (", " + index));
        status[index] = index == end ? start : (index + 1); // 不可能有在start之前的数字
      }
    } 

    buffer.append("]");
    System.out.println(buffer);
  }

第五次尝试:递归Floyd随机算法

Floyd算法说到底也是一种状态的转移过程。该算法会要求输入一个List或是array来保存已经确定的随机数。顾名思义,这里我会用到递归的解法。在递归的过程中,我们把第i个随机数的状态转移到了第i-1个随机身上了。代码如下:

private List<Integer> simpleFloyd(List<Integer> list, int count, int start, int end) {
    if (count == 0) {
      return list;
    }
    list = simpleFloyd(list, count - 1, start, end - 1);
    int random = NumberUtils.randomInteger(start, end);
    if (list.contains(random)) {
      list.add(end);
    } else {
      list.add(random);
    }
    return list;
  }

第六次尝试:迭代Floyd随机算法

思路与上面的递归Floyd随机算法是相似的,不过,这里我们加入了一个变量来做优化。就不需要再去递归了。代码如下:

private List<Integer> iterationFloyd(int start, int end, int count) {
    System.out.println("迭代Floyd随机算法:");
    List<Integer> list = new ArrayList<>();
    for (int i = end - count + 1; i < end; i++) {
      int random = NumberUtils.randomInteger(start, i);
      if (list.contains(random)) {
        list.add(i);
      } else {
        list.add(random);
      }
    } 

    return list;
  } 

测试结果:

图-2 随机数生成算法测试结果

在上面的测试结果中,我们可以很明显地看出朴素随机算法不仅有重复数据,而且还是最耗时的。所以,在抽样的随机数生成时,避免使用这一算法。而在后几种算法中,状态转移随机算法最佳,迭代Floyd随机算法次之。这个可以根据个人偏爱来做选择。

(0)

相关推荐

  • Java中随机数的产生方式与原理详解

    Java中随机数的产生方式与原理 查阅随机数相关资料,特做整理 首先说一下java中产生随机数的几种方式 在j2se中我们可以使用Math.random()方法来产生一个随机数,这个产生的随机数是0-1之间的一个double,我们可以把他乘以100,他就是个100以内的随机数字,这个在j2me中没有. 在java.util这个包里面提供了一个Random的类,我们可以新建一个Random的对象来产生随机数,他可以生产随机整数.随机float.随机double.随机long,这个也是我们在j2me

  • java生成随机数的常用方法分析

    本文实例讲述了java生成随机数的常用方法.分享给大家供大家参考,具体如下: 前因: 经常性的,测试一些功能时都需要造一些假数据,每次都上网来查一下怎么生成随机数.这回我把查到的方法自己整理一下,下次在用不用到处找了. 生成随机数的几种方法: 1. 使用Math.random()生成随机数 直接贴几个小方法 /** * 获取0.0-1.0之间的随机小数 */ private double test1() { double num = Math.random(); return num; } /*

  • 史上最全的java随机数生成算法分享

    复制代码 代码如下: String password = RandomUtil.generateString(10); 源码如下: 复制代码 代码如下: package com.javaniu.core.util;import java.util.Random;public class RandomUtil { public static final String ALLCHAR = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS

  • 如何用java生成指定范围的随机数

    要生成在[min,max]之间的随机整数, package edu.sjtu.erplab.io; import java.util.Random; public class RandomTest { public static void main(String[] args) { int max=20; int min=10; Random random = new Random(); int s = random.nextInt(max)%(max-min+1) + min; System.

  • JAVA获得包含0-9、a-z、A-Z范围内字符串的的随机数实例

    一.获得0-9,a-z,A-Z范围的随机字符串 复制代码 代码如下: /** * JAVA获得0-9,a-z,A-Z范围的随机数 * @param length 随机数长度 * @return String */ public static String getRandomChar(int length) { char[] chr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',

  • Java实现按权重随机数

    一.问题定义: 问下有一个数组,这些数组中的值都有自己的权重,怎样设计才能高效的优先取出权重高的数?? 例如: 复制代码 代码如下: 权重: 8  2  11  79 权重返回的值: 0  1  2   3 二.分析问题: 思路一:创建一个数组数组大小为权重和的大小,如值0的权重是8,则放入8个0值,值1的权重是2,则放入2个1值,依次类推. 然后用用一个权重和大小的随机数,产生随机数,即可.缺点要占用过多的内存. 思路二: 权重和数组 w[i]存储的是[0,i]元素的所有元素的权重和  时间复

  • Java生成10个1000以内的随机数并用消息框显示数组内容然后求和输出

    本文最终结果大概是这样的,使用java技术随机生成10个数,然后填充一个数组并在消息框中显示数组内容,接着对数组求和输出,将结果显示在消息框中. 设计思路:可以先用Math.Random()*1000生成1000以内随机数,然后依次存入数组中,然后读取数组,输出随机数,同时进行加法计算,最后将所有结果以消息框形式输出. 程序流程图: 源代码: package 随机数求和; import javax.swing.*; public class Sum { public static void ma

  • java生成随机数(字符串)示例分享

    用来生成简单的随机java生成随机数,大小+数字.没特符 复制代码 代码如下: package passwords;import java.util.Random;public class pwdGen { private Random rdseed=new Random(); /**  *@param  *length  password length;  *@param  *letters  boolean non-capital letters combination control; 

  • Java中生成随机数的实现方法总结

    在实际开发工作中经常需要用到随机数.如有些系统中创建用户后会给用户一个随机的初始化密码.这个密码由于是随机的,为此往往只有用户自己知道.他们获取了这个随机密码之后,需要马上去系统中更改.这就是利用随机数的原理.总之随机数在日常开发工作中经常用到.而不同的开发语言产生随机数的方法以及技巧各不相同.笔者这里就以Java语言为例,谈谈随机数生成的方法以及一些技巧. 一.利用random方法来生成随机数. 在Java语言中生成随机数相对来说比较简单,因为有一个现成的方法可以使用.在Math类中,Java

  • Java编程中随机数的生成方式总结

    本章先讲解Java随机数的几种产生方式,然后通过示例对其进行演示. 广义上讲,Java中的随机数的有三种产生方式: (01). 通过System.currentTimeMillis()来获取一个当前时间毫秒数的long型数字. (02). 通过Math.random()返回一个0到1之间的double值. (03). 通过Random类来产生一个随机数,这个是专业的Random工具类,功能强大.第1种 利用System.currentTimeMillis()获取随机数 通过System.curr

  • java 实现随机数组输出及求和实例详解

    java 实现随机数组输出及求和 问题描述: 随机生成10个数,填充一个数组,然后用消息框显示数组内容,接着计算数组元素的和,将结果也显示在消息框中. 设计思路: 使用java.util中的Random类来获取随机数,存入数组后,定义一个String类的对象result,利用for循环存储要输出的数组内容到result并且求和:再利用javax.swing中的JoptionPane类创建消息框进行结果输出. 源代码: import java.util.*; import javax.swing.

随机推荐