前一陣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