注:以下皆为个人理解,非标准答案
12.5.1:
- bigrand:rand函数随机产生15位,那么用两次rand函数再拼接起来就形成了30个随机位
- randint(l,u):将rand出的数映射到l,u 之间即可,一个实现方法是mod(u-l)+l
12.5.8:
- [0..n-1] 中选取 m 个数并乱序输出:先用12.1中的算法产生选出的m个数,然后进行洗牌算法(12.3中所说的‘弄乱’)并输出
- 允许重复,要生成顺序列表:每选出一个数后,还是从头遍历数组进行下一次选择;最后排序输出
- 允许重复,乱序输出:同上,只是省略了排序
12.5.9:
- 作者坚持要用set的方法并且最多只用m次rand函数:那么必须要避免取到重复数的情况。可以先产生一个数组a[0..n-1],a[i]=i;第j 次循环index = rand() mod (n-j+1),然后取 a[index] 放入set,并用 a[n-j] 替换掉 a[index]。可能看上去比较复杂,思想就是每次从干净的数中取一个放入set,并将该数移除,这样以后就不会取到重复的数;上述方法就是该思想的一个实现
12.5.10:
- n个对象按序排列,事先不知道n,如何随机输出一个对象:此题的意思我的理解是顺序的读进来若干对象,当读到结束符时就马上随机输出一个对象。既然是随机输出,那么在读完n个对象之前是无法决定输出哪个对象的,否则无法保证每个对象的输出概率相同。这也就是说完全可以记录下n然后 rand() mod n。所以不知道作者这里的出题意图是什么
- 看到一个类似的题,给你一个长度为 N 的链表。N 很大,但你不知道 N 有多大。你的任务是从这 N 个元素中随机取出 k 个元素。你只能遍历这个链表一次,且必须保证取出的元素是完全随机的:同上题,可采用蓄水池算法(Reservoir Sampling),假设选出来的元素存入 R[1..k] 数组中,链表记为 S,首先把遇到的前k个表元素赋值给 R[k],然后遍历 S[k+1]..S[n](下标记为i),j = rand(1,i),如果 j 在1~k范围内则用S[i] 替换 R[j] ;反复进行直到链表遍历完。