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

原创 2014年12月02日 07:22:57

重要说明:本博已迁移到 石佳劼的博客,有疑问请到 文章新地址 留言!!!

最近网上看到一道题,如何取100以内不重复的100个随机数?代码如下:

var nums = new int[100];
var list = new List<int>();
var random = new Random();
for (int i = 0; i < 100; i++)
{
    int r;
    while (list.Contains(r = random.Next(0, 99))) { }
    list.Add(r);
    nums[i] = r;
}

个人感觉题目很经典,因为实际生活中会经常遇到该类问题,但答案却如此低效,不免有一些失望,打开vs试了一把,果然2分钟都没跑完。

好的题目却没有好的答案些不甘心,便继续探索了一下,发现该问题确实不简单,在《 Programming Pearls 》一书中也有提到,题目为“如何高效产生m个n范围内的不重复随机数(m<=n)”,如果还继续使用以上算法,把m、n放大到10000,估计程序1个小时都跑不完,效率令人发指。

那么该书中是如何解决该问题的呢?代码如下:

var nums = new int[100];
var random = new Random();
for (int i = 0; i < 100; i++)
{
    nums[i] = i;
}
for (int i = 0; i < 100; i++)
{
    var r = random.Next(i, 99);
    Swap(ref nums[i], ref nums[r]);
}

该算法非常巧妙的取随机数的位置(数组的下标),替代取随机数本身,每次取到一个随机数之后,就将其在取值范围中排除,下一次仅会在剩下的数字中取,一次遍历就可以完成随机数的选取,效率相当高。

下面详细讲解该方法:

  1. 首先,为数组的每个数字按其位置(数组的下标)赋值,我们获得一个100个数字顺序排列的数组。
  2. 然后,开始取 i-99 范内的随机数,把每次取到的随机数作为位置(数组的下标)与位置(数组的下标)为 i 的数交换数值。这样做的意义是,将已经取到的随机数在取值范围中排除,下一次去随机数仅会在剩下的数字中取。

第2步不太容易理解,我带大家分析每一步的具体原理,你马上就能一目了然:
循环:i = 0 , r = 39(假设随机数为该值) ,交换 nums[0] 和 nums[39] 的值。
分析:第一次取到的随机数是39,把位置39的数位置0的数交换之后,再从位置1开始看该数组,你会惊奇的发现,剩下的是0-99除39以外的所有数字,但它们的位置是1-99,接下来我们仅需要从1-99中取一个随机数,作为数组下标,即可在剩下的数字中取随机数了,以此类推。

欢迎来到 石佳劼的博客,如有疑问,请在「原文」评论区 留言,我会尽量为您解答。


版权声明:本文为博主原创文章,欢迎转载,但需注明出处。

c++中生成n个m位的随机不重复字符串的一种方法(字母+数字)

本文系原创,转载注明。 想生成n个m位的随机不重复字符串。 以下n=15*15*15=3375; m=17 为例: 设定一个数组: public static string[] str = n...
  • ccm_oliver
  • ccm_oliver
  • 2016年03月31日 22:00
  • 1603

生成不重复验证码

import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Ra...
  • goodleiwei
  • goodleiwei
  • 2014年12月22日 11:00
  • 2941

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

如何产生不重复的随机数?最容易想到的方法,是逐个产生这些随机数,每产生一个,都跟前面的随机数比较如果重复,就重新产生。这是个很笨的方法,且比较次数呈线性增长,越往后次数越多。其实这些比较是多余的,完全...
  • hj3601947
  • hj3601947
  • 2016年08月18日 11:21
  • 534

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

如何产生不重复的随机数?最容易想到的方法,是逐个产生这些随机数,每产生一个,都跟前面的随机 数比较,如果重复,就重新产生。这是个很笨的方法,且比较次数呈线性增长,越往后次数越多。其实这些 比较是多余的...
  • a316212802
  • a316212802
  • 2014年12月23日 22:14
  • 5434

返回一组不重复随机数生成方法-(完美,100%不重复)

正好工作需要,需要一个方法能返回一组不重复的随机数,网上查了好多资料和实例。发现都是加时间种子的比较多。 最后自己想到了好办法。效率也高。100%不重复。 下面贴出代码:         ///  ...
  • wuguandi
  • wuguandi
  • 2016年02月20日 01:19
  • 721

生成不重复的随机数的高效的算法

#include #include #include #define SIZE 10 void generateRandom(); int main(){ srand((unsigned)ti...
  • robin_Xu_shuai
  • robin_Xu_shuai
  • 2016年05月19日 15:45
  • 517

一种生成不重复数的算法

 在编程中经常遇到一些类似的问题,比如做一个双色球选号软件,其中6个双色球是从1到33之间选出6个数来,这6个数是不能重复的,这个问题就是我们今天要说的生成不重复数算法。算法描述如下:从M个数中选出N...
  • zhoufoxcn
  • zhoufoxcn
  • 2007年10月24日 19:35
  • 5521

如何产生m~n范围的随机数 C++

C++的随机数函数为rand(), 可以获得一个非负整数的随机数。 要让随机数限定在一个范围,可以采用模除加加法的方式。 要产生随机数r, 其范围为 m...
  • oldthree118
  • oldthree118
  • 2016年09月06日 14:56
  • 413

产生不重复的随机数(范围:1000000-9999999)

因为《编程珠玑》的第一章是对文件排序,首先需要产生是一些不重复的随机数。关于产生不重复的随机数,可以用Hashtable的方式,即随机产生一个数就去检测,列表中这个数是否已经存在,然而这种非常耗时。有...
  • woaixfj
  • woaixfj
  • 2015年03月29日 20:48
  • 752

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

如何产生不重复的随机数?最容易想到的方法,是逐个产生这些随机数,每产生一个,都跟前面的随机 数比较,如果重复,就重新产生。这是个很笨的方法,且比较次数呈线性增长,越往后次数越多。其实这些 比较是多余的...
  • a316212802
  • a316212802
  • 2014年12月23日 22:14
  • 5434
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:算法:如何高效产生m个n范围内的不重复随机数(m<=n)
举报原因:
原因补充:

(最多只允许输入30个字)