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

来源:互联网 发布:淘宝福利群真的假的 编辑:程序博客网 时间:2024/05/17 01:36

#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[n];    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 = mremaining = nfor 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--;        }    }}





0 0
原创粉丝点击