二叉树的遍历C#实现,递归以及非递归

前序遍历

输出规则

根节点, 左子树, 右子树。
二叉树的前序遍历规则是从根节点开始,依层 逐层取 左子节点,若此节点没有 左子节点,说明此节点是叶子节点,往上 回溯, 取 最小父节点的右节点,再重复 此步骤,取左子节点。直到 没有左子节点,也没有最小父右子节点,

递归版本 比较好记,也容易理解, 只要节点不为null 先取 左子节点,后取右子节点。

   public void TraversingBSTree2<T>(BSNode<T> root)
        {
            if (root == null)
            {
                return;
            }
            Console.Write(root.Value+" ");
            TraversingBSTree2<T>(root.Left);
            TraversingBSTree2<T>(root.Right);
        }
    }

非递归版本, 利用栈的特点进行 回溯, 因为栈是 先入后出的 规则,也就是说,最新弹出的一定是最小的节点,

  • 若有节点, 压栈 取 左子节点。
  • 若没节点,说明左子树的所有左子节点取完了, 这个时候,弹出该子节点的父节点,取右子节点
  • 若此节点没右子节点,则继续弹出,直到有右子节点,直到空栈 就停止。
  • 取到右节点后,继续 压栈取它的左子节点 直到没有左子节点取了。
  • 弹出,取右子节点。
        /// <summary>
        /// 利用 栈的特点 进行回溯 ,绝大多数递归的问题可以用另一种数据结构解决  这种结构就是栈,递归和栈都有回溯特性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="root"></param>
        public static void TraversingBSTree<T>( BSNode<T> root)
        {
            Stack<BSNode<T>> stack =new Stack<BSNode<T>>();
            BSNode<T> temp = root;
            while (temp!=null || stack.Count>0)
            {
                while (temp!=null)
                {
                    //打印入栈
                    Console.WriteLine(temp.Value);
                    stack.Push(temp);
                    temp = temp.Left;
                }

                if (stack.Count > 0)
                {
                    temp = stack.Pop(); //
                    temp = temp.Right; //取最小右父节点   如果为null,则继续弹出
                }
            }
        }

中序遍历

输出规则

输出循序是:左子树,根节点,右子树。

中序遍历 二叉树 规则是根节点有左子节点,取左子节点,没直到没有左子点,进行打印,然后取该节点的父节点,打印,取右子节点 打印,若右子节点有左子节点,取左子节点打印, 依次循环上面规则。

   public void TraversingBSTree2<T>(BSNode<T> root)
        {
            if (root == null)
            {
                return;
            }            
            TraversingBSTree2<T>(root.Left);
            Console.Write(root.Value+" ");
            TraversingBSTree2<T>(root.Right);
        }
    }
public static void TraversingBSTree<T>( BSNode<T> root)
        {
            Stack<BSNode<T>> stack =new Stack<BSNode<T>>();
            BSNode<T> temp = root;
            while (temp!=null || stack.Count>0)
            {
                while (temp!=null)
                {
                    //打印入栈
                    
                    stack.Push(temp);
                    temp = temp.Left;
                }

                if (stack.Count > 0)
                {
                    temp = stack.Pop(); //
            		if (temp!= null)
                      {
                          Console.WriteLine(temp.Value);
                      }
                    temp = temp.Right;  
                }
            }
        }

后序遍历

输出规则

打印顺序:左子树 右子树 根节点

 public void TraversingBSTree2<T>(BSNode<T> root,int flag=1)
        {
            if (root == null)
            {
                return;
            }
 
            TraversingBSTree2<T>(root.Left);            
            TraversingBSTree2<T>(root.Right);
            Console.Write(root.Value + " ");            
        }

非递归版本
打印顺序:左子树 右子树 根节点
思路就是利用是逆序 倒推。根节点最后, 根节点的右子节点倒数第二。依次 倒序
压入栈1 的顺序是:先把根节点压入栈1,再将其弹出存储到栈二的 栈底里,根节点一定是最后输出的。
第一次从栈1中弹出节点,压入到栈2中存储,然后依次判断根节点是否有左子节点,有将其压入, 判断是否有 右子节点,有将其压入。

接着循环 从栈1中弹出,压入栈2中 直到空栈退出循环。

(根节点不算,在循环外) 这里的根节点 只是第一次进去 而已 不是在循环里的
压入栈1规则 左 右 根, 弹出 压出 栈二规则: 根 右 左,

压入栈二规则 根 右 左, 最后 输出 规则 左 右 根。

栈2是来用最后输出的。因为是先入后出,最先进去的一定是最后出来的。压入 顺序 就是 根 节点, 右子树 ,左子树, 因此 输出一定是
左子树,右子树 ,根节点。

public static void TraversingBSTreeBack<T>(BSNode<T> root)
        {
            if (root == null)
            {
                return;
            }
             Stack<BSNode<T>> stack1=new Stack<BSNode<T>>();
             Stack<BSNode<T>> stack2 = new Stack<BSNode<T>>();
               stack1.Push(root);
             while (stack1.Count>0)
             {
                 BSNode<T> temp= stack1.Pop();
                 stack2.Push(temp);
                 if (temp.Left!=null)
                 {
                     stack1.Push(temp.Left);
                 }

                 if (temp.Right!=null)
                 {
                     stack1.Push(temp.Right);
                }
            }

             while (stack2.Count>0)
             {
                 Console.WriteLine(stack2.Pop().Value); 
             }
        }

前中后的输出 是根据 跟节点的位置来决定的
前序 根 在前,中序 根在中间,后序 根在后面,
前面三种 遍历规则 都是基于 深度优先的, 意思就是 一头扎到底,
比如 前序遍历 输出 根节点后 会去找 最深的左孙孙孙…子节点,然后再 往上 输出。其他两种 都类似。

二叉树的层级遍历

广度优先

输出规则

按层级遍历, 从左到右进行输出。
非递归 版本可以 利用 队列的特性,
先进先出,从根节点 开始 入队, 然后 取出,如果存在左孩子,入队,
如果存在 右孩子 入队。

根据先进先出的 原则, 根节点 第一个输出,
接着 输出 左孩子, 接着 输出右孩子

        public static void LevelTraversing<T>(BSNode<T> root)
        {
            if (root == null)
            {
                return;
            }
            Queue<BSNode<T>> BsNodeQueue=new Queue<BSNode<T>>();
            BsNodeQueue.Enqueue(root); //首次进入
            while (BsNodeQueue.Count>0)
            {
                BSNode<T> node = BsNodeQueue.Dequeue(); //出队
                Console.WriteLine(node.Value);
                if (node.Left!=null)
                {
                    BsNodeQueue.Enqueue(node.Left);  //入队
                }

                if (node.Right!=null)
                {
                    BsNodeQueue.Enqueue(node.Right);//入队
                }
            }
        }
    }
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值