二叉树基础及其C#代码实现

二叉树的遍历有深度遍历(前序、中序、后序)和广度遍历(层次遍历)。二叉树的顺序存储结构就是使用一维数组存储二叉树中的结点,并且结点的存储位置,就是数组的下标索引,如下图所示就是完全二叉树的顺序存储方式,但一般它也只适用于完全二叉树,与数组、向量、链表都是一种顺序容器,它们提供了按位置访问数据的手段。但是有一个缺点,它们都是按照位置来确定数据,想要通过值来获取数据,只能通过遍历的方式。而二叉树在很大程度上解决了这个缺点,二叉树是按值来保存元素,也按值来访问元素。
在这里插入图片描述

1.前序遍历就是从二叉树的根节点出发,当第一次到达节点时就输出节点数据,按先左后右方式访问,故上图结果为ABDHIEJCFG。
2.中序遍历就是从二叉树的根节点出发,当第二次到达节点时就输出节点数据,按先左后右方式访问,故上图结果为HDIBJEAFCG。
3.后序遍历就是从二叉树的根节点出发,当第三次到达节点时就输出节点数据,按先左后右方式访问,故上图结果为HIDJEBFGCA。
4.层次遍历就是按照树的层次自上而下的遍历二叉树,故上图结果为ABCDEFGHIJ。
以下代码通过C#实现递归的方式进行二叉树的几种遍历,如果是非递归实现可以参考点这

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

namespace BinaryTree
{
    class BinaryTree
    {
        private Node _head;
        private string cStr;
        public Node Head
        {
            get { return _head; }
            set{_head=value;}
        }
        public BinaryTree()
        {
            _head=null;
        }
        public BinaryTree(string constructStr)//默认的是以层序序列构造二叉树
        {
            cStr=constructStr;
            if(cStr[0]=='#')
            {
                _head=null;
                return;//根节点为空,则无树建立
            }
            _head=new Node(cStr[0]);
            Add(_head,0);
        }
        //按照给定层序序列给二叉树添加节点
        private void Add(Node parent,int index)
        {
            int leftIndex=2*index+1;
            if(leftIndex<cStr.Length)
            {
                if (cStr[leftIndex] != '#')
                {
                    parent.Left = new Node(cStr[leftIndex]);
                    Add(parent.Left, leftIndex);
                }
            }
             int rightIndex = 2 * index + 2;
            if (rightIndex < cStr.Length)
            {
                if (cStr[rightIndex] != '#')
                {
                    parent.Right = new Node(cStr[rightIndex]);
                    Add(parent.Right, rightIndex);
                }
            }
        }
        //递归先序遍历
        public void PreOrder(Node node)
        {
            if (node != null)
            {
                Console.Write(node);
                PreOrder(node.Left);
                PreOrder(node.Right);
            }
        }
        //递归中序遍历
        public void InOrder(Node node)
        {
            if (node != null)
            {
                InOrder(node.Left);
                Console.Write(node);
                InOrder(node.Right);
            }
        }
        //递归后序遍历
        public void AfterOrder(Node node)
        {
            if (node != null)
            {
                AfterOrder(node.Left);
                AfterOrder(node.Right);
                Console.Write(node);
            }
        }
        //广度优先遍历,就是层次遍历
        public void LevelOrder()
        {
            Node node = _head;
            Queue<Node> queue = new Queue<Node>();//队列(Queue)代表了一个先进先出的对象集合,参考https://www.runoob.com/csharp/csharp-queue.html
            queue.Enqueue(node);
            while (queue.Count > 0)
            {
                node = queue.Dequeue();
                Console.Write(node);
                if (node.Left != null)
                {
                    queue.Enqueue(node.Left);

                }
                if (node.Right != null)
                {
                    queue.Enqueue(node.Right);
                }
            }
        }
        /*二叉树遍历的应用*/
        //1、计算叶子节点的个数(先序遍历)
        //度为2的节点和度为0的节点也就是叶子节点的关系是n0=n2+1;加上可以统计节点的个数所以就可以
        //分别统计度为0、度为1和度为2的节点数了。

        public void CountLeaf(Node node, ref int count)
        {
            if (node != null)
            {
                if ((node.Left == null) && (node.Right == null))
                    count++;
                CountLeaf(node.Left, ref count);
                CountLeaf(node.Right, ref count);
            }
        }
        //计算节点数
        public int Count(Node root)
        {
            if (root == null) return 0;
            return Count(root.Left) + Count(root.Right) + 1;
        }
        //2、计算树的高度(后序遍历)
        public int Height(Node root)
        {
            int a, b;
            if (root == null) return 0;
            a = Height(root.Left);
            b = Height(root.Right);
            if (a > b) return a + 1; else return b + 1;
        }
        //3、复制二叉树(后序遍历)
        public Node CopyTree(Node root)
        {
            Node newroot;
            if (root == null)
            {
                newroot = null;
            }
            else
            {
                CopyTree(root.Left);
                CopyTree(root.Right);
                newroot = root;
            }
            return newroot;
        }
        /*4、建立二叉树饿存储结构(建立二叉树的二叉链表)。上面的复制也是种建立方法*/
        //(1)按给定先序序列建立二叉树
        public static BinaryTree CreateByPre(string s)
        {
            BinaryTree tree = new BinaryTree(s);//先以层序序列初始化个树,再调整
            int _count = 0;
            Node node = tree.Head;
            Stack<Node> stack = new Stack<Node>();
            while (node != null || stack.Count > 0)
            {
                while (node != null)
                {
                    node.Data = s[_count++];
                    stack.Push(node);
                    node = node.Left;
                }
                if (stack.Count > 0)//第2步
                {
                    node = stack.Pop();
                    node = node.Right;

                }
            }
            return tree;
        }
        //以中序序列建立二叉树
        public static BinaryTree CreateByIn(string s)
        {
            BinaryTree tree = new BinaryTree(s);//先以层序序列初始化个树,再调整
            int _count = 0;
            Node node = tree.Head;
            Stack<Node> stack = new Stack<Node>();
            while (node != null || stack.Count > 0)
            {
                while (node != null)
                {
                    stack.Push(node);
                    node = node.Left;
                }
                if (stack.Count > 0)
                {
                    node = stack.Pop();
                    node.Data = s[_count++];
                    node = node.Right;

                }
            }
            return tree;
        }
        public static BinaryTree CreateByAfter(string s)
        {
            BinaryTree tree = new BinaryTree(s);//先以层序序列初始化个树,再调整
            int _count = 0;
            Node node = tree.Head;
            Node pre = tree.Head; ;
            //pre指针指向“之前出栈节点”,如果为null有问题,这里指向头节点,因为后续遍历中头节点肯定是最后被访问的。
            Stack<Node> stack = new Stack<Node>();
            while (node != null || stack.Count > 0)
            {
                while (node != null)
                {
                    stack.Push(node);
                    node = node.Left;
                }
                if (stack.Count > 0)
                {
                    Node temp = stack.Peek().Right;//获取栈顶元素的右孩子,C#的栈因为有了这个方法使得操作简单
                    if (temp == null || temp == pre)//满足规则1
                    {
                        node = stack.Pop();//出栈进行访问
                        node.Data = s[_count++];
                        pre = node;//设置“之前出栈节点”
                        node = null;//防止null再次入栈
                    }
                    else
                    {
                        node = temp;//规则2 继续循环。将栈顶节点的右孩子入栈,重复规则1的操作
                    }
                }
            }
            return tree;
        }
        //static void Main(string[] args)
        //{
        //    BinaryTree binaryTree = new BinaryTree("123456789");
           
        //}
        //**********
    }
    class Program
    {
        static void Main(string[] args)
        {
            BinaryTree binaryTree = new BinaryTree("123456789");
            binaryTree.PreOrder(binaryTree.Head);
            Console.WriteLine(" ");
            binaryTree.InOrder(binaryTree.Head);
            Console.WriteLine(" ");
            binaryTree.AfterOrder(binaryTree.Head);
            Console.ReadLine();
        }
    }
}
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值