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

获取数组未使用随机索引时触发Maximum call stack size exceeded错误

问题原因分析

你的代码触发“Maximum call stack size exceeded”错误,核心问题有两个:

  • 递归调用未返回有效结果:当生成的索引已被使用时,你递归调用getRandomIndex()但没有将递归得到的正确结果返回给上层调用。这会导致上层函数依然返回最初生成的重复索引,且随着已使用索引占比越来越高,递归次数会急剧增加,最终撑爆调用栈。
  • 缺少边界终止条件:当usedIndexes长度等于数组长度时(所有索引已被耗尽),函数会无限递归寻找不存在的未使用索引,直接触发栈溢出。

另外,你的随机索引生成代码Math.floor(Math.random() * (arr.length - 0)) + 0可简化为Math.floor(Math.random() * arr.length),效果完全一致。

修复方案一:修正递归逻辑
const arr = [81, 33, 45, 22, 97, 19, 60];
const usedIndexes = [];

function getRandomIndex() {
  // 提前判断是否所有索引已被使用,避免无限递归
  if (usedIndexes.length === arr.length) {
    return -1; // 可根据需求改为抛出错误或其他处理
  }
  
  const rndIdx = Math.floor(Math.random() * arr.length);
  
  if (usedIndexes.includes(rndIdx)) {
    // 递归调用时必须返回结果
    return getRandomIndex();
  } else {
    usedIndexes.push(rndIdx);
    return rndIdx;
  }
}

for(let i = 0; i < arr.length; i++) {
  console.log(getRandomIndex());
}
修复方案二:使用洗牌算法(更高效)

递归的“拒绝采样”方式在数组较大时效率极低,更优方案是采用Fisher-Yates洗牌算法直接打乱索引序列,无需重复检测和递归:

const arr = [81, 33, 45, 22, 97, 19, 60];

// 生成初始索引数组
const indexes = arr.map((_, idx) => idx);
// Fisher-Yates洗牌打乱顺序
for (let i = indexes.length - 1; i > 0; i--) {
  const j = Math.floor(Math.random() * (i + 1));
  [indexes[i], indexes[j]] = [indexes[j], indexes[i]];
}

// 依次取出打乱后的索引,即随机不重复的结果
for (const idx of indexes) {
  console.log(idx);
}

该方案时间复杂度为O(n),彻底避免栈溢出问题,同时效率远高于递归方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 03:20:43