Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 快速排序的尾部调用优化_Algorithm_Sorting - Fatal编程技术网

Algorithm 快速排序的尾部调用优化

Algorithm 快速排序的尾部调用优化,algorithm,sorting,Algorithm,Sorting,我刚刚接触到TCO,我理解了它如何重用单个堆栈帧的概念,而不是每次方法调用自己时创建一个新的堆栈帧。我直观地想将此结构与while循环进行比较,因为循环将持续对一组变量执行操作,直到不满足条件为止 然而,鉴于TCO只使用一个堆栈帧,似乎不可能执行诸如快速排序之类的排序算法,一旦递归方法“展开”并在达到基本情况后备份调用堆栈,就需要使用TCO作为堆栈帧的引用。如果不参考调用该方法的次数,它如何知道要执行哪个后续操作以及要执行多少次 如果每次调用的方法体都是相同的,我想它可以只保留一个对方法被调用次

我刚刚接触到TCO,我理解了它如何重用单个堆栈帧的概念,而不是每次方法调用自己时创建一个新的堆栈帧。我直观地想将此结构与
while
循环进行比较,因为循环将持续对一组变量执行操作,直到不满足条件为止

然而,鉴于TCO只使用一个堆栈帧,似乎不可能执行诸如快速排序之类的排序算法,一旦递归方法“展开”并在达到基本情况后备份调用堆栈,就需要使用TCO作为堆栈帧的引用。如果不参考调用该方法的次数,它如何知道要执行哪个后续操作以及要执行多少次

如果每次调用的方法体都是相同的,我想它可以只保留一个对方法被调用次数的引用,然后在方法体中保留一个指针,指示从何处开始执行,但这只是一个猜测


感谢您的帮助。

TCO可以在递归调用处于最终位置时执行。快速排序需要两个递归调用,因此它们显然不能同时处于该位置——但其中一个可以,这样尾部调用可以转换为
循环:

原件(伪代码):

快速排序(i,j){

返回当递归调用位于最终位置时是否可以执行jTCO。快速排序需要两个递归调用,因此它们显然不能都位于该位置,但其中一个可以,这样尾部调用可以转换为
,而
循环:

原件(伪代码):

快速排序(i,j){

return if j您能更深入地了解一下您所说的“最终位置”吗?在TCO示例中,您在对quicksort的递归调用之后设置了
i
。什么使调用成为最终调用?@louism2:
i
在消除第二次递归调用的版本中设置,将循环限制设置为(现在已消除)最后一次递归调用。(向上回答正确,向下回答注释过滤器。)递归函数调用的顺序很重要。如果确保尾部调用用于较大的分区,则可以保证最大堆栈深度不超过
log2(n)
即使分区选择不当。@louism2:i=k+1
赋值替换了一个最终的递归调用,这是一个重要条件。当您(或编译器)执行TCO时,您必须设置参数,以便在while循环的顶部看起来就像调用了函数一样。在这种情况下,第二个参数不会更改,但如果更改了(例如,对于其他可实现TCO的递归算法),您也需要对j进行赋值。您能更深入地了解一下您的意思吗“最终位置?”在TCO示例中,您在对quicksort的递归调用后设置了
i
。什么使调用成为最终调用?@louism2:
i
在消除第二次递归调用的版本中设置,将循环限制设置为(现在已消除)最终递归调用的参数。(向上回答正确,向下回答注释过滤器。)递归函数调用的顺序很重要。如果您确保尾部调用用于较大的分区,则可以保证最大堆栈深度不超过
log2(n)
即使分区选择不当。@louism2:i=k+1
赋值替换了一个最终的递归调用,这是一个重要条件。当您(或编译器)执行TCO时,您必须设置参数,以便在while循环的顶部,它看起来就像调用了函数一样。在这种情况下,第二个参数不会更改,但如果更改了(例如,对于其他可实现TCO的递归算法),您也需要为j赋值。
quicksort(i, j) {
    return if j <= i
    k = getPivot(i, j)
    partition(i, j, k)
    quicksort(i, k-1)    <--- This recursive call can't be changed
    quicksort(k+1, j)    <--- This recursive call is amenable to TCO
}
quicksort(i, j) {
    while (j > i) {
        k = getPivot(i, j)
        partition(i, j, k)
        quicksort(i, k-1)    <--- This recursive call is unchanged
        i = k+1
    }
}