C# 创建二叉树以及深度遍历二叉树

没想到多叉树的深度遍历真的用上了。最近有个功能一定要得到将UI层级完全展开后,从上到下依次记录每个物体的层级顺序,但是,每个父物体的顺序要记录在其所有子物体之后,用到了后序深度遍历。

之前项目用到了树形存储的配置结构,多叉树除了用于配置结构外,还有用于复杂文件目录结构。
二叉树一个比较经典的应用是红黑树,查找、插入、删除的时间复杂度最坏为O(log n),效率高。
很多语言的hashmap用红黑树来做。

二叉树的基础操作学会了,多叉树的基础操作也就学会了。


原文: C#代码创建二叉树以及遍历二叉树

二叉树的前中后序遍历,是根据遍历时根节点在其左右子树中的相对顺序定义的。
对于每一个节点来说,前序是只先遍历根节点,然后左子树,然后右子树
中序是先左子树,然后根节点,然后右子树
后序是先左子树,然后右子树,然后根节点
以下图所属树来做例子。
在这里插入图片描述

节点定义

using System;
using System.Collections.Generic;
using System.Text;

namespace BinaryDemo
{
    public class TreeNode
    {
        /*
         * 树的知识点
         * 树结点 根结点 结点子树
         * 结点的度  结点关系 结点层次
         * 树的深度/高度
         */
        //结点下标  结点下标字符串数据 左子树 右子树
        private int index;
        private string data;
        private TreeNode leftChild;
        private TreeNode rightChild;
        private TreeNode parent;


        /// <summary>
        /// 有参构造结点下标  结点下标的字符串数据
        /// </summary>
        /// <param name="index"></param>
        /// <param name="data"></param>
        public TreeNode(int index, string data)
        {
            this.index = index;
            this.data = data;
            this.leftChild = null;
            this.rightChild = null;
        }

        public int getIndex()
        {
            return index;
        }
        public void setIndex(int index)
        {
            this.index = index;
        }
        //拿到左右子串的数据
        public String getData()
        {
            return data;
        }
        public void setData(String data)
        {
            this.data = data;
        }
        //拿到左子树
        public TreeNode getLeftChild()
        {
            return leftChild;
        }
        public void setLeftChild(TreeNode leftChild)
        {
            this.leftChild = leftChild;
        }
        //拿到右子树
        public TreeNode getRightChild()
        {
            return rightChild;
        }
        public void setRightChild(TreeNode rightChild)
        {
            this.rightChild = rightChild;
        }
        public TreeNode getParent()
        {
            return parent;
        }
        public void setParent(TreeNode parent)
        {
            this.parent = parent;
        }
        //快捷键生成的字段get和set
        public int Index { get => index; set => index = value; }
        public string Data { get => data; set => data = value; }
        public TreeNode LeftChild { get => leftChild; set => leftChild = value; }
        public TreeNode RightChild { get => rightChild; set => rightChild = value; }
        public TreeNode Parent { get => parent; set => parent = value; }
    }
}

创建二叉树

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace BinaryDemo
{
    public class BinaryTree
    {
        //根结点
        public TreeNode root = null;
        public static string[] str;
        public static int count;
        /// <summary>
        /// 无参构造设置根结点并赋值数据
        /// </summary>
        public BinaryTree()
        {
            root = new TreeNode(1,"A");
        }
        /// <summary>
        /// 构建二叉树的方法    B C D E F
        /// 手动的构建一棵二叉树  很快就可以得出这个二叉树的结构
        /// </summary>
        public void CreateBinaryTree()
        {
            TreeNode nodeb = new TreeNode(2,"B");
            TreeNode nodec = new TreeNode(3, "C");
            TreeNode noded = new TreeNode(4, "D");
            TreeNode nodee = new TreeNode(5, "E");
            TreeNode nodef = new TreeNode(6, "F");
            root.LeftChild = nodeb;
            root.RightChild = nodec;
            nodeb.LeftChild = noded;
            nodeb.RightChild = nodee;
            nodec.RightChild = nodef;
        }

递归遍历

前序遍历

		/// <summary>
        /// 先序遍历 --迭代
        /// 若二叉树为空树直接返回,先序遍历的特点根左右
        /// </summary>
        public void PreOrder(TreeNode node)
        {
            if (node == null)
            {
                return;
            }
            else
            {
                //node.getData()我们可以获取到二叉树的根结点的数据
                Console.WriteLine("先序遍历" + "\t迭代" + node.getData());
                //得到左子树的数据
                PreOrder(node.LeftChild);
                //得到右子树的数据
                PreOrder(node.RightChild);
            }
        }
  1. 打印结点A,此时属于第零层递归,结点A左子树进入第一层递归

  2. 第一层递归中,打印结点A左子树的根结点B,结点B左子树进入第二层递归

  3. 第二层递归中,打印结点B左子树的根结点D,结点D左子树进入第三层递归

  4. 第三层递归中,因为结点D左子树为空,返回第二层递归,返回后,代码运行到了访问结点D右子树部分,结点D右子树进入第三层递归

  5. 因为结点D右子树为空,返回第二层递归,第二层访问的是结点D,返回后已经进入第二层函数尽头,第二层递归结束,返回第一层递归,第一层递归访问的是结点B

  6. 返回到第一层递归中,代码到了结点B右子树的部分,结点B右子树进入第二层递归

  7. 第二层递归中,打印结点B右子树的根结点E,然后结点E左子树进入第三层递归

  8. 第三层递归中,结点E左子树为空,返回第二层递归,返回时第二层递归的代码到了访问结点E右子树部分,进入第三层递归

  9. 进入第三层递归中,结点E右子树为空,返回第二层递归。

  10. 返回到第二层的时候函数已经进入结束部分,再次返回第一层递归,返回到第一层的时候,第一层递归已经遍历完B右子树,函数进入结束部分,返回第零层递归,第零层递归访问的是结点A。

  11. 返回到第零层递归后,代码进入到访问A的右子树部分,结点A右子树进入第一层递归

  12. 第一层递归中, 打印结点A右子树的根结点C,结点C左子树进入第二层递归

  13. 第二层递归中,结点C左子树为空,返回第一层递归,返回后,代码到了访问第一层递归的C的右子树部分,结点C右子树进入第二层递归

  14. 第二层递归中, 打印结点C右子树的根结点F,结点F左子树进入第三层递归

  15. 第三层递归中,结点F左子树为空,返回第二层递归

  16. 返回到第二层递归的时候,代码到了访问第二层递归的F的右子树部分,结点F右子树进入第三层递归

  17. 第三层递归中,结点F右子树为空,返回第二层递归

  18. 返回到第二层,第二层访问的是结点F,此时结点F左右子树都已经访问完毕,第二层递归函数已经进入函数结尾,第二层递归结束,返回第一层递归。

  19. 返回到第一层,第一层访问的是结点C,此时遍历完C右子树,第一层递归函数进入结束部分,返回第零层递归。

  20. 返回到第零层,第零层递归访问的是结点A,此时遍历完A右子树,第零层递归函数进入结束部分,所有遍历结束。

这些流程下来,打印的顺序依次为ABDECF,符合前序遍历的要求。

中序遍历

		/// <summary>
        /// 中序遍历--递归
        /// 若二叉树为空树直接返回,中序遍历的特点左根右
        /// </summary>
        /// <param name="node"></param>
        public void MidOrder(TreeNode node)
        {
            if (node == null)
            {
                return;
            }
            else
            {
                MidOrder(node.LeftChild);
                Console.WriteLine("中序遍历" + "\t迭代" + node.getData());
                MidOrder(node.RightChild);
            }
        }

  1. 第零层递归,访问的是结点A,结点A左子树进入第一层递归

  2. 第一层递归中,访问的是结点A左子树的根节点是结点B,结点B左子树进入第二层递归

  3. 第二层递归中,访问的是结点B左子树的根节点是结点D,结点D左子树进入第三层递归

  4. 第三层递归中,因为结点D左子树为空,返回第二层递归。

  5. 返回第二层递归后,代码进入打印当前层结点部分,打印第二层访问的结点D,然后代码运行到了访问结点D右子树部分,结点D右子树进入第三层递归。

  6. 第三层递归中,因为结点D右子树为空,返回第二层递归。

  7. 第二层访问的是结点D,返回后已经进入第二层函数尽头,第二层递归结束,返回第一层递归,第一层递归访问的是结点B

  8. 返回到第一层递归中,代码到了打印当前访问结点的部分,当前访问结点是B,打印结点B,然后结点B右子树进入第二层递归

  9. 第二层递归中,访问的是结点B右子树的根结点E,然后结点E左子树进入第三层递归

  10. 第三层递归中,结点E左子树为空,返回第二层递归,返回时第二层递归的代码到了打印当前访问结点的部分,当前访问结点是E,打印结点E,然后访问结点E右子树部分,进入第三层递归

  11. 进入第三层递归中,结点E右子树为空,返回第二层递归。

  12. 返回到第二层的时候函数已经进入结束部分,再次返回第一层递归,返回到第一层的时候,第一层递归已经遍历完B右子树,函数进入结束部分,返回第零层递归,第零层递归访问的是结点A。

  13. 返回到第零层递归后,代码到了打印当前访问结点的部分,当前访问结点是A,打印结点A,然后代码进入到访问A的右子树部分,结点A右子树进入第一层递归

  14. 第一层递归中, 访问的是结点A右子树的根节点结点C,结点C左子树进入第二层递归

  15. 第二层递归中,结点C左子树为空,返回第一层递归,返回后,代码到了打印当前访问结点的部分,当前访问结点是C,打印结点C。

  16. 访问第一层递归的C的右子树部分,结点C右子树进入第二层递归

  17. 第二层递归中, 访问的是结点C右子树的根结点F,结点F左子树进入第三层递归

  18. 第三层递归中,结点F左子树为空,返回第二层递归

  19. 返回到第二层递归的时候,代码到了打印当前访问结点的部分,当前访问结点是F,打印结点F,然后代码到了访问第二层递归的F的右子树部分,结点F右子树进入第三层递归

  20. 第三层递归中,结点F右子树为空,返回第二层递归

  21. 返回到第二层,第二层访问的是结点F, 此时结点F左右子树都已经访问完毕,第二层递归函数已经进入函数结尾,第二层递归结束,返回第一层递归。

  22. 返回到第一层,第一层访问的是结点C,此时遍历完C右子树,第一层递归函数进入结束部分,返回第零层递归。

  23. 返回到第零层,第零层递归访问的是结点A,此时遍历完A右子树,第零层递归函数进入结束部分,所有遍历结束。

这些流程下来,打印的顺序依次为DBEACF,符合中序遍历的要求。

后序遍历

		public void LastOrder(TreeNode node)
       {
           if (node == null)
           {
               return;
           }
           else
           {
               LastOrder(node.LeftChild);
               LastOrder(node.RightChild);
               Console.WriteLine("后序遍历" + "\t迭代" + node.getData());
           }
       }

  1. 第零层递归,访问的是结点A,结点A左子树进入第一层递归

  2. 第一层递归中,访问的是结点A左子树的根节点是结点B,结点B左子树进入第二层递归

  3. 第二层递归中,访问的是结点B左子树的根节点是结点D,结点D左子树进入第三层递归

  4. 第三层递归中,因为结点D左子树为空,返回第二层递归。

  5. 返回第二层递归后,第二层递归访问的是结点D,结点D右子树进入第三层递归。

  6. 第三层递归中,因为结点D右子树为空,返回第二层递归。

  7. 第二层访问的是结点D,返回后已经进入打印当前结点部分,打印第二层递归访问的结点D,第二层递归结束,然后第二层递归结束,返回第一层递归

  8. 返回到第一层递归中,代码到了访问当前递归结点的右子树的部分,当前第一层访问结点是B, 结点B右子树进入第二层递归

  9. 第二层递归中,访问的是结点B右子树的根结点E,然后结点E左子树进入第三层递归

  10. 第三层递归中,结点E左子树为空,返回第二层递归。

  11. 返回第二层递归时,代码到了访问当前访问结点的右子树部分,当前访问结点是E,访问结点E右子树部分,进入第三层递归

  12. 进入第三层递归中,结点E右子树为空,返回第二层递归。

  13. 第二层访问的是结点E,返回后结点E的左右子树都已经遍历完成,进入打印当前结点部分,当前结点部分是E,打印E,第二层递归结束,返回第一层递归。

  14. 返回第一层递归时,第一层递归已经将当前结点的左右子树都遍历完毕,这时打印当前遍历结点,当前遍历的结点是B,打印B,然后当前层遍历结束,返回第零层遍历

  15. 第零层遍历访问的是结点A,返回时结点A的左子树遍历结束,结点A的右子树进入第一层递归。

  16. 第一层递归,访问A的右子树的根节点C,然后第二层递归访问C的左子树

  17. 第二层递归中,结点E左子树为空,返回第一层递归

  18. 返回第一层递归时,代码到了访问当前结点的右子树部分,结点C的右子树进入第二层递归

  19. 第二层递归中,访问结点C的右子树的根节点F,然后进入第三层递归,访问F的左子树

  20. 第三层递归中,F的左子树为空,返回第二层

  21. 返回第二层时,代码到了访问当前结点的右子树部分,第三层递归访问F的右子树

  22. 第三层递归中,F的右子树为空,返回第二层

  23. 返回第二层时,代码走到了打印当前访问结点的部分,当前访问结点是F,打印F,然后第二层递归结束,返回第一层递归

  24. 返回第一层时,第一层递归已经将当前结点的左右子树都遍历完毕,代码走到了打印当前访问结点的部分,当前访问结点是C,打印C,然后第一层递归结束,返回第零层递归

  25. 返回第零层时,第零层递归已经将当前结点的左右子树都遍历完毕,代码走到了打印当前访问结点的部分,当前访问结点是A,打印A,然后第零层递归结束,所有递归结束

这些流程下来,打印的顺序依次为DEBFCA,符合后序遍历的要求。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

染指流年丨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值