如何快速生成包含唯一随机整数的Stack?
优化随机唯一整数Stack生成的方案
你的代码核心问题在于每次用stack.Contains(h)做重复检查——Stack的Contains是线性遍历查找(时间复杂度O(n)),当需要的随机数数量count接近可选范围(upper - lower + 1)时,会频繁生成重复值,导致循环次数爆炸,速度骤降。下面给你两种针对性的优化方案:
方案一:用HashSet辅助查重(适合count远小于可选范围的场景)
用HashSet来记录已生成的随机数,它的Contains操作是O(1)的哈希查找,比Stack的线性查找快得多。代码示例:
public static Stack<int> RandomNumbersGenerator(int lower, int upper, int count) { // 先做边界检查,避免无效输入 if (lower > upper) throw new ArgumentException("lower不能大于upper"); int totalAvailable = upper - lower + 1; if (count < 0 || count > totalAvailable) throw new ArgumentException("count超出有效范围"); Stack<int> stack = new Stack<int>(); HashSet<int> usedNumbers = new HashSet<int>(); Random rnd = new Random(); while (count > 0) { int num = rnd.Next(lower, upper + 1); if (usedNumbers.Add(num)) // Add返回false表示已存在,true则是新数 { stack.Push(num); count--; } } return stack; }
HashSet的Add方法本身就会判断是否存在,返回布尔值,这样可以避免先Contains再Add的两次操作,进一步提升效率。
方案二:洗牌法(适合count接近可选范围的场景)
当需要的随机数数量接近可选范围的总数时,反复生成随机数试错的效率极低,这时候直接生成所有可选数的列表,打乱顺序后取前count个,再转成Stack:
public static Stack<int> RandomNumbersGenerator(int lower, int upper, int count) { // 边界检查 if (lower > upper) throw new ArgumentException("lower不能大于upper"); int totalAvailable = upper - lower + 1; if (count < 0 || count > totalAvailable) throw new ArgumentException("count超出有效范围"); // 生成所有可选数的列表 List<int> numbers = Enumerable.Range(lower, totalAvailable).ToList(); Random rnd = new Random(); // Fisher-Yates洗牌算法,原地打乱列表,时间复杂度O(m) for (int i = numbers.Count - 1; i > 0; i--) { int j = rnd.Next(i + 1); (numbers[i], numbers[j]) = (numbers[j], numbers[i]); } // 取前count个元素转成Stack return new Stack<int>(numbers.Take(count)); }
Fisher-Yates洗牌是高效的原地打乱算法,比用OrderBy(_ => rnd.Next())的方式更优(后者会额外创建大量中间对象,效率更低)。
选择建议
- 如果count远小于可选范围(比如count ≤ 总数量的1/10),用方案一,内存占用更小;
- 如果count接近总数量(比如count ≥ 总数量的1/2),用方案二,避免大量无效的随机数生成;
- 可以在方法里加判断逻辑,自动切换两种方案,让方法适配所有场景。
内容的提问来源于stack exchange,提问作者MoonMan
相关产品推荐
相关产品推荐

