You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

生成1-99无重复随机数时代码出现栈溢出问题求助

问题原因分析

这个问题我太熟悉了——你的代码在acum集合接近装满的时候会陷入近乎无限的循环,最终导致栈溢出或者程序卡死,核心问题有两个:

  1. List.Contains()的低效性:如果acum是List<int>,Contains()方法会遍历整个列表查找元素,当列表元素很多时,每次检查的耗时会越来越长。
  2. 高概率重复的循环陷阱:Unity的Random.Range(int min, int max)是左闭右开逻辑,所以你写的Random.Range(1,99)实际生成的是1到98的数字(共98个)。当acum里的元素接近98个时,每次随机到已存在数字的概率会极高——比如已有97个元素时,命中重复值的概率是97/98,循环会一直跑,直到“撞大运”抽到唯一剩下的数字,这个过程会占用大量CPU资源,最终引发栈溢出或程序无响应。
解决方案

推荐三种方案,按优先级从高到低排列:

方案1:洗牌法(最优解)

直接先生成所有可能的数字,打乱顺序后依次取用,从根本上避免重复检查的问题,效率最高,适合需要生成全部或大部分不重复数字的场景。

// 初始化阶段:生成所有候选数字并洗牌
List<int> numberPool = Enumerable.Range(1, 98).ToList(); // 生成1到98的数字
System.Random rng = new System.Random();
int poolCount = numberPool.Count;

// Fisher-Yates 洗牌算法,高效打乱列表
while (poolCount > 1)
{
    poolCount--;
    int randomIndex = rng.Next(poolCount + 1);
    // 交换元素完成洗牌
    int temp = numberPool[randomIndex];
    numberPool[randomIndex] = numberPool[poolCount];
    numberPool[poolCount] = temp;
}

// 每次需要取新数字时
if (numberPool.Count > 0)
{
    int newNumb = numberPool[0];
    numberPool.RemoveAt(0); // 取出后从池中移除,彻底避免重复
    acum.Add(newNumb); // 如果你需要保留到acum集合里
}
else
{
    // 处理没有可用数字的情况,比如提示或返回默认值
    Debug.Log("没有更多不重复的数字了!");
}

方案2:优化原有循环+使用HashSet

如果你不想用洗牌法,可以对原有代码做两个关键优化:

  • 把acum从List<int>改成HashSet<int>,因为HashSet.Contains()是O(1)时间复杂度,比List的O(n)快得多。
  • 添加最大尝试次数,防止无限循环。
// 把acum定义为HashSet,而不是List
HashSet<int> acum = new HashSet<int>();

// 生成新数字的逻辑
int newNumb = Random.Range(1, 99);
const int maxAttempts = 1000; // 设置一个合理的最大尝试次数
int attempts = 0;

while (acum.Contains(newNumb) && attempts < maxAttempts)
{
    newNumb = Random.Range(1, 99);
    attempts++;
}

if (attempts >= maxAttempts)
{
    // 没有可用数字了,抛出异常或做相应处理
    throw new InvalidOperationException("已没有可用的不重复数字!");
}

acum.Add(newNumb);

方案3:仅添加最大尝试次数(不推荐)

如果暂时不想改集合类型,至少要给循环加一个最大尝试次数的限制,避免无限循环:

int newNumb= Random.Range(1, 99);
const int maxAttempts = 1000;
int attempts = 0;

if(acum.Count > 0) 
{
    while (acum.Contains(newNumb) && attempts < maxAttempts) 
    {
        newNumb= Random.Range(1, 99);
        attempts++;
    }
    
    if (attempts >= maxAttempts)
    {
        Debug.LogError("无法生成不重复数字,已达最大尝试次数");
        return; // 或做其他处理
    }
}

acum.Add(newNumb);

注意:这个方案在acum元素较多时仍然会有性能问题,只是避免了无限循环。

内容的提问来源于stack exchange,提问作者Nogerad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:38:24