本文通过一个简单的例子,说明将递归函数改写成非递归的基本步骤,目前只完成了一小部分
待续我们的目标是,不研究递归算法本身,即无论算法好坏快慢,也不需要看懂算法本身,给出转换为非递归的通用方式。目前我只做了第一步,将递归函数转化为最原始的非递归版本,下一步将改写成不需要goto语句的版本,使它看上去更自然,最后,试图找到算法和不需要堆栈模拟版本算法的联系,并且直观阐述什么样的递归算法可以转化为不需要递归(指不需要额外堆栈)的算法。从一个经典的程序开始using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication1
{
    class Program
    {
        public static int FibonacciRecursively(int n)
        {
            if (n < 2) return n;
            int t1 = 0;
            t1 = FibonacciRecursively(n - 1);
            return t1 + FibonacciRecursively(n - 2);
        }        static void Main(string[] args)
        {
            Console.WriteLine(FibonacciRecursively(10));
        }
    }
}这个程序是计算Fibonacci数列的程序,从老赵的blog拿来的,稍作改动,引入一个叫t1的临时变量,因为这样改写起来更容易。我们知道递归的本质就是函数调用——而且是自身调用自身,函数调用实际上系统使用了堆栈,为此,将递归函数转换为非递归函数的机械办法就是模拟堆栈。堆栈保存的是函数的返回地址和局部变量。下面是模拟堆栈版本:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication1
{
    class Program
    {
        public static int FibonacciRecursively(int n)
        {
            Stack<Tuple<int, int, int>> stack = new Stack<Tuple<int, int, int>>(); // addr, n, t1
            int result = 0;
            int t1 = 0;
        begincall:
            if (n < 2)
            {
                result = n;
                goto endcall;
            }
            stack.Push(new Tuple<int, int, int>(1, n, t1));
            n = n - 1;
            t1 = 0;
            goto begincall;
        returncall1:
            t1 = result;
            stack.Push(new Tuple<int, int, int>(2, n, t1));
            n = n - 2;
            t1 = 0;
            goto begincall;
        returncall2:
            result = t1 + result;
            goto endcall;
        endcall:
            if (stack.Count == 0) return result;
            Tuple<int, int, int> context = stack.Pop();
            n = context.Item2;
            t1 = context.Item3;
            if (context.Item1 == 1)
                goto returncall1;
            else
                goto returncall2;
        }        static void Main(string[] args)
        {
            Console.WriteLine(FibonacciRecursively(10));
        }
    }
}我们将函数调用转换为保存现场到堆栈,返回函数起始位置,执行函数,如果函数返回,我们就清堆栈,恢复之前保存的现场,然后再返回调用位置。
如果堆栈为空,说明已经是最外层的函数了,就直接return。先写这么多。

解决方案 »

  1.   

    本帖最后由 caozhy 于 2012-12-15 06:02:01 编辑
      

  2.   

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;namespace ConsoleApplication1
    {
        public class TreeNode
        {
            public TreeNode(int value, TreeNode left, TreeNode right)
            {
                this.Value = value;
                if (left != null)
                    left.Parent = this;
                this.Left = left;
                if (right != null)
                    right.Parent = this;
                this.Right = right;
            }        public int Value { get; private set; }        public TreeNode Left { get; private set; }        public TreeNode Right { get; private set; }        public TreeNode Parent { get; private set; }    }    class Program
        {
            public static void PreOrderTraversal(TreeNode root)
            {
                if (root == null) return;            Console.WriteLine(root.Value);
                PreOrderTraversal(root.Left);
                PreOrderTraversal(root.Right);
            }        public static void PreOrderTraversal1(TreeNode root)
            {
                TreeNode current = root;
                while (current != null)
                {
                    Console.WriteLine(current.Value);
                    if (current.Left != null)
                    {
                        current = current.Left;
                        continue;
                    }
                    if (current.Right != null)
                    {
                        current = current.Right;
                        continue;
                    }
                    TreeNode parent = current.Parent;
                    while (parent.Right == current || parent.Right == null)
                    {
                        current = current.Parent;
                        parent = current.Parent;
                        if (parent == null) break;
                    }
                    if (current.Parent != null) current = current.Parent.Right; else break;
                }
            }        public static void PreOrderTraversal2(TreeNode root)
            {
                if (root == null)
                {
                    return;
                }
                else
                {
                    Console.WriteLine(root.Value);
                    if (root.Left != null)
                    {
                        root = root.Left;
                    }
                    else
                    {
                        if (root.Right != null)
                        {
                            root = root.Right;
                        }
                        else
                        {
                            TreeNode parent = root.Parent;
                            while (parent.Right == root || parent.Right == null)
                            {
                                root = root.Parent;
                                parent = root.Parent;
                                if (parent == null) break;
                            }
                            if (root.Parent != null) root = root.Parent.Right; else return;
                        }
                    }
                    PreOrderTraversal2(root);
                }
            }        static void Main(string[] args)
            {
                var tree = 
                    new TreeNode(1,
                        new TreeNode(2,
                            new TreeNode(3,
                                new TreeNode(4, null, null), 
                                new TreeNode(5, null, null)),
                            new TreeNode(6,
                                new TreeNode(7, null, null),
                                new TreeNode(8, null, null))),
                        new TreeNode(9,
                            new TreeNode(10,
                                new TreeNode(11, null, null),
                                new TreeNode(12, null, new TreeNode(13, null, null))),
                            new TreeNode(14,
                                new TreeNode(15, null, null),
                                new TreeNode(16, null, null))));
                PreOrderTraversal2(tree);
                    
            }
        }
    }
      

  3.   

    PreOrderTraversal2
    这方法可以在好好写写。
    太有层次感了。