• 储水池抽样算法原理与实现


    原创作品,出自 “晓风残月xj” 博客,欢迎转载。转载时请务必注明出处(http://blog.csdn.net/xiaofengcanyuexj)。

    因为各种原因,可能存在诸多不足,欢迎斧正!

            记得在实习那会,涉及到抽奖的解决方式,即一天以k/n的概率中奖,要求给出简单高效的算法。当中n仅仅有在结束时才知道。

    换言之,题意即为怎样从未知或者非常大样本n空间中随机地取k个数,保证每一个被取到的概率为n/k。解决此题的非常好方法就是储水池算法Reservoir Sampling  Algorithm。

            储水池算法应用的前提条件是样本空间总数未知或非常大。若当前的样本数为m。则以k/m的概率保留每个样本……直到终于样本数为n时是的每个被选中的概率为k/n,缺陷是不到最后不知道哪些样本要被选中。这样问题就来了,为何不在终于结果n出来时再来随机抽取k个样本,保证概率为k/n呢?事实上这样的想法有些时候是不可行的,数据是动态增长的。可能缓存系统存储不了全部的样本信息。但却足够存储k个样本的信息,即空间复杂度能够从O(n)降到O(k),k相对n来说是非常小的。

    所以储水池算法还是非常有应用价值的。

          以下说说储水池算法的原理及实现。先把前k个数放入蓄水池;对第k+1个样本,以k/(k+1)概率决定换入蓄水池,换入时又随机选取池里的一个样本作为替换项……,相应第i个样本(i>k),以k/i的概率留下。然后随机从池里选中一个替换掉……这样一直做下去,对于随意的样本空间n,对单个样本的选取概率为k/n。

    证明步骤例如以下:

          

         此算法时间复杂度为O(n),空间复杂度为O(k),可以处理样本空间总数未知或非常大的情况。不失为一种比較好的方法。关于储水池算法。在分布式系统上有着应用,在此提供一下丰富眼界的链接。储水池算法的拓展


         因为工作原因。Java对于我来说似乎比C/C++更重要一点,全部以后的代码尽量用Java给出,直接上源码的。

    import java.util.Random;
    
    public class ReservoirSampling {
    	
    	private int m_nChoice;
    	private int [] m_arrayChoice;
    	private int m_nNowNumber;
    	private Random m_Rand =new Random(System.currentTimeMillis());
    	
    	public ReservoirSampling(int k)
    	{
    		m_nNowNumber = 0;
    		m_nChoice = k;
    		m_arrayChoice = new int [k];
    	}
    	
    	public void AdjustChoice()
    	{
    		if(m_nNowNumber < m_nChoice)
    		{
    			m_arrayChoice [m_nNowNumber] = m_nNowNumber;
    		}
    		else
    		{
    			int id = m_Rand.nextInt(m_nNowNumber + 1);
    			if(id < m_nChoice)
    			{
    				m_arrayChoice [id] = m_nNowNumber;
    			}
    		}
    		
    		++ m_nNowNumber;
    	}
    	
    
    	public void ShowChoice()
    	{
    		for( int i = 0; i <m_arrayChoice.length ; ++ i)
    		{
    			if(i != 0 && i % 10 == 0)
    				 System.out.println();
    			 System.out.print(1 + m_arrayChoice [i] + "  "); 
    		}
    	}
    	
    	public static void main(String agr[])
    	{
    		System.out.println("My Java program!");
    		ReservoirSampling test = new ReservoirSampling(20);
    		for( int i =0 ;i < 200 ; ++ i)
    		{
    			test.AdjustChoice();
    		}
    		test.ShowChoice();
    	}
    
    }
    

               因为时间和水平的原因,难免有不足的地方。欢迎斧正!


       

  • 相关阅读:
    延时提示框(定时器的使用)
    时间对象
    仿站长之家导航(setTimeout的应用)
    倒计时时钟
    简易网页始终
    网页计算器
    两个数字比较大小
    累加按钮,自加1
    用parsetInt解析数字,并求和
    JS布局转换
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/6753875.html
Copyright © 2020-2023  润新知