算法:关于生成抽样随机数的这些算法

原创 2015年12月22日 13:28:51

概述:

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

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

本文链接:http://blog.csdn.net/lemon_tree12138/article/details/50378102 -- Coding-Naga
                                                                 --转载请注明出处

算法尝试:

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

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

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

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随机算法次之。这个可以根据个人偏爱来做选择。

版权声明:本文为博主原创文章,未经博主允许不得转载。

MCMC抽样算法要点总结

对MCMC抽样算法的几个要点(目的、原理、算法步骤、收敛检测方法)进行总结,并给出了有关的概念定义,标注了一些学习MCMC算法中需要特别注意的地方。最后指出M-H算法和Gibbs算法的改进点和这些改进...
  • nomadlx53
  • nomadlx53
  • 2015年12月26日 03:14
  • 4794

从随机数生成到随机采样的C++实现

随机数的妙用:[上回书](http://blog.csdn.net/lanchunhui/article/details/49123823)说到的关于用蒙特卡洛方法进行一些数值计算(比如pi的逼近、特...
  • lanchunhui
  • lanchunhui
  • 2015年10月17日 10:56
  • 1447

随机采样和随机模拟:吉布斯采样Gibbs Sampling

http://blog.csdn.net/pipisorry/article/details/51373090 马氏链收敛定理 马氏链定理: 如果一个非周期马氏链具有转移概率矩阵P,且它的任何两个...
  • pipisorry
  • pipisorry
  • 2016年05月12日 00:24
  • 29853

随机模拟的基本思想和常用采样方法(sampling)

通常,我们会遇到很多问题无法用分析的方法来求得精确解,例如由于式子特别,真的解不出来; 一般遇到这种情况,人们经常会采用一些方法去得到近似解(越逼近精确解越好,当然如果一个近似算法与精确解的接近程度...
  • xianlingmao
  • xianlingmao
  • 2012年07月23日 15:27
  • 79522

ransac算法(随机抽样一致性)

对于运行不了几次,一次运行不了多久的方法,我们不需要考虑性能优化,对于那些需要经常运行几百次几千次的方法,我们头脑里还是要有性能这根弦。C#太优雅方便了,以至于很多人写程序时根本就把性能抛到脑后了,不...
  • fenggaoyuehei
  • fenggaoyuehei
  • 2010年12月02日 14:52
  • 8642

蓄水池抽样算法

问题:在不知道文件总行数的情况下,如何从文件中随机的抽取一行? 通常情况下,我们在已知文件大小时利用rand随机生成一个行数即可。 在不知道行数的情况下,我们首先选择第一行,然后以...
  • zm714981790
  • zm714981790
  • 2016年05月14日 19:27
  • 948

抽样算法(带有权重的随机抽样算法)

  • 2010年10月16日 19:35
  • 1.44MB
  • 下载

随机数生成算法

这两天没事,就写了写数学课上老师说的那个“蒲丰投针实验"的程序。接触到了一些随机数生成方面的东西,写出来跟大家分享一下。      对于计算机生成随机数这个东西,以前有过一些浅显的认识。只知道计算机...
  • dingwood
  • dingwood
  • 2012年04月09日 22:41
  • 15949

java实现随机抽样

     编程实现对数据记录的随机抽样。给定概率p,依概率p对给定的数据集合进行随机抽样。比如说现在在一个数组中存放了10000位同学的身高和体重信息,现在需要你对这100位同学以概率p=0.002进...
  • amber_room
  • amber_room
  • 2011年06月06日 12:34
  • 5401

随机抽样一致性算法

随机抽样一致性算法(RANSAC) 作者:王先荣     本文翻译自维基百科,英文原文地址是:http://en.wikipedia.org/wiki/ransac,如果您英语...
  • pi9nc
  • pi9nc
  • 2013年06月13日 11:19
  • 6440
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:算法:关于生成抽样随机数的这些算法
举报原因:
原因补充:

(最多只允许输入30个字)