首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将递归算法转换为尾递归算法?

如何将递归算法转换为尾递归算法?
EN

Stack Overflow用户
提问于 2013-05-24 01:53:38
回答 2查看 461关注 0票数 1

作为对合并排序的第一次尝试,我生成了以下代码,它适用于字符串,因为它们比列表更容易处理。

代码语言:javascript
复制
class Program
{
    static int iterations = 0;
    static void Main(string[] args)
    {            
        string test = "zvutsrqponmlihgfedcba";
        test = MergeSort(test);
        // test is sorted after 41 iterations
    }

    static string MergeSort(string input)
    {
        iterations++;
        if (input.Length < 2)
            return input;
        int pivot = 0;
        foreach (char c in input)
            pivot += c;
        pivot /= input.Length;
        string left = "";
        string right = "";
        foreach (char c in input)            
            if (c <= (char)pivot)
                left += c;
            else
                right += c;            
        return string.Concat(new string[] { MergeSort(left), MergeSort(right) });
    }
}

在Wikipedia上阅读有关可能的优化时,我发现了以下提示:“确保最多使用O(log N)空间,首先递归到数组的较小一半,然后使用尾部调用递归到另一半。”但老实说,我不知道如何将它应用到我的案例中。当我们学习递归和阶乘时,我对IT课上的尾部调用有一些模糊的记忆,但我真的不能理解如何将维基百科的建议应用到我的代码片段中。

任何帮助都将不胜感激。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-05-24 02:09:16

这个问题有很多问题,首先是你实现了一个非常慢的QuickSort版本,但是问了一个关于MergeSort的问题。MergeSort通常不是作为尾递归算法实现的。

让我代表你问一个更好的问题:

如何将递归算法转换为尾递归算法?

让我勾勒出一个更简单的尾递归转换,然后您可以研究如何将其应用于您的排序,如果您认为这样做是一个好主意的话。

假设您有以下递归算法:

代码语言:javascript
复制
static int Count(Tree tree)
{
    if (tree.IsEmpty) 
        return 0;
    return 1 + Count(tree.Left) + Count(tree.Right);
}

让我们使用下面这个有点奇怪的转换将其分解为更多的步骤:

代码语言:javascript
复制
static int Count(Tree tree)
{
    int total = 0;
    Tree current = tree;
    if (current.IsEmpty) 
        return 0;
    total += 1;
    int countLeft = Count(current.Left);
    total += countLeft;
    current = current.Right;
    int countRight = Count(current);
    total += countRight;
    return total;
}

请注意,这与前面的程序完全相同,只是更详细。当然,您不会以如此冗长的方式编写程序,但它将帮助我们使其尾部递归。

尾递归的目的是将递归调用转换为goto。我们可以这样做:

代码语言:javascript
复制
static int Count(Tree tree)
{
    int total = 0;
    Tree current = tree;

 Restart:

    if (current.IsEmpty) 
        return total;
    int countLeft = Count(current.Left);
    total += 1;
    total += countLeft;
    current = current.Right;
    goto Restart;
}

看到我们在那里做了什么了吗?我们不是递归,而是将当前引用重置为本应递归的对象,并返回到开始处,同时保持累加器的状态。

现在,如何对QuickSort算法做同样的事情很清楚了吗?

票数 8
EN

Stack Overflow用户

发布于 2013-05-24 02:01:32

这看起来像是QuickSort的一个不太理想的变体,而不是MergeSort。您缺少此部件的C#等效项:

代码语言:javascript
复制
function merge(left, right)
    var list result
    while length(left) > 0 or length(right) > 0
        if length(left) > 0 and length(right) > 0
            if first(left) <= first(right)
                append first(left) to result
                left = rest(left)
            else
                append first(right) to result
                right = rest(right)
        else if length(left) > 0
            append first(left) to result
            left = rest(left)
        else if length(right) > 0
            append first(right) to result
            right = rest(right)
    end while
    return result
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16720711

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档