`
talentluke
  • 浏览: 604893 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

如何高效产生m个n范围内的不重复随机数(m<=n)

 
阅读更多

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

数比较,如果重复,就重新产生。这是个很笨的方法,且比较次数呈线性增长,越往后次数越多。其实这些

比较是多余的,完全可以不进行比较,只要反过来,按顺序产生这些数,但随机产生它们的位置。例如下

面产生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]);

上面这段代码只需要遍历一次就可以产生这100个不重复的随机数,它是如何做到的呢?首先第二行按顺

序用0到99填满整个数组;第三行,是随机产生从0到m-2个数组下标,把这个下标的元素值跟m-1下标的元

素值交换,一直进行到下标为1的元素。因此它只需要遍历一次就能产生全部的随机数。

        再看下面的代码,原理跟上面例子相似,但效率比上面的差点,但仍不失为一个好方法:

int a[100]={0};
int i, m;
for(i=1; i<=99; ++i)
{
        while(a[m=rand()0]);
        a[m] = i;
}

这段代码也是随机产生位置,但它预先把整个数组初始化为0,然后随机产生其中一个位置,如果该元素

值为0,表示这个位置还没有被使用过,就把i赋予它;否则,就重新随机产生另一个位置,直到整个数组

被填满。这个方法,越到后面,遇到已使用过的元素的可能性越高,重复次数就越多,这是不及第一个方

法的地方,但总的来说,效率还是不错的。

===================================================================================

1.产生一个随机数(从0到32767)
   srand((unsigned) time(NULL)); //为了提高不重复的概率
   rand(); //产生随机数

2.产生从m到n的随机数(包括m,不包括n)
   srand((unsigned) time(NULL)); //为了提高不重复的概率
   rand()%(n - m + 1) + m;                //使用时将m和n换为具体数即可

==================================================================================

问题的来由 - "随机取m个数(在1到n的范围之内),(m <= n),要求m个数没有重复。有没有
什么好的算法,时间复杂度和空间复杂度都很好"

----------------------------------------------------------------
方案一:
取随机数可以用C++标准的rand,至于M个不重复,你可以用std::set来解决,把取道的随机数
插入到set里面,set的size() == m就可以了, 具体可以这样:

#include <set>
#include <stdlib.h>

int main()
{
   std::set<int> s;
   while(1)
   {
      int r = rand() % n;
      s.insert(r);
      if(s.size() == m)
      {
         break;
      }
   }
}

由于set底层实现是红黑树,插入复杂度是对数级的^_^

----------------------------------------------------------------
方案二:
#include <iostream>
#include <cstdlib>      //用于rand()和srand()函数
#include <ctime>        //设置不同的随机数

using namespace std;

int main (){
    srand( time( 0 ) );    //调用不重复的随机数函数
    unsigned i;
    for ( int n = 0; n++ < 10; )
    {
        i = rand() ;        //对i 赋系统的随机数
        cout << " The NO." << n << "is : " << i << endl;
    }

    return 0;
}

1. C++标准函数库提供一随机数生成器rand,返回0-RAND_MAX之间均匀分布的伪随机整数。 RAND_MAX
   必须至少为32767。rand()函数不接受参数,默认以1为种子(即起始值)。

   随机数生成器总是以相同的种子开始,所以形成的伪随机数列也相同。失去了随机意义。

2. C++中另一函数srand(),可以指定不同的数(无符号整数变元)为种子。但是如果种子相同,伪
   随机数列也相同。--一个办法是让用户输入种子,但是仍然不理想。

3. 比较理想的是用变化的数,比如时间来作为随机数生成器的种子。
   在 头文件ctime中时间库包含time函数,它可以返回一个表示时间、日期、月和年的数值使用如
   下调用可将该值设为rand的种子
   srand(static_cast<unsigned>(time(static_cast<time_t*>(NULL))));

4. 但, srand()并不是说使随机数都不一样,它只是使取随机数的种子随着时间而改变:)
   So, 还是方案一好!

===============================================================================

生成无重复的随机数,注意,是不重复的序列.
   通常的生成随机数的做法是不考虑重复的,因为即使重复也属于概率意义上的正常情况.但某些情况下需要不重复的随机数据,怎么办呢?
   我想从大方向上来说,应该只有两个方法.要么牺牲时间要么牺牲空间.讲得不对或不完整,大家一定要指出来啊,谢谢.

 

                            =---------------来源CSDN

 

  注意,下面均以在101~200的范围内(设为b[100],它实际上是附加空间),从中产生10个不重复的随机数(设为a[10]).
   
一.牺牲时间为代价
   这种方法不需要附加空间b数组.
   要产生一定范围内不可重复的随机数,把曾经生成的随机数保存起来作为历史数据。产生一个新的随机数后在历史数据搜索,若找到就重新产生一个新的再重复数据搜索;否则就认为已经找到了一个新的不同随机数。
   可以预见,每个新产生的随机数都要与前面所有的数比较.若重复,舍弃,再产生;否则,产生下一个.平均耗时n的平方量级.
   粗看起来,上面的程序似乎没有什么问题,在执行过程中程序也能够通过。但,仔细分析我们就会发现问题出在一个新产生的随机数是否已经存在的判定上。既然是随机数,那么从数学的角度来说在概率上,每次产生的随机数 r就有可能相同,尽管这种可能性很小,但确是一个逻辑性与正确性的问题。因此,每次产生的新的随机数r都有可能是数组random的前i-1个数中的某一个,也就是说程序在运行过程中由此可能会导致死循环!
    有人可能会争辩说,这种概率很小嘛,几乎为零.的确,但我要问,算法的五大特性是什么,其中两大特性就是:确定性和有穷性.
    所以,怎么解决?牺牲空间.(稍后介绍)

二.牺牲空间为代价
   以下方法需要附加空间b数组.
   (1)将范围数组b[100](b[i]=100+i,不妨设数组下标从1开始)的每个元素设置一个标志位flag.初始均为flag=0;若某元素被选入到a数组中,则flag=1;显然,以后再选到重复元素可以立刻判定是否已选.这不正是以空间换时间吗?
   但是仍然有一个很严重的问题,在小规模输入下,无疑它的表现是不错的.但现在举一个失败的例子.
   在1~65536之间,选择65500个不重复的随机数.看看后面的随机数,比如第65500个数(最后一个),它要在剩下的36个数中选择才会有flag=0(根本不知道这36个数是什么);哼哼,概率36/65536.越到后面,随机数越难产生,空间也换不了时间.
   改进:先在1~65536之间随机选取36个数,删除.将剩下的65500个数依次赋值给a[65500],然后打乱顺序即可,如下伪码:

1【转】如何高效产生m个n范围内的不重复随机数(m<=n)fori ← 1to length[a]
2【转】如何高效产生m个n范围内的不重复随机数(m<=n)   doj ← random() //随机产生一个a数组的下标

3【转】如何高效产生m个n范围内的不重复随机数(m<=n)       exchange a[i]←→a[j]//交换a[i]与a[j]
4【转】如何高效产生m个n范围内的不重复随机数(m<=n)

当范围数组与目标数组的大小非常接近时,上述算法非常有效,建议采用.

(2)问题的最终解决.
   仍以最开始的那个例子来说,初始数组b[i]=100+i,a数组空.
   每次随机生成数组b的一个下标subscript,然后取出它所对应的数据a[subscript],记下来.然后将数组b的最后一个数b[length]放到下标subscript的位置,同时将数组a长度减1。尽管前若干次生成的下标subscript随机数有可能相同,但,因为每一次都把最后一个数填到取出的位置,因此,相同下标subscript对应的数却绝不会相同,每一次取出的数都不会一样,这样,就保证了算法的确定性、有效性、有穷性.
伪码算法如下:

1【转】如何高效产生m个n范围内的不重复随机数(m<=n)lower ← 101
2【转】如何高效产生m个n范围内的不重复随机数(m<=n)upper ← 200
3【转】如何高效产生m个n范围内的不重复随机数(m<=n)fori ← 1to upper-lower+1
4【转】如何高效产生m个n范围内的不重复随机数(m<=n)    dob[i]=lower+i-1
5【转】如何高效产生m个n范围内的不重复随机数(m<=n)fori←1to length[a]
6【转】如何高效产生m个n范围内的不重复随机数(m<=n)    dosubscript =(int)(length[b]*Rnd +lower)//随机产生b数组的一个下标,Rnd产生0~1随机数

7【转】如何高效产生m个n范围内的不重复随机数(m<=n)        temp ← b[subscript]
8
【转】如何高效产生m个n范围内的不重复随机数(m<=n)        b[subscript] ← b[length[b]]
9【转】如何高效产生m个n范围内的不重复随机数(m<=n)        length[b]--
;
10【转】如何高效产生m个n范围内的不重复随机数(m<=n)        a[i]=
temp;
11
分享到:
评论

相关推荐

    Matlab中产生随机数.pdf

    `randperm`函数就是MATLAB提供的一种高效工具,用于生成指定范围内的无重复整数随机序列。下面将详细介绍`randperm`函数及其相关知识。 `randperm`函数的基本用法是`randperm(n)`,它会生成一个1到n之间(包括1,不...

    python 在指定范围内随机生成不重复的n个数实例

    总之,Python的`random.sample()`函数是生成指定范围内不重复随机数的利器,它的高效和便捷性使得处理这类问题变得非常简单。通过合理地利用`random`模块提供的工具,我们可以轻松实现各种复杂的随机数生成需求。

    matlab数理统计数据分析:26 数理统计随机数的产生(含教学视频).zip

    随机数是指在一定范围内没有特定规律、不可预测的数值。在数理统计中,我们通常需要生成遵循特定概率分布的随机数,如正态分布、均匀分布、泊松分布等。MATLAB提供了丰富的函数来生成这些分布的随机数。 1. **基本...

    2.随机数.ppt

    - **定义**:随机数是指在一定范围内(通常为[0,1])均匀分布的独立随机变量。在蒙特卡罗模拟等计算方法中扮演着基础角色。 - **性质**: - **独立性**:随机数序列中的每个随机数都是相互独立的。 - **均匀性**:...

    群体(大小为N的数组)中随机抽取一定数量(M个)的样本1

    标题所述的"群体(大小为N的...总结来说,这个算法是基于无放回抽样的思想,通过优化数据结构(列表记录已抽取位置)和随机数生成策略(生成剩余元素范围内的随机数),实现了高效地从大数组中抽取不重复样本的目标。

    数论算法模板

    Sum(gcd(x,y)) 1&lt;=x,y&lt;=n 计算所有可能的两个数对(x, y)的gcd之和。 #### 34. 大整数因数分解 对大整数进行高效分解,通常涉及多项式时间复杂度的算法。 #### 35. 三分模板 用于寻找函数在某区间上的极值点,...

    VB程序设计的常用算法

    例如,在统计100个[0,99]范围内随机整数个位上数字出现次数的问题中,我们创建了两个数组:a(1 To 100)用于存储随机数,x(1 To 10)用于存储计数。通过遍历数组a,对每个元素取模运算得到个位数,然后更新对应的x...

    matlab矩阵的生成.zip

    - `1:n:m`生成等差序列,从1开始,每次增加m,直到n(如果n-m+1为偶数,则不包括n)。 5. **使用linspace和logspace函数**: - `linspace(a,b,n)`生成从a到b的等差序列,包含n个元素。 - `logspace(a,b,n)`生成...

    j2me试题一本万利,大量试题

    - 随机整数赋值:要生成指定范围内的随机整数,如`n&lt;=x&lt;=m`,应使用`n = (int)(n + Math.random() * (m-n+1))`。因此,选项D正确。 这些试题涵盖了J2ME开发中的关键知识点,包括线程交互、图形处理、文件格式理解...

    抽样floyd算法

    这段代码可以生成一个长度为M,范围在1到N之间的随机整数序列。当M设置为12且N设置为3时,可能生成的序列为:313311121131。 3. **无重复随机抽样**:然而,在许多情况下,我们需要的是一个不包含重复元素的随机...

    Js生成随机数/随机字符串的方法小结【5种方法】

    如果你需要生成一个指定范围内的随机整数,可以使用`GetRandomNum`函数。这个函数接受两个参数`Min`和`Max`,返回`Min`和`Max`之间的随机整数: ```javascript function GetRandomNum(Min, Max) { var Range = Max...

    蒙特卡洛仿真_蒙特卡洛方法求圆周率_

    为了生成正方形内的点,我们需要生成两个这样的随机数作为x和y坐标,然后确保它们都在[0,1]的范围内。 2. **montecarlo.m**:这是主程序文件,它可能包含了整个蒙特卡洛方法的实现,包括生成随机点、判断点是否在圆...

    MillerRabin素数测试

    其中,Miller-Rabin素数测试(也称为米勒-拉宾素性测试)是一种实用且相对快速的算法,它以概率方式确定一个数是否为素数,其错误率可控制在极低的范围内。本文将详细介绍Miller-Rabin测试的基本原理、实现步骤以及...

    完整详细版Python全套教学课件 第02节 内置数据结构06作业.pptx

    Python的random模块提供了生成随机数的功能,如random.randint(a, b)可生成[a, b]范围内(包括a和b)的一个整数。要生成10个取值范围在[1, 20]的随机数,可以使用循环实现。然后,我们需要统计重复和不重复的数字。...

    费马素性检测,费马小定理

    - 在范围 \( [1, n-1] \) 内随机选取一个整数 \( a \)。 - 计算 \( a^{n-1} \mod n \)。 - 如果 \( a^{n-1} \mod n \neq 1 \),则返回“合数”。 2. 如果经过 \( k \) 次检测没有发现任何问题,则返回“可能是...

    LeetCode算法设计

    3. **猜数问题[E]**:这是一个互动问题,需要利用二分查找来猜出一个范围内的随机数。 4. **旋转后的二分查找[H]**:给定一个旋转排序数组和一个目标值,要求找到目标值在数组中的索引。此问题较为复杂,需要考虑...

    EXCEL集成工具箱V6.0

    【快捷综合取数】 功能较&lt;快捷取数列&gt;功能更强大,支持同时取6个不同存储格区域(或列)为6个唯一值清单,并在指定的6个不同的生效范围自适应地显示对应的清单。清单的最后6项也为子程序功能,能完成相关操作。且...

    《你必须知道的495个C语言问题》

    2.9 为什么不能用内建的==和!=操作符比较结构? 26 2.10 结构传递和返回是如何实现的? 26 2.11 如何向接受结构参数的函数传入常量值?怎样创建无名的中间的常量结构值? 26 2.12 怎样从/向数据文件读/写结构...

    2012年3月计算机等级考试二级c语言试题及答案[定义].pdf

    20. **随机数与switch**:rand()函数生成0到指定范围内的随机数,结合switch语句,根据生成的随机数决定打印的值。 以上内容涵盖了C语言的基础知识,包括数据结构、算法、程序设计原则、数据库操作以及程序的输入...

    你必须知道的495个C语言问题

    2.9 为什么不能用内建的==和!=操作符比较结构? 2.10结构传递和返回是如何实现的? 2.11 如何向接受结构参数的函数传入常量值?怎样创建无名的中间的常量结构值? 2.12 怎样从/向数据文件读/写结构? 结构...

Global site tag (gtag.js) - Google Analytics