您的位置:首页 > 其它

等概率随机生成不重复的数

2015-11-26 18:01 225 查看
#include <iostream>
#include <cstdlib>
#include <ctime>


一、1到n n个数字随机全排序,或者说,随机生成1到n n个不重复的数字

用空间换时间,需要空间复杂度为o(n),时间复杂度为o(n)

用一维数组顺序存储1到n这n个数字。

然后先在1到n中随机生成一个下标,输出该下标对应的值,然后将数组最后一个交换。并将此时最后一个从逻辑上删除。倒数第二个成为最后一个。

生成n次随机下标,问题解决。简单吧。

void generate_N_Random(int n)
{
int* NumPool = new int
;
for(int i = 0; i < n; i++)
NumPool[i] = i + 1;

srand((unsigned int)time(0));
int subIndex = 0;
int currentLastIndex = n - 1;
for (int i = 0; i < n; i++)
{
subIndex = rand()%( n-i);
std::cout << NumPool[subIndex] << " ";
NumPool[subIndex] = NumPool[currentLastIndex];
currentLastIndex--;
}
endl(std::cout);
delete[] NumPool;
}


上面这个太简单了,稍微再加点难度。

二、用1...n 这n个数,随机生成m个不重复的数字。(m < n)

1)先用一个猥琐一点儿的方法,在前面方法的基础上取前m个数字即可。

2)新方法。时间复杂度也为o(n).

当然,还有对数复杂度的算法,那个等会儿再讲。

先来算一下概率,咱们都是学过条件概率的人。从n个数字中先m个数,每个数字被选中的概率为m/n.

举个直观点儿的例子,在0,1,2,3,4这五个数字中选两个数,我们只要保证从全局来看,每个数字被选中的概率为2/5即可,按照什么顺序选不重要。

比如,我们规定按照从0到4的顺序依次选,如果对于0,本次没有选上,那么以后也不会去选0了,所以我们要给予0这个数字2/5的选中概率。好的。

之后我们来考察1,如果刚刚0没有被选上,那么我们就要给予1这个数字2/4的选中概率。如果刚刚0被选上了,那么我们就要给予1这个数字1/4的选中概率。这样,综合来看,数字1被选中的概率就是(2/5 * 1/4 + 3/5 * 2/4) = 2/5. 符合要求。

如果已经选中了两个,即剩余要选的数字个数为0了,那么算法也就结束了。如果不为0,则同上述分析。

这样,我们就可以严格按照从0到4的顺序来等概率地选数字了。

讲解完毕。算法如下:

Knuth的《The Art of Computer Programming, Volume2:Seminumerical Algorithms》的伪代码:

select = m
remaining = n
for i = [0,n)
if (rand() % remaining) < select
print  i
select --
remaining--


//用算法发明者的名字来命名函数吧
void knuth(int n, int m)
{
srand((unsigned int)time(0));
for (int i=0; i<n; i++)
{
if (rand()%(n-i)<m)
{
std::cout << i << " ";
m--;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: