递归在这种情况下如何工作?

时间:2011-06-21 21:54:33

标签: javascript algorithm recursion quicksort

var arr = [7,3,28,8,9,13,1500,45];

function qsort(a) {
    if (a.length == 0) return [];

    var left = [], right = [], pivot = a[0];

    for (var i = 1; i < a.length; i++) {
        a[i] < pivot ? left.push(a[i]) : right.push(a[i]);
    }

    return qsort(left).concat(pivot, qsort(right));
}

alert(qsort(arr));

此例程使用Quicksort算法对数组进行排序。 问题是基本案例if (a.length == 0) return [];将如何真实地阻止递归?

7 个答案:

答案 0 :(得分:6)

if (a.length == 0) return [];

当长度为0时,它会停止。

答案 1 :(得分:6)

传递给递归调用的数组总是至少比传递给函数的数组小一个,因为它不包含pivot元素。因此,您最终会遇到a.length == 0的基本情况,并返回而不会递归。

答案 2 :(得分:6)

请记住:

  • pivot是数组
  • 中的第一项
  • left是低于pivot
  • 的项目
  • right是高于pivot
  • 的项目

所以你第一次拥有qsort( [7,3,28,8,9,13,1500,45] )

left=[3]      pivot=7      right=[28,8,9,13,1500,45]

现在,qsort()left数组都会递归调用right

我们只看leftqsort( [3] )

left=[]       pivot=3        right=[]

再次qsort()leftright阵列递归调用{。}}。

再次,我们只看leftqsort( [] )

qsort()的第一件事是什么?

if (a.length == 0) return [];

如果它收到一个空数组(它在这里做了),它只返回一个空数组,暂停该分支上的执行。

因为qsort()的每次调用都会弹出数组中的第一项,所以每次调用qsort()时,它收到的数组都会越来越短,直到空数组被发送到{{1} }。


另一种思考方式:

可能令人困惑的部分是qsort()关闭第一个项目,然后将数组的其余部分分成两部分。

想象一下,如果它没有拆分数组,而只是关闭了第一个项目。

这个函数实际上并没有做任何事情,只是用数组的其余部分递归调用自己。

qsort()

因此,当您调用该函数时,会发生以下情况:

function recursive_test( arr ) {
    if( arr.length === 0 ) { return []; } // empty Array? Just return.

    var first_item = arr.shift();      // first item in the Array (the head)
                            // now "arr" represents the remainder (the tail)

    return recursive_test( arr );  // Just send the "tail" to the same function
                                   //   so the next time through, the Array is 
}                                  //   shorter by 1

在你的函数中发生了同样的事情,除了递归传递“tail”而不是“head”和“tail”之外,你得到一个“head”(var array = [5,2,8,3,6,9,0]; // original Array recursive_test( array ); // the first time it gets the full Array // [5,2,8,3,6,9,0] // but then it pops the first item off, and calls itself with the "tail" of the Array // [2,8,3,6,9,0] // again it calls itself, just with the "tail" // [8,3,6,9,0] // and again, and again, and again... // [3,6,9,0] // [6,9,0] // [9,0] // [0] // [] // The last time it gets an empty Array. // The function sees that it gets an empty Array, and just returns, // halting the recursion )和一个“尾巴”,分为2个阵列(pivotleft)。

尾部的两个部分都被发送到递归调用,弹出它们的头部,分割剩余部分,然后再次执行,直到没有任何东西为止。

答案 3 :(得分:2)

在快速排序中,你采取了一种分裂和征服的方法 - 而不是立即解决整个问题,你将问题分成两半,解决每一半,然后将答案合并在一起。

为了解决问题的每一半,我们只是递归地调用快速排序 - 也就是说,我们将问题再分成两半,直到我们得到一些我们无法进一步划分它的东西......这是由这条线处理的:

if (a.length == 0) return [];

所以现在我们已经将它分成了很多次并解决了所有这些问题,我们可以将它们合并在一起。

这一行:

return qsort(left).concat(pivot, qsort(right));

说“把左子问题和正确的子问题,把它们粘在一起,这就是我的答案”。

这种气泡直到顶部,将所有不同的子阵列粘在一起并生成一个带答案的数组。

这比那复杂一点,但无论如何这都是递归的。

答案 4 :(得分:2)

将此作为单独的答案发布,因为它占用了一点空间。

这是递归调用的表示。我将left更改为lo,将right更改为hi,将pivot更改为piv以便节省空间。

虽然连接可能很难遵循,但它可以很好地显示流程。

                          qsort( [7,3,28,8,9,13,1500,45] )
                                           |
             |-----------------------------v-----------------------------------|
             | lo=[3]                   piv=7           hi=[28,8,9,13,1500,45] |
                 |                                                  |
                 |                                                  |
                 v                                                  v
            qsort( [3] )                             qsort( [28,8,9,13,1500,45] )
                 |                                                  |
   |-------------v------------|       |-----------------------------v--------------------------------------------|
   | lo=[]    piv=3     hi=[] |       | lo=[8,9,13]               piv=28                            hi=[1500,45] |
       |                 |                   |                                                              |
       |                 |                   |                                                              |
       v                 v                   v                                                              v
  qsort( [] )       qsort( [] )       qsort( [8,9,13] )                                           qsort( [1500,45] )
                                             |                                                              |
                                |------------v---------------|                                |-------------v--------------|
                                | lo=[]   piv=8    hi=[9,13] |                                | lo=[45]   piv=1500   hi=[] |
                                    |                  |                                            |                  |
                                    |                  |                                            |                  |
                                    v                  v                                            v                  v
                                qsort( [] )      qsort( [9,13] )                              qsort( [45] )       qsort( [] )
                                                       |                                            |  
                                         |-------------v -----------|                  |------------v-------------|
                                         | lo=[]    piv=9   hi=[13] |                  | lo=[]    piv=45    hi=[] |
                                            |                  |                           |                  |
                                            |                  |                           |                  |
                                            v                  v                           v                  v
                                       qsort( [] )        qsort( [13] )                qsort( [] )         qsort( [] )
                                                               |           
                                                   |-----------v-------------|
                                                   | lo=[]   piv=13    hi=[] |          
                                                       |                 |          
                                                       |                 |    
                                                       v                 v   
                                                  qsort( [] )        qsort( [] ) 

要跟随连接,基本上从根开始,尽可能远地跟随lo,直到你无法深入。

然后回溯记录您通过的最新piv,并按照其hi分支,然后执行您可以执行的所有lo分支。

重复此过程,始终支持lo分支,并在回溯时传递它们时记下piv

这将为您提供完全排序的数组。

答案 5 :(得分:0)

这会导致递归停止

if (a.length == 0) return [];

答案 6 :(得分:0)

这就是if (a.length == 0) return [];行。一旦将空数组传递给函数,递归就会停止。由于每次递归都会将输入数组除以2,因此必然会发生这种情况。

底层示例:

+是连接

["a","b","c"]最终成为

[] + [a] + [] + [b] + [] + [c] + [] b是枢轴,(左)和c(右)都经过另一次快速排序迭代。这会在两者的每一侧添加[],然后将所有三个连接在一起。