C#二叉树的层次遍历

C#二叉树的从右向左的层次遍历详解

2.4 用C#构造一棵二叉树,并从根开始,按层的顺序,从右到左,从上到下,依次进行访问。

引言

这是一道C#初学时遇到的问题,也正好趁此机会回顾一下有关于二叉树的内容

通过本篇文章,你将收获到:
1.关于二叉树和层次遍历的基础知识;
2.复习有关于队列的基本知识
3.学习如何解决这道习题

环境设置

编译环境为Microsoft Visual Studio 2019,控制台程序

具体过程实现

首先,我们先回顾一下有关于二叉树和其遍历的基础知识:

简单来说,二叉树是一种每个结点最多有两个子树的树结构,如下图所示:

image.png

对于二叉树的遍历来说,常见的先序遍历,中序遍历,后序遍历,层次遍历等多种方法,而这道题要用到二叉树的层次遍历

所谓的层次遍历,也就是从上到下一层一层地对二叉树进行遍历.这道题要求的是每一层从右往左遍历,不过为了使题目更加好理解,我们优先考虑常见情况,也就是每一层从左到右进行遍历,此时上图的遍历顺序应该是A-B-C-D-E-F-G-H..

一种比较经典的做法是运用队列,我们以上图为例叙述过程(为了方便,仅作示意图):

image.png

如果读者想要回顾关于队列的基本知识,可以参考这一篇文章:
https://www.cnblogs.com/TimVerion/p/11194552.html

通过队列可以很好的实现二叉树的层次遍历,在思路清晰之后,我们需要对本题情况进行分析:
我们每次将元素出队之后,访问它并将它的左右子树依次加入队列,从而实现从左至右的层次遍历.那如果我们出队某节点并访问之后,将其右子树先入队,再入队左子树,是不是就可以实现每层从右到左的遍历了?接下来我们试一下:
1.入队A;
2.出队A,入队C,B;
3.出队C,入队G,F;
4.出队B,入队E,D;
5.出队G,无左右子树,因此不入队元素;
6.出队F,无左右子树,因此不入队元素;
7.出队E,无左右子树,因此不入队元素;
8.出队D,入队H;
9.出队H,队空,结束;
至此,出队顺序为:A-C-B-G-F-E-D-H,说明思路是正确的,接下来我们用C#的代码实现该过程:

首先是定义树的结点类
public class TreeNode
    {
        //树结点类的成员变量
        private object _data;//存放结点数据
        private TreeNode _left;//树的左孩子
        private TreeNode _right;//树的右孩子
        //属性
        public object Data
        {
            get { return _data; }
        }
        public TreeNode Left
        {
            get { return _left; }
            set { _left = value; }
        }
        public TreeNode Right
        {
            get { return _right; }
            set { _right = value; }
        }
        //构造方法
        public TreeNode(object data)
        {
            _data = data;//接收数据
        }
        public override string ToString()//重写了object类的ToString()方法
        {
            return _data.ToString();
        }
    }

这里面我们应用了属性来进行对字段的访问
关于属性的问题,详见https://www.cnblogs.com/zhangbaochong/p/4793360.html

接下来是二叉树操作的类的构造
    public class BinaryTree//二叉树的类
    {
        private TreeNode _head;//二叉树的头节点
        private string str;//用来存放结点信息的字符串
        //属性
        public TreeNode Head
        {
            get { return _head; }
        }
        private void Add(TreeNode parent,int index)//根据字符串添加左右结点,建立二叉树
        {
            int leftindex = 2 * index + 1;//左孩子结点应该对应的数组中的位置
            if(leftindex<str.Length)
            {
                if(str[leftindex]!='#')
                {
                    parent.Left = new TreeNode(str[leftindex]);
                    Add(parent.Left, leftindex);//用递归实现左孩子结点添加
                }
            }
            int rightindex = index * 2 + 2;
            if(rightindex<str.Length)
            {
                if(str[rightindex]!='#')
                {
                    parent.Right = new TreeNode(str[rightindex]);
                    Add(parent.Right, rightindex);//用递归实现右孩子结点添加
                }
            }
        }
        public BinaryTree(string Cstr)
        {
            str = Cstr;
            _head = new TreeNode(str[0]);//添加头结点
            Add(_head, 0);//给头结点添加孩子结点
        }
        //接下来,用队列实现二叉树的层次遍历
        public void leveltraverse()
        {
            Queue queue = new Queue();//建立一个队列
            queue.Enqueue(_head);//让头结点进入队列
            while(queue.Count>0)//当队列不为空
            {
                TreeNode node = (TreeNode)queue.Dequeue();//出队
                Console.Write(node.ToString());//访问该结点
                if(node.Right!=null)
                {
                    queue.Enqueue(node.Right);//右子树不为空则右子树进入队列
                }  
                if(node.Left!=null)
                {
                    queue.Enqueue(node.Left);//左子树不为空则左子树进入队列
                }
            }

        }
    }

在这一部分里,我们一共解决了这样几件事情:
1.将一个顺序输入的字符串转换为二叉树(其中字符串的#字符对应二叉树的空结点)
这一部分的原理是,在空结点用#表示的情况下,跟结点在字符串中对应的位置为0,则其左子树的序号为2x+1=1,右子树的序号为2x+2=2,以此类推(二叉树的性质)
2.用递归不断地实现左子树的加入和右子树的加入
3.用队列的方式实现二叉树的每层从右到左的层次遍历

接下来是主函数部分
class Program
    {
        static void Main(string[] args)
        {
            string str;
            Console.WriteLine("请按照层次遍历从左到右的顺序输入树的结点(结点为空则用#表示)");
            str = Console.ReadLine();
            Console.WriteLine("层次遍历从右到左的结果是:");
            BinaryTree bitree = new BinaryTree(str);
            bitree.leveltraverse();
        }
    }

至此,我们通过用户输入的字符串实现了二叉树每层从右到左的层次遍历

最后,附上本题的全部代码:

using System;
using System.Collections;
using System.ComponentModel;
using System.Reflection.Metadata.Ecma335;

namespace leveltraverse
{
    public class TreeNode
    {
        //树结点类的成员变量
        private object _data;//存放结点数据
        private TreeNode _left;//树的左孩子
        private TreeNode _right;//树的右孩子
        //属性
        public object Data
        {
            get { return _data; }
        }
        public TreeNode Left
        {
            get { return _left; }
            set { _left = value; }
        }
        public TreeNode Right
        {
            get { return _right; }
            set { _right = value; }
        }
        //构造方法
        public TreeNode(object data)
        {
            _data = data;//接收数据
        }
        public override string ToString()//重写了object类的ToString()方法
        {
            return _data.ToString();
        }

    }
    public class BinaryTree//二叉树的类
    {
        private TreeNode _head;//二叉树的头节点
        private string str;//用来存放结点信息的字符串
        //属性
        public TreeNode Head
        {
            get { return _head; }
        }
        private void Add(TreeNode parent,int index)//根据字符串添加左右结点,建立二叉树
        {
            int leftindex = 2 * index + 1;//左孩子结点应该对应的数组中的位置
            if(leftindex<str.Length)
            {
                if(str[leftindex]!='#')
                {
                    parent.Left = new TreeNode(str[leftindex]);
                    Add(parent.Left, leftindex);//用递归实现左孩子结点添加
                }
            }
            int rightindex = index * 2 + 2;
            if(rightindex<str.Length)
            {
                if(str[rightindex]!='#')
                {
                    parent.Right = new TreeNode(str[rightindex]);
                    Add(parent.Right, rightindex);//用递归实现右孩子结点添加
                }
            }
        }
        public BinaryTree(string Cstr)
        {
            str = Cstr;
            _head = new TreeNode(str[0]);//添加头结点
            Add(_head, 0);//给头结点添加孩子结点
        }
        //接下来,用队列实现二叉树的层次遍历
        public void leveltraverse()
        {
            Queue queue = new Queue();//建立一个队列
            queue.Enqueue(_head);//让头结点进入队列
            while(queue.Count>0)//当队列不为空
            {
                TreeNode node = (TreeNode)queue.Dequeue();//出队
                Console.Write(node.ToString());//访问该结点
                if(node.Right!=null)
                {
                    queue.Enqueue(node.Right);//右子树不为空则右子树进入队列
                } 
                if(node.Left!=null)
                {
                    queue.Enqueue(node.Left);//左子树不为空则左子树进入队列
                }
            }

        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            string str;
            Console.WriteLine("请按照层次遍历从左到右的顺序输入树的结点(结点为空则用#表示)");
            str = Console.ReadLine();
            Console.WriteLine("层次遍历从右到左的结果是:");
            BinaryTree bitree = new BinaryTree(str);
            bitree.leveltraverse();
        }
    }
}

运行结果可以看到如下图所示:


image.png

总结

1.本文介绍了有关于二叉树层次遍历的基础知识及其具体实现的方式(通过队列)
2.本文通过对于这道题目的探索巩固了C#的一些基础的语法知识
3.读者如果对于二叉树的其他遍历方式(如先序遍历,中序遍历,后序遍历等)感兴趣,可以参考文末的文章[3]https://www.cnblogs.com/zhaodayou/p/6883147.html

最后想说的话

因为本人刚接触C#这门优秀的语言,所以这篇文章难免会有错误和不足的地方,也欢迎大家讨论和交流.同时我也会在接下来的学习中不断提升自己,掌握更多的知识和技能.
参考文章:
[1]https://blog.csdn.net/weixin_43251547/article/details/104062082
[2]https://blog.csdn.net/qq_24642743/article/details/78597219?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2-all-first_rank_v2~rank_v25-1-78597219.nonecase&utm_term=c#%20%E4%BA%8C%E5%8F%89%E6%A0%91&spm=1000.2123.3001.4430
[3]https://www.cnblogs.com/zhaodayou/p/6883147.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。