【算法导论学习-012】n个数随机等概率的抽样m个
2014-08-13 15:53
225 查看
算法法导论》P129页课后题5.3-7
suppose we want to create a random sample of the set {1,2,3,…,n}, thatis, an m-element subset S, where0≤m≤n, such that each m-subset is equally likely to be created. One waywould be to set A[i]=i for i=1,2,3,…,n, call RANDOMIZE-IN-PLACE(A),and then take just the first marray elements. This method would make n calls to the RANDOM procedure.
If n is much larger than m, we can create a random samplewith fewer calls to RANDOM. Show that the following recursive procedurereturns a random m-subset S of {1,2,…,n}, in which eachm-subset is equally likely, while making
only m calls to RANDOM:
RANDOM-SAMPLE(m,n) if m == 0 return ∅ else S = RANDOM-SAMPLE(m-1, n-1) i = RANDOM(1,n) if i ∈ S S = S ∪ {n} else S = S ∪ {i} return S
翻译过来就是:n个数随机等概率的取样m个。
该题的证明方法1:http://clrs.skanev.com/05/03/07.html
该题的证明方法2 :/article/6972015.html
题目中其实给出了两种解决方案。
方案1:调用RANDOMIZE-IN-PLACE(A)
/** * 创建时间:2014年8月13日 上午9:46:51 * 项目名称:Test * @author Cao Yanfeng * @since JDK 1.6.0_21 * 类说明: */ public class RandomSampleTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int[] array={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; int[] result=randomSample(array, 5); for (int i : result) { System.out.println(i); } } public static int[] randomSample(int[] array,int m) { randomInPlace(array); int[] result=new int[m]; for (int i = 0; i <m; i++) { result[i]=array[i]; } return result; } /*《算法导论》P126页伪代码*/ public static void randomInPlace(int[] array) { int n=array.length; for (int i = 0; i < n; i++) { int index=random(i, n-1); if (array[i]!=array[index]) { array[i]^=array[index]; array[index]^=array[i]; array[i]^=array[index]; } } } public static int random(int a,int b) { return new Random().nextInt(b-a+1)+a; } }
方案2:实现题目中的伪代码
/*** 创建时间:2014年8月13日上午9:46:51
* 项目名称:Test
* @author
Cao Yanfeng
* @since JDK 1.6.0_21
* 类说明:
*/
public
classRandomSampleTest {
/**
* @param args
*/
public
static void main(String[]
args) {
// TODO Auto-generated method stub
int[]
array={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
LinkedList<Integer>result=randomSample(array, 5);
for (Integer
integer : result) {
System.out.println(integer);
}
}
public
staticLinkedList<Integer> randomSample(int[]
array,int
m){
return
sample(array,
array.length,
m);
}
public
staticLinkedList<Integer> sample(int[]
array,int
n,int
m) {
if (m==0) {
return
newLinkedList<Integer>();
}else {
LinkedList<Integer> s=sample(array,
n-1, m-1);
int
i=array[random( 0,
n-1)];
if (s.contains(i)) {
s.add(array[n-1]);
}else {
s.add(i);
}
return
s;
}
}
/*返回闭区间的[a,b]随机数*/
public
staticintrandom(inta,int
b) {
return
new Random().nextInt(b-a+1)+a;
}
}
方案3:赋予权重法
《算法导论》P1225.3节的Randomized algorithms中提供的第一种随机采样方法即赋予权重法。但是权重有可能出现相同情况,不推荐这种方法。方案4:蓄水池抽样
见最后的扩展问题。*******************************************************************************
正如题目中所言,如果n个数据选取m个样本,如果n远大于m,则应该使用方案2,仅调用m次random()函数;如果n与m差距不大,则应该使用方案1,调用n次random()函数,但是方法简单。
*******************************************************************************
扩展问题:【google面试题】给定一个数据流,其中包含无穷尽的搜索关键字(比如,人们在谷歌搜索时不断输入的关键字) 。如何才能从这个无穷尽的流中随机的选取 1000 个关键字?
参考:/article/9402058.html
这也是“n个数随机等概率的取样m个”问题,但是n是未知的。采用的方式是蓄水池抽样。即:将数据流中的前1000个放入长度为1000的数组,对于1001个数,调用random(0,
1000),[0,999]闭区间内每个数被选中的概率都是1000/1001。之后对于n>1000的每个数,[0,999]闭区间内每个数被选中的概率都是1000/n。这里random被调用的次数为n-m。下面模拟一下这个过程。
/** * 创建时间:2014年8月13日 上午9:46:51 * 项目名称:Test * @author Cao Yanfeng * @since JDK 1.6.0_21 * 类说明: */ public class RandomSampleTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int[] array={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; int[] result=reservoirSample(array, 5); for (int i : result) { System.out.println(i); } } /*蓄水池抽样*/ public static int[] reservoirSample(int[] array,int m) { int[] reservoir=new int[m]; for (int i = 0; i <array.length; i++) { if (i<m) { reservoir[i]=array[i]; }else { int temp=random(0, i); if (temp<m) { reservoir[temp]=array[i]; } } } return reservoir; } }
相关文章推荐
- 算法导论学习笔记-5.4 概率分析和指示器随机变量的应用-几个有趣的问题
- 算法导论学习笔记-第五章-概率分析和随机算法
- 算法导论 学习笔记 第五章 概率分析和随机化算法
- 算法导论之排序算法学习
- 学习算法导论-插入查询
- 算法导论学习笔记-1
- 算法导论学习笔记——插入排序
- 算法导论--第六章学习笔记
- 一个无聊男人的疯狂《数据结构与算法分析-C++描述》学习笔记 用C++/lua/python/bash的四重实现(7)习题2.8 随机数组的三种生成算法
- Introduction to Algorithms (算法导论) 学习笔记 -- Chapter 9
- 给你一个链表和一个 random函数, 设计一个算法能随机返回链表的某个节点, 要求每个节点被返回的概率一样。限制条件是只能遍历链表一次并且不能用额外空间。
- 算法导论 学习笔记。
- 算法学习导论学习笔记-第6章 堆排序
- 学习算法导论-选择排序
- 算法导论学习笔记-第九章-中位数和顺序统计学
- 算法导论学习笔记-第二十章-斐波那契堆
- 学习算法导论
- 算法导论学习笔记-找数组中第二小的数
- 算法导论学习笔记-第十三章-红黑树
- 算法导论学习笔记——桶排序