C#实现指定范围内不重复随机数生成的四种方法
在C#开发中,生成不重复随机数是常见的需求。本文将深入解析四种主流实现方案,从基础的遍历查重到高效的空间置换算法,并提供可运行的核心代码片段,协助解决此技术难题。
问题背景与挑战
C#标准库中的 System.Random 类提供的 Next() 方法只能生成单个随机整数,本身不具备去重机制。若需获取一个范围内的不重复序列(如1到100中取10个不重复数字),直接循环调用往往会导致碰撞,需要通过额外的逻辑进行过滤或管理已选数据状态。
准备条件与通用参数
- 目标范围:设定最小值
minValue和最大值maxValue。 - 抽取数量:确定需要生成的不重复随机数个数
count。 - 依赖组件:主要使用
System命名空间下的Random类;部分方法涉及System.Collections或System.Linq。
实现方法详解
第1步:基础循环与内部查重
这是最直观的逻辑:每次生成一个随机数后,遍历当前结果数组检查是否已存在。如果已存在则忽略本次生成并重新尝试(通过递减索引实现重试)。
- 入口/动作:初始化一个长度为
Number的整型数组,外层循环控制生成次数,内层循环用于比对历史数据。 - 关键逻辑:当发现冲突(
num > 0)时,通过j--使外层循环回退,确保最终填满有效数组。 - 代码示例
public int[] GetRandomArray(int Number, int minNum, int maxNum)
{
int j;
int[] b = new int[Number];
Random r = new Random();
for (j = 0; j < Number; j++)
{
// 包含上限
int i = r.Next(minNum, maxNum + 1);
int num = 0;
// 检查是否与之前生成的数重复
for (int k = 0; k < j; k++)
{
if (b[k] == i)
{
num++;
break; // 只要发现重复即可提前跳出
}
}
if (num == 0)
{
b[j] = i;
}
else
{
// 发生重复,本次计数作废,重新生成
j--;
}
}
return b;
}
第2步:数组置换法(推荐高效方案)
该方法的思路类似于“抽彩票”或“洗牌”。先建立一个包含所有候选数的数组,每次随机抽取一个位置,将该位置的元素放入结果集,并将该位置替换为末尾元素,同时将可选池的大小减一。这种方法时间复杂度低,且不产生重复风险。
- 操作对象:
index数组作为备选池,result数组存储结果。 - 参数说明:
site代表当前可选池的有效上限。
int[] index = new int[15];
// 初始化备选池 0-14
for (int i = 0; i < 15; i++)
index[i] = i;
Random r = new Random();
int[] result = new int[10];
int site = 15;
int id;
// 只需循环10次
for (int j = 0; j < 10; j++)
{
// 在当前可选范围内随机选一个索引
id = r.Next(0, site);
result[j] = index[id];
// 用最后一个元素填补当前位置,移除已选项
index[id] = index[site - 1];
// 缩小可选池
site--;
}
第3步:集合去重法
利用字典结构的唯一性键值特性(如 HashSet`1 或旧版的 Hashtable)。将生成的随机数作为Key加入集合,直到集合大小达到目标数量。由于Key不可重复,因此自然保证了随机数的唯一性。
- 注意:原版代码使用了
Hashtable且校验ContainsValue,这在现代 .NET 中效率较低(应校验 Key)。推荐使用HashSet<int>。
// 推荐写法:使用 HashSet<int>
HashSet<int>hs = new HashSet<int>();
Random rm = new Random();
int targetCount = 10;
while (hs.Count < targetCount) {
int val = rm.Next(1, 100); // 指定范围
hs.Add(val); // 如果已存在则返回false,不会增加Count
}
// 转换回数组或其他形式
int[] results = hs.ToArray();
第4步:LINQ 简化方案
如果性能不是极端敏感的场景,可以使用 LINQ 进行区间映射和去重,代码最为简洁,但需注意大数据量时的内存开销。
using System.Linq;
// 假设范围是 1 到 100,取 10 个
var random = new Random();
var range = Enumerable.Range(1, 100);
var result = range.OrderBy(x => random.Next()).Take(10).ToArray();
完成判断与总结
以上即为 C# 生成不重复随机数的详细内容。对于小规模数据,简单的循环查重足够适用;追求性能时应选用数组置换法(Fisher-Yates Shuffle 的变体);而在编写脚本或快速原型时,LINQ 方案能极大提升开发效率。更多关于 C# 算法优化的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













