问题:
请描述RANDOM(a,b)过程的一种实现,它只调用RANDOM(0,1),该函数以等可能返回0或者1。作为a和b的函数,你的过程的期望运行时间是多少。
解答:
假设a<b,设n=b-a,首先计算出n的二进制数位数,记为digit。
接着,调用过程RANDOM(0,1)digit次,生成有digit位的二进制数result。
若result大于n,则重新调用过程RANDOM(0,1)digit次,再次生成result,直到result小于或等于n为止。
最后返回result+a作为RANDOM(a,b)结果。
算法分析:
设X为成功生成一次result所用的总次数,设p为成功生成一次result的概率,成功即result小于或者等于n,则
p=(n+1)/2digit
。
又该问题生成result的次数服从参数为p的几何分布,计算其均值可得,E(X)=1/p。
每次生成result调用了digit次RANDOM(0,1),所以调用RANDOM(0,1)的总次数为digit/p,即时间复杂度为:
T(n)=O(digitp)=O(digit∗2digitn+1)
算法实现:
c语言实现如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>
int sum;
int summary[100];
void display_bits(unsigned number) {
unsigned mask = 1;
mask <<= CHAR_BIT * sizeof(unsigned) - 1;
for (int i = 0; i < CHAR_BIT * sizeof(unsigned); ++i)
{
/* code */
putchar(mask & number ? '1' : '0');
number <<= 1;
if (i % 8 == 0)
putchar(' ');
}
putchar('\n');
}
unsigned random_0_to_1() {
return rand() % 2;
}
unsigned random_a_to_b(unsigned a, unsigned b) {
//make sure that b is greater than a
if (b < a) {
unsigned temp = a;
a = b;
b = temp;
}
unsigned n = b - a;
//get the digit of n
int digit = 0;
while (n != 0) {
n >>= 1;
digit++;
}
printf("digit:%d_\n", digit);
n = b - a;
display_bits(n);
unsigned result = n + 1;
while (result > n) {
result = 0;
for (int i = 0; i < digit; i++) {
result <<= 1;
result += random_0_to_1();
}
//summary how many times result is repeatly generated
sum++;
}
//summary the numbers of each result number
summary[result]++;
display_bits(result);
return result + a;
}
int main(int argc, char const *argv[])
{
/* code */
srand(time(NULL));
for (int i = 0; i < 100000; ++i)
{
printf("random number:%d\n", random_a_to_b(5, 10));
}
printf("sum:%d\n", sum);
for (int i = 0; i < 10; ++i) {
printf("summary%d:%d\n", i, summary[i]);
}
return 0;
}
sum表示总共生成result的次数,summary为生成的每个合法结果的个数。经过统计得,生成的result的平均次数确实符合上述分析结果。