递归——CPS(二)

给出一个计算树深度的函数:

function treeDepth(curtree)
{
    if(curtree == null)
        return 0;
    else
    {
        var leftDepth = treeDepth(curtree.left);
        var rightDepth = treeDepth(curtree.right);
        return 1 + Math.max(leftDepth, rightDepth);
    }
}

现在要用CPS风格重写这个函数。

避免函数的返回值,而是将返回值传入continuation。记住,continuation就是这个函数完成后需要做的事情。于是写出如下代码

function treeDepth(curtree, afterDepth)
{
    if(curtree == null)
        afterDepth(0);
    else
    {
        // undone: var leftDepth = treeDepth(curtree.left);
        // undone: var rightDepth = treeDepth(curtree.right);
        afterDepth(1 + Math.max(leftDepth, rightDepth));
    }
}

这里假定加法和求最大值不写成CPS风格,以降低难度。

现在需要组合递归调用。考虑第二个递归调用,嗯,它的continuation是什么?也就是,当右子树的深度确定好了之后需要做哪些事情?两件事,第一,左右子树的深度的最大值需要被计算出来然后加1;第二,需要保证,做完后将会调用continuation。于是,写一个闭包来完成这两件事情。

function treeDepth(curtree, afterDepth)
{
    if(curtree == null)
        afterDepth(0);
    else
    {
        function afterRight(rightDepth)
        {
            afterDepth(1+Math.max(leftDepth, rightDepth));
        }
        // undone: var leftDepth = treeDepth(curtree.left);
        treeDepth(curtree.right, afterRight);
    }
}

嗯,有进步了。那么,当左子树的深度确定后需要做什么?将左深度传给continuation,这个continuation在右树上面递归来决定右树深度,然后决定两者最大值,然后调用 afterDepth 这个continuation。

function treeDepth(curtree, afterDepth)
{
    if(curtree == null)
        afterDepth(0);
    else
    {
        function afterLeft(leftDepth)
        {
            function afterRight(rightDepth)
            {
                afterDepth(1+Math.max(leftDepth, rightDepth));
            }
            treeDepth(curtree.right, afterRight);
        }
        treeDepth(curtree.left, afterLeft);
    }
}

 原文:https://blogs.msdn.microsoft.com/ericlippert/2005/08/11/recursion-part-five-more-on-cps/

posted @ 2016-07-01 20:45  gaoshoufenmu  阅读(241)  评论(0编辑  收藏  举报