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

namespace BitTree
{
    //TODO:打印二叉树

    class Constant
    {
        public static readonly string Space = " ";
    }

    class Program
    {
        static void Main(string[] args)
        {
           //" "表示叶子结点

            string preorder = "ABC  DE G  F  ";
            //string preorder = "ABDH  I  EJ  K  CFL   G  ";

            Console.WriteLine("树结点:{0}", preorder);
            BitTree bt = new BitTree(preorder);
            Node root = bt.CreateBitTreePreOrder();

            int width = bt.GetTreeWidth(root);

            Console.WriteLine("树宽:{0}", width);            

            //树高
            int depth = bt.GetTreeDepth(root);
            Console.WriteLine("树高递归算法:{0}", depth);

            depth = bt.GetTreeDepthNoneRecursion(root);
            Console.WriteLine("树高非递归算法:{0}", depth);

            //先序
            Console.WriteLine("先序递归遍历:");
            bt.PreTraverse(root);
            Console.WriteLine();
            Console.WriteLine("先序非递归遍历:");
            bt.PreTraverseNoneRecursion(root);
            Console.WriteLine();

            //中序
            Console.WriteLine("中序递归遍历:");
            bt.MidTraverse(root);
            Console.WriteLine();
            Console.WriteLine("中序非递归遍历:");
            bt.MidTraverseNoneRecursion(root);
            Console.WriteLine();

            //后序
            Console.WriteLine("后序递归遍历:");
            bt.PostTraverse(root);
            Console.WriteLine();

            Console.WriteLine("后序非递归遍历:");
            bt.PostTraverseNoneRecursion(root);
            Console.WriteLine();

            //层次遍历
            Console.WriteLine("层次遍历:");
            bt.TopToBottomReserver(root);
            Console.ReadLine();
        }
    }

    internal class Node
    {
        internal Node Left { get; set; }
        internal Node Right { get; set; }
        internal string Value { get; set; }
    }

    class BitTree
    {
        string inputSequence;

        public BitTree(string input)
        {
            inputSequence = input;
        }

        #region 先序算法
        //先序创建二叉树
        public Node CreateBitTreePreOrder()
        {
            return CreateBitTreePreOrder(null);
        }

        private Node CreateBitTreePreOrder(Node node)
        {
            if (string.IsNullOrEmpty(inputSequence))
            {
                return null;
            }

            string value = inputSequence.Substring(0, 1);
            inputSequence = inputSequence.Substring(1);

            if (string.IsNullOrEmpty(value) || value == Constant.Space)
            {
                return null;
            }

            node = new Node();
            node.Value = value;
            node.Left = CreateBitTreePreOrder(node.Left);
            node.Right = CreateBitTreePreOrder(node.Right);

            return node;
        }

        //先序遍历二叉树,递归
        public void PreTraverse(Node node)
        {
            if (node != null)
            {
                Console.Write(node.Value);
                PreTraverse(node.Left);
                PreTraverse(node.Right);
            }
        }

        //先序遍历二叉树,非递归
        public void PreTraverseNoneRecursion(Node node)
        {
            Stack<Node> stack = new Stack<Node>();

            while (node != null || stack.Count > 0)//while用的很牛
            {
                if (node != null)//压栈同时访问
                {
                    Console.Write(node.Value);
                    stack.Push(node);
                    node = node.Left;
                }
                else//处理右边
                {
                    node = stack.Pop();
                    node = node.Right;
                }
            }
        }

        #endregion

        #region 中序遍历算法

        //中序不能唯一确定一颗二叉树

        //中序遍历二叉树,递归
        public void MidTraverse(Node node)
        {
            if (node != null)
            {
                MidTraverse(node.Left);
                Console.Write(node.Value);
                MidTraverse(node.Right);
            }
        }

        //中序遍历二叉树,非递归
        public void MidTraverseNoneRecursion(Node node)
        {
            Stack<Node> stack = new Stack<Node>();

            while (node != null || stack.Count > 0)//while用的很牛
            {
                if (node != null)//压栈
                {
                    stack.Push(node);
                    node = node.Left;
                }
                else//弹出后访问
                {
                    node = stack.Pop();
                    Console.Write(node.Value);
                    node = node.Right;
                }
            }
        }

        #endregion

        #region 后序遍历算法

        //后序遍历二叉树,递归
        public void PostTraverse(Node node)
        {
            if (node != null)
            {
                PostTraverse(node.Left);
                PostTraverse(node.Right);
                Console.Write(node.Value);
            }
        }

        //后序遍历二叉树,非递归
        public void PostTraverseNoneRecursion(Node node)
        {
            Stack<Node> stack = new Stack<Node>();

            Node lastvisit = node;//最后访问的结点

            while (node != null || stack.Count > 0)
            {
                if (node != null)
                {
                    stack.Push(node);
                    node = node.Left;
                }
                else
                {
                    Node p = stack.Peek();//取而不出

                    //    || (p.Right == lastvisit))//若右边为空,或已经访问过,则返回到父结点
                    if(p.Right == null || p.Right == lastvisit)
                    {
                        stack.Pop();
                        Console.Write(p.Value);
                        lastvisit = p;
                    }
                    else//非叶结点,右边未访问过,访问右边
                    {
                        node = p.Right;
                    }
                }
            }
        }

        #endregion

        #region 层次遍历

        public void TopToBottomReserver(Node node)
        {
            Queue<Node> queue = new Queue<Node>();

            queue.Enqueue(node);
            while (queue.Count > 0)
            {
                node = queue.Dequeue();

                if (node != null)
                {
                    Console.Write(node.Value);

                    queue.Enqueue(node.Left);
                    queue.Enqueue(node.Right);
                }
            }
        }

        #endregion

        #region 树高
        public int GetTreeDepth(Node node)
        {
            if (node == null)
            {
                return 0;
            }
            else if (node.Left == null && node.Right == null)
            {
                return 1;
            }
            else
            {
                int ldepth = GetTreeDepth(node.Left);
                int rdepth = GetTreeDepth(node.Right);
                return ldepth > rdepth ? 1 + ldepth : 1 + rdepth;
            }
        }

        //方法和遍历一样,用两个int作标记
        public int GetTreeDepthNoneRecursion(Node root)
        {
            int depth = 0;

            Stack<Node> stack = new Stack<Node>();

            Node lastvisit = root;//最后访问的结点

            while (root != null || stack.Count > 0)
            {
                if (root != null)
                {
                    stack.Push(root);

                    depth = stack.Count > depth ? stack.Count : depth;
                    root = root.Left;
                }
                else
                {
                    Node p = stack.Peek();//取而不出

                    if (p.Right == null || p.Right == lastvisit)
                    {
                        stack.Pop();
                        lastvisit = p;
                    }
                    else//非叶结点,右边未访问过,访问右边
                    {
                        root = p.Right;
                    }
                }
            }

            return depth;
        }
        #endregion

        public int GetTreeWidth(Node root)
        {
            if (root == null)
            {
                return 0;
            }
            else if (root.Left == null && root.Right == null)
            {
                return 1;
            }
            else
            {
                int lwidth = GetTreeWidth(root.Left);
                int rwidth = GetTreeWidth(root.Right);

                return 1 + lwidth - rwidth;
            }
        }

        //返回结点总数
        public int GetNodeCount(Node root)
        {
            if (root == null)
            {
                return 0;
            }
            else if (root.Left == null && root.Right == null)
            {
                return 1;
            }
            else
            {
                int lwidth = GetNodeCount(root.Left);
                int rwidth = GetNodeCount(root.Right);

                return 1 + lwidth + rwidth;
            }
        }

        //得到指定层上所有结点
        private List<Node> GetNodeListInDepth(Node root, int depthNum)
        {
            int treeheight = GetTreeDepth(root);

            if (root == null || depthNum > treeheight)
            {
                return new List<Node>();
            }

            List<Node> sumNode = new List<Node>();

            if(depthNum == 1)
            {
                sumNode.Add(root);
                return sumNode;
            }

            Node node = root;

            List<Node> lchilrenlist = new List<Node>();
            lchilrenlist = GetNodeListInDepth(node.Left, depthNum - 1);

            List<Node> rchilrenlist = new List<Node>();
            rchilrenlist = GetNodeListInDepth(node.Right, depthNum - 1);

            sumNode.AddRange(lchilrenlist);
            sumNode.AddRange(rchilrenlist);

            return sumNode;
        }

    }
}