Javascript 对于大型数组,是否有更好的方法可以在不超过最大调用堆栈的情况下递归执行shuffle方法?

Javascript 对于大型数组,是否有更好的方法可以在不超过最大调用堆栈的情况下递归执行shuffle方法?,javascript,arrays,algorithm,shuffle,Javascript,Arrays,Algorithm,Shuffle,我试图编写一个递归函数,对数组进行随机/洗牌 我编写的函数使用Fisher-Yates shuffle方法,该方法在小数组上运行良好,但在包含5000个元素的预期数组上给出了“最大调用堆栈超出错误” 我想知道是否有人能帮我修复这个方法,使它仍然在更大的数组上递归工作 以下是函数: shufflearlay=(数组,currentIndex=0)=>{ if(currentIndex>=array.length){ 返回数组; } 让randomIndex=Math.floor(Math.ran

我试图编写一个递归函数,对数组进行随机/洗牌

我编写的函数使用Fisher-Yates shuffle方法,该方法在小数组上运行良好,但在包含5000个元素的预期数组上给出了“最大调用堆栈超出错误”

我想知道是否有人能帮我修复这个方法,使它仍然在更大的数组上递归工作

以下是函数:

shufflearlay=(数组,currentIndex=0)=>{
if(currentIndex>=array.length){
返回数组;
}
让randomIndex=Math.floor(Math.random()*currentIndex);
让tempValue=数组[currentIndex];
数组[currentIndex]=数组[randomIndex];
数组[randomIndex]=临时值;
设newIndex=currentIndex+=1;
返回此.shufflearlay(数组,newIndex);
}
log(shufflearlay([1,2,3,4,5,6]);
//返回类似[3,4,6,1,2,5]的随机数组
log(shufflearlay([…数组(5000).keys()]);
//一个包含5000个元素的示例数组返回错误:uncaughtrangeerror:超过最大调用堆栈大小

for (let i = 0; i < n; i++) {
    // do something with i
}
任何这样的循环:

for (let i = 0; i < n; i++) {
    // do something with i
}

你可以用蹦床

//数据蹦床a在哪里
//结果::a->蹦床a
const Result=Result=>({bounce:false,Result});
//弹跳::(a->蹦床b)->a->蹦床b
常量Bounce=func=>(…args)=>({Bounce:true,func,args});
//蹦床:蹦床a->a
康斯特蹦床=t=>{
而(t.bounce)t=t.func(…t.args);
返回t.result;
};
//_shufflearlay::([a],Int)->蹦床[a]
const\u shufflearlay=反弹((数组,当前索引)=>{
if(currentIndex>=array.length)返回结果(array);
让randomIndex=Math.floor(Math.random()*currentIndex);
[array[currentIndex],array[randomIndex]=[array[randomIndex],array[currentIndex]];
return Shuffarray(数组,currentIndex+1);
});
//shuffleArray::[a]->[a]
常量shufflearlay=数组=>蹦床(_shufflearlay(数组,0));
//在没有堆栈溢出的情况下洗牌100k个数字。

log(shufflearlay([…数组(1e5.keys()]))您可以随时使用蹦床

//数据蹦床a在哪里
//结果::a->蹦床a
const Result=Result=>({bounce:false,Result});
//弹跳::(a->蹦床b)->a->蹦床b
常量Bounce=func=>(…args)=>({Bounce:true,func,args});
//蹦床:蹦床a->a
康斯特蹦床=t=>{
而(t.bounce)t=t.func(…t.args);
返回t.result;
};
//_shufflearlay::([a],Int)->蹦床[a]
const\u shufflearlay=反弹((数组,当前索引)=>{
if(currentIndex>=array.length)返回结果(array);
让randomIndex=Math.floor(Math.random()*currentIndex);
[array[currentIndex],array[randomIndex]=[array[randomIndex],array[currentIndex]];
return Shuffarray(数组,currentIndex+1);
});
//shuffleArray::[a]->[a]
常量shufflearlay=数组=>蹦床(_shufflearlay(数组,0));
//在没有堆栈溢出的情况下洗牌100k个数字。

log(shufflearlay([…数组(1e5.keys()]))不太可能,因为大多数JavaScript引擎没有正确的尾部调用。除非你想把它变成一个奇怪的东西,每次调用都会洗牌一半的输入,然后是另一半?(这将最终成为“Fisher–Yates,但我们假装它是递归的”。)这种洗牌的实现也是错误的:它从不将元素保留在同一个位置。这是不可能的,因为大多数JavaScript引擎没有适当的尾部调用。除非你想把它变成一个奇怪的东西,每次调用都会洗牌一半的输入,然后是另一半?(这将最终成为“Fisher–Yates,但我们假装它是递归的”。)这种洗牌的实现也是错误的:它从不将元素保持在同一个位置。这如何回答OP的问题?@AaditMShah:以
for(让i=0;i
留给读者作为练习。啊,我知道现在发生了什么。调用堆栈的最大大小为O(log n)。它确实可以防止相当大的阵列的堆栈溢出。您需要具有大于可用空间量的阵列才能导致堆栈溢出。巧妙的解决方案+1这是如何回答OP的问题的?@AaditMShah:for(让i=0;i
的形式实现洗牌,留给读者作为练习。啊,我知道现在发生了什么。调用堆栈的最大大小为O(log n)。它确实可以防止相当大的阵列的堆栈溢出。您需要具有大于可用空间量的阵列才能导致堆栈溢出。巧妙的解决方案+1.