美文网首页
二叉树基于栈的递归消除

二叉树基于栈的递归消除

作者: 周末的游戏之旅 | 来源:发表于2019-08-03 10:41 被阅读0次

递归转非递归的原因

递归执行效率低;(有进入、保存、出来、恢复四个操作)
有些运行环境没有递归机制

递归转换的两种方法

  • 直接尾递归
    可转化为直线型:用循环代替递归,例如求阶乘
  • 复杂情况
    采用工作栈消除递归,例如二叉树的遍历

基于栈的递归消除

在大量复杂的情况下,递归的问题无法直接转换成循环,需要采用工作栈消除递归。
将递归中系统隐含的栈=》用户自己操纵的栈(工作栈提供一种控制结构)

递归进层时,需要保留信息 递归进层的三件事如下:

  1. 保存本层参数,返回地址(断点)
  2. 传递参数,分配局部数据空间(给下一层参数赋值)
  3. 控制转移。(转向下一个开始)

递归退层时,需要恢复信息

  1. 恢复上层(恢复返回结果和保存的断点信息)
  2. 传递结果
  3. 转断点执行。

从C++中序遍历二叉树分析递归

void Inorde(BiTree root)
{
    if(root!=null)           //L1断点
        Inorder(root->LChild);
    Visit(root->data);       //L2断点
    Inorder(root->RChild);   //L3断点
}

非递归先序遍历

static void PreOrderNoRecursion(TreeNode<string> tree)
{
    if (tree == null)
        return;
    Stack<TreeNode<string>> stack = new Stack<TreeNode<string>>();
    TreeNode<string> node = tree;

    while (node != null || stack.Any()) //栈不空
    {
        if (node != null)
        {
            stack.Push(node);
            Console.WriteLine(node.data);
            node = node.lchrild;
        }
        else
        {
            var item = stack.Pop();
            node = item.rchrild;
        }
    }
}

非递归中序遍历

二叉树中序遍历的非递归算法的关键:在中序遍历过某结点的整个左子树后,如何找到该结点的根及右子树。

基本思想:

  1. 建立一个栈
  2. 根结点进栈,遍历左子树
  3. 根节点出栈,输出根节点,遍历右子树

下面是我的算法实现,其中的栈是自定义的(顺便复习一下栈),也可以用C#系统提供的栈

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NotRecursion
{
    /// <summary>
    ///链栈的结点
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class StackNode<T>
    {
        public T data;
        public StackNode<T> next;

        public StackNode()
        {
            this.data = default(T);
            this.next = null;
        }

        public StackNode(T data)
        {
            this.data = data;
        }
    }

    /// <summary>
    /// 链栈类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class LinkStack<T>
    {
        StackNode<T> head;

        /// <summary>
        /// 构造
        /// </summary>
        public LinkStack()
        {
            head = new StackNode<T>();
        }

        /// <summary>
        /// 判空
        /// </summary>
        /// <returns></returns>
        public bool IsEmpty()
        {
            return head.next == null;
        }

        /// <summary>
        /// 入栈
        /// </summary>
        /// <param name="data"></param>
        public void Push(T data)
        {
            StackNode<T> node = new StackNode<T>(data);
            //挂载结点
            node.next = head.next;
            head.next = node;
        }

        /// <summary>
        /// 出栈
        /// </summary>
        /// <returns></returns>
        public T Pop()
        {
            if (IsEmpty())
            {
                Console.WriteLine("栈空");
                return default(T);
            }
            //保留首结点
            StackNode<T> node = head.next;
            //悬空首结点
            head.next = head.next.next;
            return node.data;
        }

        /// <summary>
        /// 读栈顶
        /// </summary>
        /// <returns></returns>
        public T Peek()
        {
            return head.next.data;
        }
    }

    /// <summary>
    /// 二叉树结点
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class TreeNode<T>
    {
        public T data;
        public TreeNode<T> lchrild;
        public TreeNode<T> rchrild;

        public TreeNode(T data)
        {
            this.data = data;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            TreeNode<string> A = new TreeNode<string>("a");
            TreeNode<string> B = new TreeNode<string>("b");
            TreeNode<string> C = new TreeNode<string>("c");
            TreeNode<string> D = new TreeNode<string>("d");
            TreeNode<string> E = new TreeNode<string>("e");
            TreeNode<string> F = new TreeNode<string>("f");
            TreeNode<string> G = new TreeNode<string>("g");
            TreeNode<string> H = new TreeNode<string>("h");

            A.lchrild = B;
            B.rchrild = D;
            A.rchrild = C;
            D.lchrild = F;
            D.rchrild = G;
            C.rchrild = E;
            E.rchrild = H;

            PreOrderNoRecursion(A);
        }

        //中序遍历非递归算法
        static void PreOrderNoRecursion(TreeNode<string> tree)
        {
            //创建栈对象
            LinkStack<TreeNode<string>> linkStack = new LinkStack<TreeNode<string>>();
            TreeNode<string> p = tree;


            while (p != null || !linkStack.IsEmpty())
            {
                if (p != null)
                {   //将根节点入栈
                    linkStack.Push(p);
                    //访问其左子树
                    p = p.lchrild;
                }
                else
                {
                    //将根节点出栈
                    TreeNode<string> q = linkStack.Pop();
                    //打印根节点
                    Console.WriteLine(q.data);
                    //访问其右子树
                    p = q.rchrild;
                }
            }
        }
    }
}

相关文章

  • 二叉树遍历(递归&非递归实现)

    递归实现: 非递归实现: 基于栈的递归消除: 递归(recursion)就是子程序(或函数)直接调用自己或通过一系...

  • 二叉树基于栈的递归消除

    递归转非递归的原因 递归执行效率低;(有进入、保存、出来、恢复四个操作)有些运行环境没有递归机制 递归转换的两种方...

  • 二叉树的镜像

    描述 操作给定的二叉树,将其变换为源二叉树的镜像。源二叉树 代码 递归 非递归用栈

  • 二叉树,非递归法

    递归法 二叉树的递归,有前序遍历、中序遍历、后序遍历,一般采用递归法,比较简单 非递归法 二叉树非递归法,采用栈来实现

  • 二叉树

    结构体 创建二叉树 递归遍历 栈操作 非递归遍历 层次遍历 完整代码

  • 二叉树基础算法

    1. 二叉树利用栈的非递归先序遍历 2. 二叉树利用栈的非递归后序遍历 3. 找二叉树最近的共同祖先 找二叉排序树...

  • 面试题----树

    94. 二叉树的非递归前序遍历 直接进出入栈,拿出数据: 94. 二叉树的非递归中序遍历 首先是根非空入栈,对子树...

  • 二叉树的非递归遍历一(先序/JAVA)

    前言 二叉树的非递归遍历对于初学者来说可能不太容易掌握,其实它源于递归遍历,只是把递归栈换成了我们自己的栈。掌握了...

  • 二叉树遍历java,非递归、层次。

    /** * 前序遍历 * 递归 */ /*** 前序遍历* 非递归*/ 后续遍历非递归 二叉树层次遍历基于java...

  • 不一样的二叉树非递归遍历

    本篇将讨论模拟系统栈的二叉树非递归遍历,并由此讨论一般化的将递归程序改为非递归程序的方式。 二叉树的非递归遍历 就...

网友评论

      本文标题:二叉树基于栈的递归消除

      本文链接:https://www.haomeiwen.com/subject/optjdctx.html