模仿 System.Random 提供的用户界面。可以从 System.Random 继承,也可以不。1、尽可能不重复。含义是,Next 方法在没有达到必定会重复的时候,就不能重复。
比如,生成21-24之间(含21和24)的伪随机数,则生成前4个数不能重复,当然,第5个数不可避免会重复的。
NextDouble 方法也要求返回尽可能不重复的数,也就是说,在耗尽大于或等于 0.0 而小于 1.0 的双精度浮点数之前,不得重复。
NextBytes 方法则可以要求在数组长度小于或等于 byte.MaxValue+1 (也就是256)时,返回的数组元素不得重复。若数组长度大于256,则要求前256个元素不得重复。2、随机性。我们知道,计算机不可能生成真正的随机序列,只能要求是伪随机序列。但我们可以要求这个序列不能有十分明显的规律,比如说,不能是等差数列、等比数列、斐波拿契数列,等等。3、高效。要求实现尽量高效,这可能会和随机性发生矛盾。比如,是否要在内部保存已生成的序列,以判定是否重复。以上抛砖引玉,还有很多方面都可以展开讨论。欢迎大家补充。

解决方案 »

  1.   

    以下 Skyiv.Random.Next(int minValue, int maxValue) 的实现只保证在每次都用同样的参数(minValue, maxValue)调用时是正确的,如果调用的参数不一样,则可能会出问题。namespace Skyiv
    {
      using System.Collections.Generic;  class Random : System.Random
      {
        private List<int> int32List = new List<int>();
        
        public override int Next(int minValue, int maxValue)
        {
          if (minValue == maxValue) return minValue;
          int next = base.Next(minValue, maxValue);
          if (int32List.Count >= maxValue - minValue) return next;
          if (int32List.Contains(next)) return Next(minValue, maxValue);
          int32List.Add(next);
          return next;
        }
      }
    }namespace Test
    {
      using System;
      using Rand = Skyiv.Random;
      
      class Program
      {
        static void Main()
        {
          Rand r = new Rand();
          Console.WriteLine(r.Next(21,25));
          Console.WriteLine(r.Next(21,25));
          Console.WriteLine(r.Next(21,25));
          Console.WriteLine(r.Next(21,25));
          Console.WriteLine(r.Next(21,25));
        }
      }
    }
      

  2.   

          Rand r = new Rand();
          Console.WriteLine(r.Next(15,99));  // 1
          Console.WriteLine(r.Next(10,80));  // 2
          Console.WriteLine(r.Next(21,25));  // 3
          Console.WriteLine(r.Next(21,23));  // 4
          Console.WriteLine(r.Next(21,22));  // 5
    如果是象上面那样调用,比如说,在第4次调用时,就应该检查前面的序列中是否已包含21和22,如果是,就不可避免重复,否则,就应该返回与前面不重复的整数。上面的实现就未必正确了。
      

  3.   

    使用 System.Security.Cryptography.RNGCryptoServiceProvider 生成 Random 实例的种子可以大大减小产生重复值的几率.关于相关对比请见:生成大量随机字符串不同实现方式的效率对比 
      

  4.   

    另外,在每次调用的参数(minValue, maxValue)都相同时,如果简单地返回 (上次的返回值+1)%区间长度,则不必保存前面生成的序列,也能保证不重复,却失去了随机性。
    如果每次返回 (new System.Random((上次的返回值+1)%区间长度)).Next(minValue, maxValue),是否可以保证不重复呢?随机性又如何?
      

  5.   

    空空儿的思路很好。但我们的要求是:没有达到必定会重复的时候,就不能重复。这可能很不容易做到高效,特别是参数(minValue, maxValue)可变时,而参数必须可变。
      

  6.   

    1楼的实现仅仅是个示例,还很不完善。例如,还要加上指定的种子值的构造函数。namespace Skyiv
    {
      class Random : System.Random
      {
        public Random(int Seed) : base(Seed){}
      }
    }还有其他的方法也需要重写,如public virtual int Next()
    public virtual int Next(int maxValue)
    public virtual double NextDouble()
    public virtual void NextBytes(byte[] buffer)
      

  7.   

    在我的测试中生成100W,产生的重复值在200-500之间,耗时在20000MS-30000MS之间
    生成的是字符串,如果生成数字的话,重复值会上升,耗时可能会更长
      

  8.   

    如果生成等差数列,效率非常高,但失去了随机性。如4楼所说,每次返回 (new System.Random((上次的返回值+1)%区间长度)).Next(minValue, maxValue),不知效果如何?也就是说:是否可以保证不重复呢?随机性又如何?
      

  9.   

    namespace Skyiv
    {
      using System.Collections.Generic;  class Random : System.Random
      {
        private List<double> doubleList = new List<double>();    public Random(int Seed) : base(Seed){}    public override double NextDouble()
        {
          double next = base.NextDouble();
          if (doubleList.Contains(next)) return NextDouble();
          doubleList.Add(next);
          return next;
        }
      }
    }NextDouble 似可这样实现,请大家看看还有什么更高效的实现。另,这种实现在耗尽大于或等于 0.0 而小于 1.0 的双精度浮点数后,会陷入无限递归,导致用完stack而抛出异常。但,大于或等于 0.0 而小于 1.0 的双精度浮点数不知有多少个,有谁知道吗?我想应该是非常非常多的。
      

  10.   

    另,是否应该实现一个 DoubleList 属性,来公开目前为止已生成的序列:    public List<double> DoubleList
        {
          get { return doubleList; }
        }问题是,怎么防止外部程序更改这个序列呢?
      

  11.   

    好了,现在真的要去睡觉了。已经是三月八日了,祝csdn的女同胞们节日快乐。
      

  12.   

    接17楼,为防止外部程序更改这个序列,是不是可以这样公开DoubleList:    public System.Collections.ObjectModel.ReadOnlyCollection<double> DoubleList
        {
          get { return doubleList.AsReadOnly(); }
        }
      

  13.   

    我们知道:Console.WriteLine(double.Epsilon);  // 输出:4.94065645841247E-324/*
    而 double.Epsilon 字段的含义是:表示大于零的最小正 double。两个看来相等的浮点数字的比较结果可能为不相等,因为它们的最低有效位不同。例如,C# 表达式 (double)1/3 == (double)0.33333 的比较结果为不相等,因为左侧的除法运算具有最大精度,而右侧的常数仅精确到可见位。相反,它通过比较左右两边的差的绝对值是否小于 double.Epsilon,确定比较的双方是否近似相等。
    */接16楼的话题,我们是否可以猜测,大于或等于 0.0 而小于 1.0 的双精度浮点数的个数是不是大约为 1/double.Epsilon,也就是 2.0240225330731E+323。
      

  14.   

    接1楼的话题:namespace Test
    {
      using System;
      using Rand = Skyiv.Random;
      
      class Program
      {
        static void Main()
        {
          Rand r = new Rand();
          int  N = 10000;
          int[] array = new int[N + 1];
          for (int i = 0; i < array.Length - 1; i++)
          {
            array[i] = r.Next(0, array.Length * 2);
          }
          Console.WriteLine(array[0]);
          Console.WriteLine(array[array.Length - 2]);
          // 以上生成 10000 个不重复的伪随机数,这没问题。      // 在已经有长度为 10000 的序列后,下面要生成一个 50-79 之间的随机数,
          // 就该检查是不是已经不可能不重复了,也就是前面 10000 个数是不是已经完整地覆盖了 50-79。
          // 如果不是,就应该返回一个不重复的伪随机数,否则,只好随机地返回一个 50-79 之间的整数。
          // 而我1楼的程序就不符合以上要求,极有可能在可以不重复的情况下返回一个重复的伪随机数。
          array[array.Length - 1] = r.Next(50, 80);
          Console.WriteLine(array[array.Length - 1]);
        }
      }
    }
      

  15.   

    namespace Skyiv
    {
      using System.Collections.Generic;  class Random : System.Random
      {
        private List<int> int32List = new List<int>();
        
        public override int Next(int minValue, int maxValue)
        {
          if (minValue == maxValue) return minValue;
          int next = base.Next(minValue, maxValue);
          if (int32List.Count >= maxValue - minValue) return next;
          if (int32List.Contains(next)) return Next(minValue, maxValue);
          int32List.Add(next);
          return next;
        }
      }
    }namespace Test
    {
      using System;
      using Rand = Skyiv.Random;
      
      class Program
      {
        static void Main()
        {
          Rand r = new Rand();
          Console.WriteLine(r.Next(21,25));
          Console.WriteLine(r.Next(21,25));
          Console.WriteLine(r.Next(21,25));
          Console.WriteLine(r.Next(21,25));
          Console.WriteLine(r.Next(21,25));
        }
      }
    }
      

  16.   


    1: 把你最终需要的结果(不重复的数)预先放在一个数组中, 因为rand函数产生的随机数会重复,我们不直接用,而是用来对应数组的下标
    2: rand产生一个随机下标,我们就取出对应数组中的值(我们真正需要的随机数)
    3: 然后用数组最后一个值来替换该下标数组中的值
    4: 将产生随机下标的范围减少一
    5: goto 2注: 3中所谓数组最后一个值是指产生随机下标范围内的最后一个. 
         如产生随机下标0-9, 第一次就用array[9]替换,第二次就用array[8]替换.#include<time.h>
    #include<stdlib.h>
    #include <stdio.h>#define NUM 10int main()
    {
        int cont[NUM];
        int index, i;    for (i=0; i<NUM; i++)
            cont[i] = i;    srand((int)time(0));    for (i=0; i<NUM; i++) {
            index = (int)((float)(NUM-i) * rand() / (RAND_MAX+1.0));
            printf("%d ", cont[index]);
            cont[index] = cont[NUM-1-i];
        }
        putchar('\n');    return 0;
    }
      

  17.   

    以下是 Skyiv.Random.Next(int minValue, int maxValue) 的一个新实现,效率很成问题,但应该是正确地实现了尽可能不重复的要求,请大家测试:namespace Skyiv
    {
      using System;
      using System.Collections.Generic;
      using System.Collections.ObjectModel;  class Random : System.Random
      {
        private List<int> int32List = new List<int>();    public ReadOnlyCollection<int> Int32List
        {
          get { return int32List.AsReadOnly(); }
        }        public override int Next(int minValue, int maxValue)
        {
          return Next(minValue, maxValue, true);
        }
        
        private int Next(int minValue, int maxValue, bool check)
        {
          bool full = false;
          if (check)
          {
            if (minValue > maxValue)
              throw new ArgumentOutOfRangeException("minValue", "“minValue”不能大于 maxValue");
            if (minValue == maxValue)
            {
              int32List.Add(minValue);
              return minValue;
            }
            int n = 0;
            for (int i = minValue; i < maxValue; i++)
            {
              if (int32List.Contains(i)) n++;
            }
            full = n == maxValue - minValue;
          }
          int next = base.Next(minValue, maxValue);
          if (full) return next;
          if (int32List.Contains(next)) return Next(minValue, maxValue, false);
          int32List.Add(next);
          return next;
        }
      }
    }
      

  18.   

    至于 Next 方法的另外两个重载版本,则相当简单:    public override int Next()
        {
          return Next(0, int.MaxValue);
        }    public override int Next(int maxValue)
        {
          if (maxValue < 0)
            throw new ArgumentOutOfRangeException("maxValue", "“maxValue”必须大于或等于零");
          return Next(0, maxValue);
        }
      

  19.   

    godogoflive的想法不错,就是不知在数组很大时(这时需要大量的内存)性能如何,可能要比我26楼的实现效率高。我按这个想法来做一个实现看看。
      

  20.   

    在实现25楼godogoflive的想法时,才发现该思路只能用于每次调用Next()方法时都使用同样的参数(minValue, maxValue)的情形,那还不如直接使用我1楼的实现,简单,又不浪费空间。
      

  21.   


    不要光路过,学习啊,我抛了那么多,也应该引一点来啊。象25楼godogoflive的想法也是一种不同的思路啊。
    来得更猛烈些吧!
      

  22.   

    重写 public virtual void NextBytes(byte[] buffer):// SkyivRandomNextBytes.cs:NextBytes()方法重写namespace Skyiv
    {
      using System.Collections.Generic;  partial class Random : System.Random
      {
        private List<byte> byteList;
        
        // 重写基类的方法
        public override void NextBytes(byte[] buffer)
        {
          if (byteList != null) byteList.Clear();
          byteList = new List<byte>(buffer.Length);
          int i;
          for (i = 0; i < buffer.Length && i < byte.MaxValue + 1; i++)
          {
            byte next = NextByte();
            byteList.Add(next);
          }
          for (; i < buffer.Length; i++)
          {
            byte next = (byte)base.Next(byte.MaxValue + 1);
            byteList.Add(next);
          }
          byteList.CopyTo(buffer);
        }
        
        private byte NextByte()
        {
          byte next = (byte)base.Next(byte.MaxValue + 1);
          if (byteList.Contains(next)) return NextByte();
          return next;
        }
      }
    }
      

  23.   

    // SkyivRandom.cs:构造函数namespace Skyiv
    {
      partial class Random : System.Random
      {
        
        public Random() : base() { }
        public Random(int Seed) : base(Seed) { }
      }
    }
      

  24.   

    // Program.cs:程序入口点,测试用。namespace Test
    {
      using System;
      using Rand = Skyiv.Random;  class Program
      {
        static void Main()
        {
          Rand r = new Rand();
          byte[] bs = new byte[20];
          r.NextBytes(bs);
          foreach (byte b in bs)
          {
            Console.WriteLine(b);
          }
          Console.ReadLine();
        }
      }
    }
      

  25.   

    // SkyivRandomNextDouble.cs:NextDouble()方法重写namespace Skyiv
    {
      using System.Collections.Generic;
      using System.Collections.ObjectModel;  partial class Random : System.Random
      {
        private List<double> doubleList = new List<double>();    // doubleList 的只读副本
        public ReadOnlyCollection<double> DoubleList
        {
          get { return doubleList.AsReadOnly(); }
        }    // 重写基类的方法
        public override double NextDouble()
        {
          double next = base.NextDouble();
          if (doubleList.Contains(next)) return NextDouble();
          doubleList.Add(next);
          return next;
        }
      }
    }
      

  26.   

    Next()方法重写的效率最差,请大家重点改进:// SkyivRandomNext.cs:Next()方法重写namespace Skyiv
    {
      using System;
      using System.Collections.Generic;
      using System.Collections.ObjectModel;  partial class Random : System.Random
      {
        private List<int> int32List = new List<int>();    public ReadOnlyCollection<int> Int32List
        {
          get { return int32List.AsReadOnly(); }
        }    public override int Next()
        {
          return Next(0, int.MaxValue);
        }    public override int Next(int maxValue)
        {
          if (maxValue < 0)
            throw new ArgumentOutOfRangeException("maxValue", "“maxValue”必须大于或等于零");
          return Next(0, maxValue);
        }    public override int Next(int minValue, int maxValue)
        {
          return Next(minValue, maxValue, true);
        }    private int Next(int minValue, int maxValue, bool check)
        {
          bool full = false;
          if (check)
          {
            if (minValue > maxValue)
              throw new ArgumentOutOfRangeException("minValue", "“minValue”不能大于 maxValue");
            if (minValue == maxValue)
            {
              int32List.Add(minValue);
              return minValue;
            }
            int n = 0;
            for (int i = minValue; i < maxValue; i++)
            {
              if (int32List.Contains(i)) n++;
            }
            full = n == maxValue - minValue;
          }
          int next = base.Next(minValue, maxValue);
          if (full) return next;
          if (int32List.Contains(next)) return Next(minValue, maxValue, false);
          int32List.Add(next);
          return next;
        }
      }
    }
      

  27.   

    不懂C#,平时用EXCEL解决1~100的正整数随机排序时,使用下面的方法:搞一个2维数组
    第一维为随机数,第二维为等差序列
    对该数组按照第一维排序,就得到第二维的随机顺序排列。
      

  28.   

    1、尽可能不重复。含义是,Next 方法在没有达到必定会重复的时候,就不能重复。 
    比如,生成21-24之间(含21和24)的伪随机数,则生成前4个数不能重复,当然,第5个数不可避免会重复的。 
    NextDouble 方法也要求返回尽可能不重复的数,也就是说,在耗尽大于或等于 0.0 而小于 1.0 的双精度浮点数之前,不得重复。 
    NextBytes 方法则可以要求在数组长度小于或等于 byte.MaxValue+1 (也就是256)时,返回的数组元素不得重复。若数组长度大于256,则要求前256个元素不得重复。
     这个设计有问题,所谓(伪)随机数,是尽量随机得到一个数字,让人无法猜出下一个数会是什么。如果照lz说的,用生成21-24之间(含21和24)的伪随机数为例来说,那么我可以3次调用,得出第四个数是什么!这就失去了随机的意义了。如果lz想要高效,可靠的实现,建议使用Windows Crypt API,里面有专门的随机数发生器——CryptGenRandom,并且它是FIPS 140-1认可,这个在不少国家都认可的高效可靠算法。我看了ls的达人们的贴,基本上真正的随机数发生器都采用System.Random,而.NET的Random算法是线性的,lz可以读读下面的代码,这是从.NET shared source里摘抄的,有很详细的注释,也就是说,这样生成的数字依然是线性的,只不过线性数据中间某些被过滤而已。3楼的方法是可取的,RNGCryptoServiceProvider是.NET实现的为随机数发生器,和Crypt API基本上一样(实际内部还是有不少区别的,参考MSDN)。// ==++== 
    //
    //   Copyright (c) Microsoft Corporation.  All rights reserved.
    //
    // ==--== 
    /*============================================================
    ** 
    ** Class:  Random 
    **
    ** 
    ** Purpose: A random number generator.
    **
    **
    ===========================================================*/ 
    namespace System {
     
        using System; 
        using System.Runtime.CompilerServices;
        using System.Globalization; 
    [System.Runtime.InteropServices.ComVisible(true)]
        [Serializable()] public class Random {
          //
          // Private Constants 
          //
          private const int MBIG =  Int32.MaxValue; 
          private const int MSEED = 161803398; 
          private const int MZ = 0;
           //
          // Member Variables
          // 
          private int inext, inextp;
          private int[] SeedArray = new int[56]; 
     
          //
          // Public Constants 
          //      //
          // Native Declarations 
          //
     
          // 
          // Constructors
          //       public Random()
            : this(Environment.TickCount) {
          }       public Random(int Seed) { 
            int ii; 
            int mj, mk;
     
            //Initialize our Seed array.
            //This algorithm comes from Numerical Recipes in C (2nd Ed.)
            mj = MSEED - Math.Abs(Seed);
            SeedArray[55]=mj; 
            mk=1;
            for (int i=1; i<55; i++) {  //Apparently the range [1..55] is special (Knuth) and so we're wasting the 0'th position. 
              ii = (21*i)%55; 
              SeedArray[ii]=mk;
              mk = mj - mk; 
              if (mk<0) mk+=MBIG;
              mj=SeedArray[ii];
            }
            for (int k=1; k<5; k++) { 
              for (int i=1; i<56; i++) {
            SeedArray[i] -= SeedArray[1+(i+30)%55]; 
            if (SeedArray[i]<0) SeedArray[i]+=MBIG; 
              }
            } 
            inext=0;
            inextp = 21;
            Seed = 1;
          }       // 
          // Package Private Methods 
          //
     
          /*====================================Sample====================================
          **Action: Return a new random number [0..1) and reSeed the Seed array.
          **Returns: A double [0..1)
          **Arguments: None 
          **Exceptions: None
          ==============================================================================*/ 
          protected virtual double Sample() { 
              //Including this division at the end gives us significantly improved
              //random number distribution. 
              return (InternalSample()*(1.0/MBIG));
          }      private int InternalSample() { 
              int retVal;
              int locINext = inext; 
              int locINextp = inextp;           if (++locINext >=56) locINext=1; 
              if (++locINextp>= 56) locINextp = 1;          retVal = SeedArray[locINext]-SeedArray[locINextp];
     
              if (retVal<0) retVal+=MBIG;
     
              SeedArray[locINext]=retVal;           inext = locINext; 
              inextp = locINextp;          return retVal;
          }       // 
          // Public Instance Methods 
          //
           /*=====================================Next=====================================
          **Returns: An int [0..Int32.MaxValue)
          **Arguments: None 
          **Exceptions: None.
          ==============================================================================*/ 
          public virtual int Next() { 
            return InternalSample();
          }       private double GetSampleForLargeRange() {
              // The distribution of double value returned by Sample
              // is not distributed well enough for a large range. 
              // If we use Sample for a range [Int32.MinValue..Int32.MaxValue)
              // We will end up getting even numbers only. 
     
              int result = InternalSample();
              // Note we can't use addition here. The distribution will be bad if we do that. 
              bool negative = (InternalSample()%2 == 0) ? true : false;  // decide the sign based on second sample
              if( negative) {
                  result = -result;
              } 
              double d = result;
              d += (Int32.MaxValue - 1); // get a number in range [0 .. 2 * Int32MaxValue - 1) 
              d /= 2*(uint)Int32.MaxValue - 1  ; 
              return d;
          } 
          /*=====================================Next=====================================
          **Returns: An int [minvalue..maxvalue) 
          **Arguments: minValue -- the least legal value for the Random number.
          **           maxValue -- One greater than the greatest legal return value. 
          **Exceptions: None. 
          ==============================================================================*/
          public virtual int Next(int minValue, int maxValue) { 
              if (minValue>maxValue) {
                  throw new ArgumentOutOfRangeException("minValue",String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_MinMaxValue"), "minValue", "maxValue"));
              }
     
              long range = (long)maxValue-minValue;
              if( range <= (long)Int32.MaxValue) { 
                  return ((int)(Sample() * range) + minValue); 
              }
              else { 
                  return (int)((long)(GetSampleForLargeRange() * range) + minValue);
              }
          }
           /*=====================================Next===================================== 
          **Returns: An int [0..maxValue) 
          **Arguments: maxValue -- One more than the greatest legal return value.
          **Exceptions: None. 
          ==============================================================================*/
          public virtual int Next(int maxValue) {
              if (maxValue<0) {
                  throw new ArgumentOutOfRangeException("maxValue", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_MustBePositive"), "maxValue")); 
              }
              return (int)(Sample()*maxValue); 
          }  
          /*=====================================Next=====================================
          **Returns: A double [0..1)
          **Arguments: None
          **Exceptions: None 
          ==============================================================================*/
          public virtual double NextDouble() { 
            return Sample(); 
          }
           /*==================================NextBytes===================================
          **Action:  Fills the byte array with random bytes [0..0x7f].  The entire array is filled.
          **Returns:Void 
          **Arugments:  buffer -- the array to be filled.
          **Exceptions: None 
          ==============================================================================*/ 
          public virtual void NextBytes(byte [] buffer){
            if (buffer==null) throw new ArgumentNullException("buffer"); 
            for (int i=0; i<buffer.Length; i++) {
              buffer[i]=(byte)(InternalSample()%(Byte.MaxValue+1));
            }
          } 
        }
     
     } 
      

  29.   


    private void button2_Click(object sender, EventArgs e)
            {
                Dictionary<double, object> test = new Dictionary<double, object>();
                int DoubleCount = 0;
                for (int bi1 = 0; bi1 < 10000000; bi1++)
                {
                    Guid temp = Guid.NewGuid();
                    double Return = BitConverter.ToDouble(temp.ToByteArray(), 0);
                    if (test.ContainsKey(Return))
                    {
                        DoubleCount++;
                    }
                    else
                    {
                        test.Add(Return,null);
                    }
                }
                this.Text = DoubleCount.ToString();        }LZ看看这段代码...1千万个随机数,没有一个重复..
      

  30.   


    Guid temp = Guid.NewGuid();
    double Return = BitConverter.ToDouble(temp.ToByteArray(), 0);这是实际的随机数产生代码..
      

  31.   


    Dictionary<double, object> test = new Dictionary<double, object>();
                int DoubleCount = 0;
                for (int a = 0; a < 10000000; a++)
                {
                   
                    Guid temp = Guid.NewGuid();
                    ulong bi1 = BitConverter.ToUInt64(temp.ToByteArray(), 0);
                    bi1 = bi1 & 0x7FFFFFFFFFFFF;//00000000 00001111 11111111 11111111 11111111 11111111 11111111 1111111
                    bi1 = bi1 | 0x3FF8000000000000;
                    byte[] bb = BitConverter.GetBytes(bi1);
                    double Return = BitConverter.ToDouble(bb, 0);
                    if (test.ContainsKey(Return))
                    {
                        DoubleCount++;
                    }
                    else
                    {
                        test.Add(Return,null);
                    }
    实用的纯小数代码...1去不掉了,不行就执行一个减1操作..
      

  32.   

     System.Security.Cryptography.RNGCryptoServiceProvider 的随机性会高很多GUID的随机性好像是最高的,我的项目中经常使用GUID
      

  33.   


    Dictionary<double, object> test = new Dictionary<double, object>();
                int DoubleCount = 0;
                for (int a = 0; a < 10000000; a++)
                {
                   
                    Guid temp = Guid.NewGuid();
                    ulong bi1 = BitConverter.ToUInt64(temp.ToByteArray(), 0);
                    bi1 = bi1 & 0x7FFFFFFFFFFFF;//00000000 00001111 11111111 11111111 11111111 11111111 11111111 1111111
                    bi1 = bi1 | 0x3FF8000000000000;
                    byte[] bb = BitConverter.GetBytes(bi1);
                    double Return = BitConverter.ToDouble(bb, 0);
                    if (test.ContainsKey(Return))
                    {
                        DoubleCount++;
                    }
                    else
                    {
                        test.Add(Return,null);
                    }
    那这个算法没有满足楼主要求吗?
      

  34.   

    50楼的程序是可以应用于NextDouble()的。还有Next(int minValue, int maxValue),并且要求minValue、maxValue可变的情形没有讨论。
      

  35.   

    看了好多高手的写的东西,还真的是学到了不少东西。不过,我自己也学到了一些东西。我的老师曾经交了我一个算不重复的随机数的方法。和25楼的算法差不多。我自己些了个算法:class Program
        {
            static List<int> GetRandom(int maxCount)
            {
                Random rnd = new Random();
                List<int> lsOld = new List<int>();
                //为一个泛型集合添加1到maxCount的顺序数字
                for (int i = 0; i < maxCount; i++)
                {
                    lsOld.Add(i);
                }            int temp;
                int tempRnd;
                for (int i = maxCount; i > 0; i--)
                {
                    tempRnd = rnd.Next(0, i - 1);
                    temp = lsOld[i - 1];
                    lsOld[i - 1] = lsOld[tempRnd];
                    lsOld[tempRnd] = temp;
                }
                return lsOld;
            }
            static void Main()
            {
                //只添加100个不重复的随即数
                List<int> lsAll;            DateTime startTime = DateTime.Now;            lsAll = GetRandom(1000000);
                //foreach (int i in lsAll)
                //{
                //    Console.WriteLine(i);
                //}            TimeSpan timeSpan = DateTime.Now - startTime;            Console.WriteLine("共消耗时间:" + timeSpan.TotalMilliseconds + "毫秒");
                Console.ReadKey();        }
        }
      

  36.   

    随机数就是要保证统计概率为1/N如果按楼主设计
    那么
    1-N之间随机整数概率将在N/2次子后变大例如N=5
    第一次 3    概率1/5
    第二次 1    概率1/4
    第三次 4    概率1/3
    第四次 2    概率1/2
    第五次 5    概率1/1 必然没有意义啊
      

  37.   

    在值域小数量级下可以做一个值域的全排列,然后随机抽取一个全排列作为一组随机数输出。
    在大数量级下一般用循环链表来解决这个问题。即将值域中所有值作为一个循环链表,从第一个节点开始,取一个随机数便向后推进随机个节点,输出这个节点并将其从循环链表中删除。但是如果要在链表大小范围内抽取随机数,或许向后检索一个很大的个数的时候性能不够好,即使采用双向检索(将超过链表一半大小的检索转变为向后检索)也不能获得很好的性能,那么可以参考十字链表的做法,做一个循环十字链表。如下图结构:  A1 -> A2 -> A3 -> A4 .....  A10 ->接A11
      ↓     ↓     ↓     ↓         ↓
    ->A11   A12   A13   A14....  A20
      ....
    这里是按照十进制做的二维,如果我们要从A1向后14项,那么只需要按照向下的顺序向后推进1项,向前的顺序推进4项即可。
      

  38.   

    刚查了一些统计计算方面的教材, 找到这个网站,希望能有帮助http://www.fjtu.com.cn/fjnu/courseware/1017/course/_source/web/lesson/char6/j2.htm
      

  39.   

    楼上曾经有人提到过用数组来记录是不是已经重复,当然这在数据量大的时候,效率是很难保证的。我想,既然楼主那么执著的要实现一个不重复的随机,我倒是觉得可以把我们生成的记录保存到磁盘,然后参照B tree或者B+ tree的方式来形成索引,以提高遍历时的效率。
    当然,因为中间有大量io操作,效率降低在所难免。而取随机数,上文的朋友提到是一个正态分布或者泊松分布的问题,我也这么认为,那么,当你的取值区间很小时,你的重复的概率就高。 那么,我们可以通过增大取值区间来降低重复的概率。
    说得不好,请大家不要见笑。
      

  40.   

    MARK uP
      

  41.   

    说个整数情况下的想法:
    1、MaxValue和MinValue只能通过new输入,创建好之后不能改变(否则就麻烦了)
    2、Count=MaxValue-MinValue
    3、随机产生n个数字(m1,m2,m3...mn),保证这些数字与Count互质
    4、用每一个数字做等差数列,例如:
    f1(x)=m1*x%Count;
    f2(x)=f1(m2*x%Count);
    ...
    fn(x)=fn-1(mn*x%Count);
    5、每一次调用Next方法就是x++,然后对MinValue+fn(x)求解
    6、当x=Count时,重新生成随机数m1,m2,m3...mn,x重置为0,达到重新排列的目的
    附:可以通过增加m的数量,来减少规律
      

  42.   

    做过一个不能重复的随机数的东西 ,不过值是4位的,太小,
    我是用链表保存了所有的4位数的值(for循环加的),然后用随机数当作链表的位置,
    取出来一个就把这个数在链表中删掉,每次random的最大值-1