生成m个0到n范围内的不同的随机数

(1)背景

在0~n的范围内,生成m个不同的随机数,每个数出现的概率相同;

或者生成m个0~(m-1)范围内的不同的随机数;

(2)方法一

(2.1)原理

最容易想到的方法,是逐个产生这些随机数,每产生一个,都跟前面的随机

数比较,如果重复,就重新产生。

(2.2)伪代码实现

void get_rand(int *a, int m, int n, int k)//结果存在a中

{

    int i,j,t;

    for(i = 0; i < k; )

    {

        t = rand()%(n-m+1)+m;

        for(j = 0; j < i; j ++)

            if(a[j] == t) break;

        if(j == i)//不重复

            a[i++] = t;//记录随机数。

    }

}

分析,上面中生成一个随机数之后,还需要与之前的数进行对比,效率比较差;可以考虑使用标志位来判断某个数是否被选取过;

如下所示:

/******************************************************************************

*函数名称:voidgenerateDiffRandV2(int a[], int n)

*函数功能:产生互不相同的随机数(产生随机数的范围是1~n-1)

*入口参数:

*返 回 值:无

*

*思 路:先生成一个放置座号的数组,然后从中随机抽取,抽取后为防止重复,立即归零。

* :每次生成座号,只需判断是否为0 即可,大大提高了程序执行的效率。

*******************************************************************************/

void generateDiffRandV2(int a[], int n)

{

   int *flag =(int *)malloc(sizeof(int) * n);

   static int flag_once = 0;

   int i, index;

   

   for(i = 0; i < n; i++)

                        flag[i]= i+1;

   if(!flag_once){

       srand(time(0));

       flag_once = 1;

    }

   

   for(i = 0; i < n;){

       index = rand() % n;

       if(flag[index] != 0){

           a[i++] = flag[index]-1;

           flag[index] = 0;

       }

    }

   free(flag);

}

(3)方法二

(3.1)原理

            将含有n个元素的数组中元素的位置随机调换;这样只需要一次遍历就可以产生全部的随机数;

(3.2)伪代码实现

下面产生100个100以内不重复随机数的代码:

int a[100];

for(i=0; i<=99; ++i) {

a[i]=i;

}

for(i=99; i>=1; --i) {

swap(a[i],a[rand()%i]);

//因为rand()%i的值的范围为0~(i-1);所以i>=1;

}

说明:此中开始的时候最好以时间为种子的随机数,即srand(time(0));这样保证每次产生的随机数序列都是不同的;

(4)方法三

(4.1)背景

随机产生m个0~n范围内不同的随机数;

(4.2)原理

            先用一个数组A保存范围内的每一个数字,然后写个洗牌算法把这个数组的元素随机打乱,最后用另外一个数组B存储数组A的前N个元素的值。这里数组B就是要得到的结果。

(4.3)伪代码实现

// 洗牌算法

void shuffle(vector<int>* vec)

{

   int size = vec->size();

   srand((unsigned)time(nullptr));

   for (int i=1; i<size; i++)

    {

       

       int r = rand()%size;

      swap(vec, i, r)

}

}

void getRandomCount(int range, int count)

{

   vector<int> m_aviable; // 存储结果的数组

   vector<int> v_range; // 保存范围的索引值

   for (int i=1; i<=range; i++)

    {

        v_range.push_back(i);

    }

   

   // 洗牌

   shuffle(&v_range);

   

   // 取洗牌后数组里前count个数。

   for (int i=0; i<count; i++)

    {

       m_aviable.push_back(v_range[i]);

    }

   

   // 测试打印

   for (int i=0; i<v_range.size(); i++)

    {

       cout << v_range[i] << "\t";

    }

   cout << endl;

}

说明:其实此中可以直接一次遍历,进行m次交换即可;

猜你喜欢

转载自blog.csdn.net/legend050709/article/details/80808038