面試毒瘤 之 反轉二叉樹


前一陣homebrew作者面試谷歌被拒,原因之一是這位老兄無法反轉出二叉樹。

 

既然眾公司面試都愛用這貨面試,咱也來做一下。

 

先定義二叉樹類

    public class BinaryTreeNode<T>
    {
        public string Name { get; set; }
        public T Data { get; set; }
        public BinaryTreeNode<T> Left { get; set; }
        public BinaryTreeNode<T> Right { get; set; }
        private bool _isLeaf;
        public bool IsLeaf
        {
            get
            {
                _isLeaf = (Left == null && Right == null);
                return _isLeaf;
            }
        }
        public BinaryTreeNode(string name, T data = default(T))
        {
            Name = name;
            Data = data;
        }
        public BinaryTreeNode<T> CreateAndJionLeft(string name, T data = default(T))
        {
            return Left = new BinaryTreeNode<T>(name, data);
        }
        public BinaryTreeNode<T> CreateAndJionRight(string name, T data = default(T))
        {
            return Right = new BinaryTreeNode<T>(name, data);
        }
    }

Name和Data是二叉樹內部元素,根據需求調整即可,CreateAndJionLeft表示將左邊子節點加入當前節點,也可在外部調用端實例化子節點。

 

接下來是二叉樹常用的幾種遍歷方式:前序遍歷,中序遍歷,后序遍歷,逐層遍歷

        /// <summary>
        /// 前序遍歷
        /// </summary>
        public void PreOrderTraversal()
        {
            if (this != null)
            {
                Trace.WriteLine(Name);
            }
            if (Left != null)
            {
                Left.PreOrderTraversal();
            }
            if (Right != null)
            {
                Right.PreOrderTraversal();
            }
        }
        /// <summary>
        /// 前序遍歷 非遞歸
        /// </summary>
        public void PreOrderTraversalEx()
        {
            Stack<BinaryTreeNode<T>> stack = new Stack<BinaryTreeNode<T>>();
            BinaryTreeNode<T> node = this;
            while (node != null || stack.Count != 0)
            {
                while (node != null)
                {
                    Trace.WriteLine(node.Name);
                    stack.Push(node);
                    node = node.Left;
                }
                if (stack.Count != 0)
                {
                    node = stack.Pop();
                    node = node.Right;
                }
            }
        }

        /// <summary>
        /// 中序遍歷
        /// </summary>
        public void InOrderTraversal()
        {
            if (Left != null)
            {
                Left.InOrderTraversal();
            }
            if (this != null)
            {
                Trace.WriteLine(Name);
            }
            if (Right != null)
            {
                Right.InOrderTraversal();
            }
        }
        /// <summary>
        /// 中序遍歷 非遞歸
        /// </summary>
        public void InOrderTraversalEx()
        {
            Stack<BinaryTreeNode<T>> stack = new Stack<BinaryTreeNode<T>>();
            BinaryTreeNode<T> node = this;
            while (node != null || stack.Count != 0)
            {
                while (node != null)
                {
                    stack.Push(node);
                    node = node.Left;
                }
                if (stack.Count != 0)
                {
                    node = stack.Peek();
                    stack.Pop();
                    Trace.WriteLine(node.Name);
                    node = node.Right;
                }
            }
        }

        /// <summary>
        /// 后序遍歷
        /// </summary>
        public void PostOrderTraversal()
        {
            if (Left != null)
            {
                Left.PostOrderTraversal();
            }
            if (Right != null)
            {
                Right.PostOrderTraversal();
            }
            if (this != null)
            {
                Trace.WriteLine(Name);
            }
        }
        /// <summary>
        /// 后序遍歷 非遞歸
        /// </summary>
        public void PostOrderTraversalEx()
        {
            Stack<BinaryTreeNode<T>> stack = new Stack<BinaryTreeNode<T>>();
            BinaryTreeNode<T> node = this;
            BinaryTreeNode<T> lastNode = null;
            stack.Push(node);
            while (stack.Count!=0)
            {
                node = stack.Peek();
                if ((node.Left == null && node.Right == null) || (lastNode != null && (lastNode == node.Left || lastNode == node.Right)))
                {
                    //如果當前結點沒有子結點或者子節點都已被訪問過就輸出  因為后序遍歷是先子節點再根節點
                    Trace.WriteLine(node.Name);
                    stack.Pop();
                    lastNode = node;//設定本次訪問的節點為上一次訪問的節點
                }
                else
                {
                    if (node.Right != null)
                        stack.Push(node.Right);
                    if (node.Left != null)
                        stack.Push(node.Left);
                }
            }
        }

        /// <summary>
        /// 逐層遍歷
        /// </summary>
        public void Traversal()
        {
            Stack<BinaryTreeNode<T>> stack = new Stack<BinaryTreeNode<T>>();
            stack.Push(this);
            while (stack.Count > 0)
            {
                BinaryTreeNode<T> temp = stack.Peek();
                Trace.WriteLine(temp.Name);
                stack.Pop();
                if (temp.Left != null)
                {
                    stack.Push(temp.Left);
                }
                if (temp.Right != null)
                {
                    stack.Push(temp.Right);
                }
            }
        }

 

遞歸實現反轉二叉樹

        /// <summary>
        /// 反轉二叉樹(遞歸)
        /// </summary>
        public BinaryTreeNode<T> ReverseWithRecursive()
        {
            if (this == null)
            {
                return null;
            }

            if (!(Left == null && Right == null))
            {
                BinaryTreeNode<T> temp = Right;//左右節點反轉
                Right = Left;
                Left = temp;

                if (Left != null)
                    Left = Left.ReverseWithRecursive();//遞歸反轉左子節點
                if (Right != null)
                    Right = Right.ReverseWithRecursive();//遞歸反轉右子節點
            }
            return this;
        }

 

非遞歸方式實現反轉二叉樹

     /// <summary>
        /// 反轉二叉樹(非遞歸)
        /// </summary>
        /// <returns></returns>
        public BinaryTreeNode<T> Reverse()
        {
            if (this == null)
            {
                return null;
            }

            Queue<BinaryTreeNode<T>> nodeQueue = new Queue<BinaryTreeNode<T>>();
            nodeQueue.Enqueue(this);
            while (nodeQueue.Count > 0)
            {
                BinaryTreeNode<T> node = nodeQueue.Peek();
                nodeQueue.Dequeue();

                BinaryTreeNode<T> tempNode = node.Right;//左右節點反轉
                node.Right = node.Left;
                node.Left = tempNode;

                if (node.Left != null)
                {
                    nodeQueue.Enqueue(node.Left);
                }
                if (node.Right != null)
                {
                    nodeQueue.Enqueue(node.Right);
                }
            }
            return this;
        }

定義一個隊列來臨時存儲即將反轉的節點。獲取隊列中存儲的節點,獲取到一個節點后隊列中的此節點已無用將其刪除,然后把獲取到的節點的左右子節點反轉,將反轉后的左右子節點都放入隊列用於下一次循環。重復執行直到反轉完所有樹節點。

 

換成棧存儲

        /// <summary>
        /// 反轉二叉樹(非遞歸) 棧
        /// </summary>
        /// <returns></returns>
        public BinaryTreeNode<T> ReverseEx()
        {
            if (this == null)
            {
                return null;
            }

            Stack<BinaryTreeNode<T>> nodeStack = new Stack<BinaryTreeNode<T>>();
            nodeStack.Push(this);
            while (nodeStack.Count > 0)
            {
                BinaryTreeNode<T> node = nodeStack.Peek();
                nodeStack.Pop();

                BinaryTreeNode<T> tempNode = node.Right;//左右節點反轉
                node.Right = node.Left;
                node.Left = tempNode;

                if (node.Left != null)
                {
                    nodeStack.Push(node.Left);
                }
                if (node.Right != null)
                {
                    nodeStack.Push(node.Right);
                }
            }
            return this;
        }

 

 

客戶端調用

            //創建二叉樹
            BinaryTreeNode<int> tree = new BinaryTreeNode<int>("0");//rootNode
            BinaryTreeNode<int> n01 = tree.CreateAndJionLeft("01");
            BinaryTreeNode<int> n02 = tree.CreateAndJionRight("02");
            BinaryTreeNode<int> n011 = n01.CreateAndJionLeft("011");
            BinaryTreeNode<int> n012 = n01.CreateAndJionRight("012");
            BinaryTreeNode<int> n021 = n02.CreateAndJionLeft("021");
            BinaryTreeNode<int> n0211 = n021.CreateAndJionLeft("0211");
            BinaryTreeNode<int> n0212 = n021.CreateAndJionRight("0212");

            //遍歷輸出
            tree.Traversal();

            //反轉二叉樹並遍歷輸出
            BinaryTreeNode<int> treeReverse = tree.Reverse();
            treeReverse.Traversal();

反轉前

 

反轉后

 

轉載請注明地址:http://www.cnblogs.com/wintersoft/p/4676124.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM