堆的算法排列 JavaScript 和递归的堆栈?

Posted

技术标签:

【中文标题】堆的算法排列 JavaScript 和递归的堆栈?【英文标题】:Heap's Algorithm Permutation JavaScript and Recursions' Stack? 【发布时间】:2017-01-17 14:34:20 【问题描述】:

我有一个任务是根据堆的算法排列来计算重复的字符串。我要做的第一件事是输出交换的字符串,我从jake's answer 找到了这段代码,有人可以帮我理解这段代码中的递归吗一个循环?该函数的输出是交换后的字符串。

function permAlone(string) 

var arr = string.split(''),   // Turns the input string into a letter array.
          permutations = []; // results

function swap(a, b)   
debugger; // This function will simply swap positions a and b inside the input array.
var tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;


function gen(n)    
  debugger;
  if (n === 1)   
  var x =arr.join('');
  permutations.push(x);  
   else 
  for (var i = 0; i != n; i++)  // how does this loop executes within the call stack?  
    gen(n - 1);
    debugger;
    swap(n % 2 ? 0 : i, n - 1); // i don't understand this part. i understand the swap function, but I don't get how indexes are swapped here
     
 

 gen(arr.length);
 return permutations;

permAlone('xyz'); // output -> ["xyz","yxz","zxy","xzy","yzx","zyx"]

我一直在调试器上进行试验,但仍然无法了解发生了什么。

【问题讨论】:

请正确缩进函数中的代码。阅读缩进的代码要容易得多。我尝试自己编辑您的代码,但它不会将空格计入最少 6 个字符的编辑中。 【参考方案1】:

我不知道你的意思是什么

在循环中理解此代码中的递归

如果您想以循环形式而不是递归形式查看算法,您可以在 wikipedia page here 中的伪代码中并排查看它们。

关于代码中的问题:

这个循环如何在调用栈中执行?

引用调用堆栈是对的,这是关于递归的一般问题。如果您不了解递归如何与堆栈一起工作,您可以参考this really nice and simple video,它演示了在 java 中使用阶乘计算进行递归调用(大约从 4:00 开始)。

您看到的行与递归函数中的任何其他行没有什么不同。我们首先定义 i 并将值 0 分配给它。我们继续检查它是否满足for循环的条件。如果是,我们进入循环并执行循环内的第一行,即递归调用。在递归调用内部,我们有一个新的堆栈帧,它不知道我们在执行递归调用之前定义的 i 变量,因为它是一个局部变量。因此,当我们在新调用中进入循环时,我们定义了一个新变量 i,首先将其分配为 0,并随着循环在此堆栈帧/调用实例中重复而递增。当这个调用完成时,我们删除堆栈帧并恢复到上一个​​堆栈帧(我们开始的那个),其中 i=0,我们继续下一行。 所有调用都可以访问 arr 和 permutations 变量,因为该函数与变量定义在同一范围内(在函数 permAlone 中),因此在每次调用中 - 无论我们在什么堆栈框架中,对这些变量所做的更改都是制作相同的实例。这就是为什么对排列所做的每次推送都会添加到现有结果中,并且会在函数最后返回变量时出现。

我不明白这部分。我了解交换功能,但我不明白这里的索引是如何交换的

这里没有交换索引。它只是调用具有正确索引的交换函数。

swap(n % 2 ? 0 : i, n - 1);

只是

swap(a, b);

a = n% 2 ? 0 : i;
b = n - 1;

如果a 部分让您感到困惑,那么这是the ternary operator for conditional value 的用法。也就是说,它是用于形成表达式的符号,该表达式根据情况进行不同的评估。使用是由

<<i>boolean epression</i>> ? <<i>value-if-true</i>> : <<i>value-if-false</i>>

要评估上述内容,首先要评估布尔表达式>。如果它的值是true,那么整个表达式被评估为value-if-true>。否则,整个表达式被评估为 value-if-false>。

在代码本身中,对于an % 2 是布尔表达式——js 将n 除以2 并取余数。余数为10。 Node.js 分别将它们隐式转换为 truefalse。所以如果n 是奇数,我们会得到 ​​p>

a = 0

如果是这样的话,我们会得到

a = i

按照算法的要求。

【讨论】:

以上是关于堆的算法排列 JavaScript 和递归的堆栈?的主要内容,如果未能解决你的问题,请参考以下文章

堆的排列算法

使用 Ruby/Erlang 迭代生成排列,无需递归或堆栈

每天进步一点点之堆栈思想

在 Heap 的递归算法中返回一个数组

算法——全排列

Swift 中的值与引用类型,以 Wikipedia 实现堆的排列算法为例