C#生成随机数之二 生成不重复的随机数
来源:互联网 发布:java加密解密工具类 编辑:程序博客网 时间:2024/05/10 15:10
用 C# 生成不重复的随机数的三种方法
第一种方法:利用HashTable
/// <summary>/// 利用Hashtable/// </summary>static int[] UseHashTableToNonRepeatedRandom(int length, int minValue, int maxValue){ Hashtable hashtable = new Hashtable(); int seed = Guid.NewGuid().GetHashCode(); Random random = new Random(seed); for (int i = 0; hashtable.Count < length; i++) { int nValue = random.Next(minValue, maxValue); if (!hashtable.ContainsValue(nValue) && nValue != 0) { hashtable.Add(i, nValue); //hashtable.Add(nValue, nValue); // 将 key 和 value设置成一样的值,导致hashtable无法按添加顺序输出数组 //Console.WriteLine(nValue.ToString()); } } int[] array = new int[hashtable.Count]; hashtable.Values.CopyTo(array, 0); return array;}
注意事项:
1.该方法 length 和 maxValue的相关性比较强,使用时应该予以着重考虑
2.方法不适合生成 maxValue == length 相等的数据,
例如:不适合生成有10道考题的不重复题目号(要求从1-10,随机生成且不重复)
maxValue最好不等于length参数,
当 maxValue - minValue = length 时,时间效率差一个数量级【主要由于for循环内的生成语句导致】
实际测试生成1w个数 maxValue - minValue 是 length 的
2倍 :生成时间(使用7倍时)翻倍
7倍及以上:生成时间基本一致
3.使用HashTable保存 key 和 value 时,不要将同一个数值存入key和value,否则将导致数据顺序输出给数组
注意:
生成时间和具体使用的PC几性能有关,仅做参考!
效率说明:1w条数据测试
HashTable方法当ArrayNum_=_maxValue时
HashTable方法当maxValue是ArrayNum的1000倍时
第二种方法:递归(使用递归检测重复数)
/// <summary>/// 检查生成的随机数据是否重复/// 如果重复则继续递归调用/// 如果不重复则返回该数/// </summary>/// <param name="arr">生成的非重复随机数数组</param>/// <param name="temp">随机数</param>/// <param name="minValue">最大值</param>/// <param name="maxValue">最小值</param>/// <param name="random">生成随机数对象</param>/// <returns>返回一个不重复的随机数</returns>static int getNumberNonRepeatedRandom(int[] arr, int temp, int minValue, int maxValue, Random random){ int n = 0; while (n <= arr.Length - 1) { if (arr[n] == temp) //利用循环判断是否有重复 { temp = random.Next(minValue, maxValue); //重新随机获取。 getNumberNonRepeatedRandom(arr, temp, minValue, maxValue, random);//递归:如果取出来的数字和已取得的数字有重复就重新随机获取。 } n++; } return temp;}/// <summary>/// 递归,用它来检测生成的随机数是否有重复,如果取出来的数字和已取得的数字有重复就重新随机获取。/// </summary>static int[] RecursiveMethodToNonRepeatedRandom(int length, int minValue, int maxValue){ int seed = Guid.NewGuid().GetHashCode(); Random random = new Random(seed); int[] array = new int[length]; int temp = 0; for (int i = 0; i < length; i++) { temp = random.Next(minValue, maxValue); // 随机取数 array[i] = getNumberNonRepeatedRandom(array, temp, minValue, maxValue, random); // 取出值赋到数组中 } return array;}
注意事项:
使用条件:
1.maxValue - minValue = length。
若差值过于接近或等于length将导致 Stack Overflow Excepion 异常
该异常一般是因为函数调用栈溢出,
也就是函数调用的层次超出了程序能够接受的范围.
这种情况通常是由函数循环调用导致无限递归而引起的
2.实际测试生成1w个数 maxValue 是 length 的
2倍及以上:生成时间基本一致
效率说明:1w条数据测试
maxValue - minValue = length 若差值过于接近或等于length将导致 Stack Overflow Excepion 异常
实际测试生成1w个数 maxValue 是 length 的 2倍及以上:生成时间基本一致
第三种方法:使用双数组策略
【思路】:是用一个数组来保存索引号,先随机生成一个数组位置,然后把随机抽取到的位置的索引号取出来,并把最后一个索引号复制到当前的数组位置,然后使随机数的上限减一。
具体如:先把这100个数放在一个数组内,每次随机取一个位置(第一次是1-100,第二次是1-99,…),将该位置的数用最后的数代替。
/// <summary>/// 方法一 使用随机抽取数组index中的数,填充在新的数组array中,使数组array中的数是随机的/// 方法一思路:用一个数组来保存索引号,先随机生成一个数组位置,然后把随机抽取到的位置的索引号取出来,/// 并把最后一个索引号复制到当前的数组位置,然后使随机数的上限减一,具体如:先把这100个数放在一个数组内,/// 每次随机取一个位置(第一次是1-100,第二次是1-99,...),将该位置的数用最后的数代替。/// </summary>static int[] UseDoubleArrayToNonRepeatedRandom(int length, int minValue, int maxValue){ int seed = Guid.NewGuid().GetHashCode(); Random radom = new Random(seed); int[] index = new int[length]; for (int i = 0; i < length; i++) { index[i] = i + 1; } int[] array = new int[length]; // 用来保存随机生成的不重复的数 int site = length; // 设置上限 int idx; // 获取index数组中索引为idx位置的数据,赋给结果数组array的j索引位置 for (int j = 0; j < length; j++) { idx = radom.Next(0, site - 1); // 生成随机索引数 array[j] = index[idx]; // 在随机索引位置取出一个数,保存到结果数组 index[idx] = index[site - 1]; // 作废当前索引位置数据,并用数组的最后一个数据代替之 site--; // 索引位置的上限减一(弃置最后一个数据) } return array;}
注意事项:
1.生成上w条不重复随机数据时,建议使用该方法;
2.该方法生成的不重复随机数,参数length 和 maxValue 没有相互的限制关系,适合生成类似随机考题的类似情况;
3.效率是三个方法中最高的,推荐使用;
三个方法的效率比较:
maxValue是length的1000倍进行测试
完整代码:
using System;using System.Collections;using System.Diagnostics;namespace CSharp生成不重复的随机数{ class Program { /// <summary> /// 利用Hashtable /// </summary> /// <remarks> /// 使用条件: /// /// 1.该方法 length 和 maxValue的相关性比较强,使用时应该予以着重考虑 /// /// 2.方法不适合生成 maxValue == length 相等的数据, /// 例如:生成有10道考题的不重复题目号(要求从1-10,随机生成且不重复) /// maxValue最好不等于length参数, /// 当 maxValue - minValue = length 时,时间效率差一个数量级【主要由于for循环内的生成语句导致】 /// 实际测试生成1w个数 maxValue - minValue 是 length 的 /// 2倍 :生成时间(使用7倍时)翻倍 /// 7倍及以上:生成时间基本一致 /// 4.使用HashTable保存 key 和 value 时,不要将同一个数值存入key和value,否则将导致数据顺序输出给数组 /// 注意: /// 生成时间和具体使用的PC几性能有关,仅做参考! /// </remarks> static int[] UseHashTableToNonRepeatedRandom(int length, int minValue, int maxValue) { Hashtable hashtable = new Hashtable(); int seed = Guid.NewGuid().GetHashCode(); Random random = new Random(seed); for (int i = 0; hashtable.Count < length; i++) { int nValue = random.Next(minValue, maxValue); if (!hashtable.ContainsValue(nValue) && nValue != 0) { hashtable.Add(i, nValue); //hashtable.Add(nValue, nValue); // 将 key 和 value设置成一样的值,导致hashtable无法按添加顺序输出数组 //Console.WriteLine(nValue.ToString()); } } int[] array = new int[hashtable.Count]; hashtable.Values.CopyTo(array, 0); return array; } /// <summary> /// 检查生成的随机数据是否重复 /// 如果重复则继续递归调用 /// 如果不重复则返回该数 /// </summary> /// <param name="arr">生成的非重复随机数数组</param> /// <param name="temp">随机数</param> /// <param name="minValue">最大值</param> /// <param name="maxValue">最小值</param> /// <param name="random">生成随机数对象</param> /// <returns>返回一个不重复的随机数</returns> static int getNumberNonRepeatedRandom(int[] arr, int temp, int minValue, int maxValue, Random random) { int n = 0; while (n <= arr.Length - 1) { if (arr[n] == temp) //利用循环判断是否有重复 { temp = random.Next(minValue, maxValue); //重新随机获取。 getNumberNonRepeatedRandom(arr, temp, minValue, maxValue, random);//递归:如果取出来的数字和已取得的数字有重复就重新随机获取。 } n++; } return temp; } /// <summary> /// 递归,用它来检测生成的随机数是否有重复,如果取出来的数字和已取得的数字有重复就重新随机获取。 /// </summary> /// <remarks> /// 使用条件: /// 1.maxValue - minValue = length。 /// 若差值过于接近或等于length将导致 Stack Overflow Excepion 异常 /// 该异常一般是因为函数调用栈溢出, /// 也就是函数调用的层次超出了程序能够接受的范围. /// 这种情况通常是由函数循环调用导致无限递归而引起的 /// 2.实际测试生成1w个数 maxValue 是 length 的 /// 2倍及以上:生成时间基本一致 /// </remarks> static int[] RecursiveMethodToNonRepeatedRandom(int length, int minValue, int maxValue) { int seed = Guid.NewGuid().GetHashCode(); Random random = new Random(seed); int[] array = new int[length]; int temp = 0; for (int i = 0; i < length; i++) { temp = random.Next(minValue, maxValue); // 随机取数 array[i] = getNumberNonRepeatedRandom(array, temp, minValue, maxValue, random); // 取出值赋到数组中 } return array; } /// <summary> /// 方法一 使用随机抽取数组index中的数,填充在新的数组array中,使数组array中的数是随机的 /// 方法一思路:用一个数组来保存索引号,先随机生成一个数组位置,然后把随机抽取到的位置的索引号取出来, /// 并把最后一个索引号复制到当前的数组位置,然后使随机数的上限减一,具体如:先把这100个数放在一个数组内, /// 每次随机取一个位置(第一次是1-100,第二次是1-99,...),将该位置的数用最后的数代替。 /// </summary> /// <remarks> /// 使用条件: /// 1.生成上w条不重复随机数据时,建议使用该方法; /// 2.该方法生成的不重复随机数,参数length 和 maxValue 没有相互的限制关系 /// </remarks> static int[] UseDoubleArrayToNonRepeatedRandom(int length, int minValue, int maxValue) { int seed = Guid.NewGuid().GetHashCode(); Random radom = new Random(seed); int[] index = new int[length]; for (int i = 0; i < length; i++) { index[i] = i + 1; } int[] array = new int[length]; // 用来保存随机生成的不重复的数 int site = length; // 设置上限 int idx; // 获取index数组中索引为idx位置的数据,赋给结果数组array的j索引位置 for (int j = 0; j < length; j++) { idx = radom.Next(0, site - 1); // 生成随机索引数 array[j] = index[idx]; // 在随机索引位置取出一个数,保存到结果数组 index[idx] = index[site - 1]; // 作废当前索引位置数据,并用数组的最后一个数据代替之 site--; // 索引位置的上限减一(弃置最后一个数据) } return array; } static void Print(int[] array) { for (int i = 0; i < array.Length; i++) Console.Write(string.Format("{0} ", array[i])); Console.WriteLine(); } static void Main(string[] args) { int arrayNum = 10000; int minValue = 1; int maxValue = arrayNum * 100; Stopwatch sw = new Stopwatch(); sw.Start(); int[] array1 = UseHashTableToNonRepeatedRandom(arrayNum, minValue, maxValue + 1); //Print(array1); sw.Stop(); TimeSpan ts = sw.Elapsed; Console.WriteLine("使用HashTable总共花费{0}ms.", ts.TotalMilliseconds); sw.Reset(); sw.Start(); int[] array2 = RecursiveMethodToNonRepeatedRandom(arrayNum, minValue, maxValue + 1); //Print(array2); sw.Stop(); ts = sw.Elapsed; Console.WriteLine("使用Recursion总共花费{0}ms.", ts.TotalMilliseconds); sw.Reset(); sw.Start(); int[] array = UseDoubleArrayToNonRepeatedRandom(arrayNum, minValue, maxValue); //Print(array); sw.Stop(); ts = sw.Elapsed; Console.WriteLine("使用DoubleArray创建不重复随机数总共花费{0}ms.", ts.TotalMilliseconds); sw.Reset(); Console.ReadLine(); } }}
参考链接:
C# Random 生成不重复随机数
c# Random太快产生的随机数会重复
C# 产生真随机数(RNGCryptoServiceProvider)
C#生成随机数的三种方法
- C#生成随机数之二 生成不重复的随机数
- 用C#生成不重复的随机数
- C#生成不重复的随机数
- 使用c#生成不重复的随机数
- 用C#生成不重复的随机数
- 用C#生成不重复的随机数
- 用C#生成不重复的随机数
- C#生成100%不重复的随机数
- 用C#生成不重复的随机数
- 用C#生成不重复的随机数
- c#生成不重复随机数的方法
- C#下生成不重复的随机数
- 用C#生成不重复的随机数
- 用C#生成不重复的随机数
- C#生成不重复随机数的方法
- C# 生成不重复的随机数
- java之生成不重复的随机数
- 生成不重复的随机数
- [题解]bzoj1297(SCOI2009)迷路
- 关于mysql数据库8小时不进行操作连接自动断开问题的解决办法
- SSH学习之Struts2中的配置文件
- <context:annotation-config>与<context:component-scan>的区别
- Java 数组的输入输出
- C#生成随机数之二 生成不重复的随机数
- Docker-compose使用全解
- RecyclerView.Adapter 简化适配器
- leecode 解题总结:354. Russian Doll Envelopes
- 微信页面隐藏分享按钮
- 机器学习指标大汇总
- 树莓派使用RFID-RC522A读卡器对IC卡进行读写(通过 python)
- ANT安装指导
- 去除网站地址jsessionid