实际问题
从n个数据中随机取得m个数,n>m
算法大概思路
源数据的数组为a[] 大小为n “水池”即存放取出的数据的数组为b[] 大小为m 若要做到随机 则每个数据被选中的概率则为m/n
进行如下操作
①对数组a[]进行遍历,设置j为遍历时当前元素下标,将a[]数组的前m个数据依次存入数组b[]中,此操作a[]数组中的前m个数被加入b[]数组的概率为100%即为1
②当j=m-1时,此时b[]数组的元素已满,若后面的元素要加入b[]数组,则要与池中的元素替换
替换的规则:(j为当前元素的下标,此时j>=m),在0-j的范围内随机出一个数字 r ,r<m 则将j对应的元素(a[j])值赋给水池中的b[r],水池中r对应的数据被替换,被替换的概率为1/(j+1)---{因为数组从0开始,所以0-j有j+1个数}。而当前元素a[j]也就是j对应元素被选入水池的概率为r/(j+1)。
如果r>m,则j++向前移动,也就表示池中的数据没有被替换。
③j每向前移动一步则重复步骤②,直到数组a[]被完全遍历
分析前m个数和m之后的数被选入池中的概率
根据替换规矩可得出
①前m个数据 :
当j=m-1时,前m个数据被选入池中,概率为1:
当j=m时,水池中的数据被替换的概率为1/(j+1),即1/(m+1);则此轮留下概率为1-1/(m+1) =m/(m+1)
当j=m+1时,水池中的数据被替换的概率为1/(j+1),即1/(m+2);则此轮留下的概率为1-1/(m+2)=(m+1)/(m+2)
当j=m+2时,水池中的数据被替换的概率为1/(j+1),即1/(m+3);则此轮留下的概率为1-1/(m+3)=(m+2)/(m+3)
.........以此类推
计算最终留下概率:
1 * m/(m+1) * (m+1)/(m+2) * (m+2)/(m+3) *...* (n-2)/(n-1) * (n-1)/(n) = m/n
②m以后的数据:
j<m时,不会被选中
当j=m时,m之后的数据被留下的概率为m/(j+1),即m/(m+1)
当j=m+1时,m之后的数据被留下的概率为m/(j+1),即(m+1) /(m+2);
当j=m+2时,m之后的数据被留下的概率为m/(j+1),即(m+2)/(m+3)
.........以此类推
计算最终留下概率:
m/(m+1) * (m+1)/(m+2) * (m+2)/(m+3) *...* (n-2)/(n-1) * (n-1)/(n) = m/n
结论
前m个数和m之后的数被选入池中的概率是一样的
代码实现
//k[]表示源数组 m表示水池大小
public static int[] xushuichi(int k[], int m) {
//b为水池
int b[] = new int[m];
if (k.length <= m)
return new int[0];
else if (k.length > m) {
for (int j = 0; j < k.length; j++) {
if (j < m)
b[j] = k[j]; // 将前m个数据存入数组
else if (j >= m) {
//从0-j中随机出一个数
int r = new Random().nextInt(j + 1);
if (r < m)
b[r] = k[j]; //如果随机出的r<水池大小 ,则进行替换
}
}
}
return b;
}
测试
public static void main(String[] args) {
int n = 5;
int m = 4;
int one = 0;
int two = 0;
int three = 0;
int four = 0;
int five = 0;
int N[] = new int[n];
for (int i = 0; i < n; i++)
System.out.print((N[i] = i) + " ");
System.out.println();
for (int j = 0; j < 10000000; j++) {
int l[] = xushuichi(N, m);
for (int q = 0; q < m; q++) {
if (l[q] == 0)
one++;
if (l[q] == 1)
two++;
if (l[q] == 2)
three++;
if (l[q] == 3)
four++;
if (l[q] == 4)
five++;
}
}
System.out.println("0 " + one + " 1 " + two + " 2 " + three + " 3 " + four + " 4 " + five);
源数组存放1,2,3,4,5 测试每个数据出现概率
result:
0 1 2 3 4
0 7999128 1 8001228 2 8000456 3 7999657 4 7999531
概率基本一致。