需求分析
有一个题库,包含10000道题.对于每个学生,生成一套试卷,试卷包含10道题.
离线随机抽样
从a[N]中选取k个元素
for i in range(0,k):
swap(a[i],a[random.nextint(i,N)])
最终所得a[0~k]即为所求,这样抽样会打乱原数组的顺序,不过没有关系(对于离线随机抽样,原始数组混乱也没关系).只要保证每一时刻只有一个线程在"操作"这个题库数组即可.
复杂度分析:O(k)的时间复杂度,O(N)的空间复杂度
在线随机抽样
一个流数组,它有N个元素,从中随机抽取k个元素,每个元素只能读取一次.
int a[k]
for i in range(0,k):
cin>>a[i]
for i in range(k,N):
cin>>x
p=random.nextInt(0,i)
if p<k:
a[p]=x
以7选3为例,对于整个流中的第一个元素,它被选中的概率为1*(3/4)*(4/5)*(5/6)*(6/7)=3/7
,3/4表示第4个元素来临时,第四个元素有1/4的概率替换掉第一个元素,所以就有3/4的概率不被第四个元素替换掉。同理,不被第五个元素替换掉的概率为4/5,不被第六个元素替换掉的概率为5/6......
对于流中的第4个元素,它进入a数组的概率为3/4
,它最终留在a数组中的概率为(3/4)*(4/5)*(5/6)*(6/7)=3/7
上面这种证明不够完善,需要说明一件事:
第一个元素被选择的概率为3/7,定义为事件p1
第二个元素被选择的概率为3/7,定义为事件p2
第三个元素被选择的概率为3/7,定义为事件p3
第四个元素被选择的概率为3/7,定义为事件p4
第五个元素被选择的概率为3/7,定义为事件p5
......
p1,p2,p3,p4......两两互相独立,任意组合C(N,K)出现的概率都等于(K/N)^K
不说明事件独立性这一点,是不完善的证明。
复杂度分析:因为是流式处理,所以整个数组没有完全读入内存,空间复杂度为O(k).时间复杂度为O(N),因为要遍历整个数组一次.
离线和在线时间复杂度和空间复杂度正好颠倒,可以说离线算法是以空间换时间,在线算法是以时间换空间.