首页 > 代码库 > 重拾算法(1)——优雅地非递归遍历二叉树及其它

重拾算法(1)——优雅地非递归遍历二叉树及其它

重拾算法(1)——优雅地非递归遍历二叉树及其它

本文中非递归遍历二叉树的思想和代码都来自这里(http://jianshu.io/p/49c8cfd07410#)。我认为其思想和代码都足够优雅动人了,于是稍作整理,得到如下的程序。

前中后序遍历二叉树

  1     public class BinaryTreeNode<T>  2     {  3         public T Value { get;set; }  4         public BinaryTreeNode<T> Parent { get;set; }  5         public BinaryTreeNode<T> Left { get;set; }  6         public BinaryTreeNode<T> Right { get;set; }  7           8         public BinaryTreeNode(T value, BinaryTreeNode<T> parent = null, BinaryTreeNode<T> left = null, BinaryTreeNode<T> right = null)  9         { 10             this.Value = http://www.mamicode.com/value; this.Left = left; this.Right = right; 11         } 12          13         public virtual void Traverse<T1>(TraverseOrder order, Action<BinaryTreeNode<T>, T1> actionOnNode, T1 sender) 14         { 15             if (actionOnNode == null) { return; } 16  17             var left = this.Left; 18             var right = this.Right; 19             switch (order) 20             { 21             case TraverseOrder.Preorder: 22                 /* recursive preorder traverse 23                 actionOnNode(this, sender); 24                 if (left != null) { Left.Traverse(order, actionOnNode, sender); } 25                 if (right != null) { Right.Traverse(order, actionOnNode, sender); } 26                 */ 27                 PreorderTraverse(actionOnNode, sender); 28                 break; 29             case TraverseOrder.Inorder: 30                 /* recursive inorder traverse 31                 if (left != null) { Left.Traverse(order, actionOnNode, sender); } 32                 actionOnNode(this, sender); 33                 if (right != null) { Right.Traverse(order, actionOnNode, sender); } 34                 */ 35                 InorderTraverse(actionOnNode, sender); 36                 break; 37             case TraverseOrder.Postorder: 38                 /* recursive postorder traverse 39                 if (left != null) { Left.Traverse(order, actionOnNode, sender); } 40                 if (right != null) { Right.Traverse(order, actionOnNode, sender); } 41                 actionOnNode(this, sender); 42                 */ 43                 PostorderTraverse(actionOnNode, sender); 44                 break; 45             default: 46                 break; 47             } 48         } 49          50         void PreorderTraverse<T1>(Action<BinaryTreeNode<T>, T1> actionOnNode, T1 sender) 51         { 52             var stack = new Stack<BinaryTreeNode<T>>(); var stackReady4Visit = new Stack<bool>(); 53              54             stack.Push(this); stackReady4Visit.Push(false); 55              56             while (stack.Count > 0) 57             { 58                 var node = stack.Pop(); var ready4Visit = stackReady4Visit.Pop(); 59                 if (node == null) { continue; } 60                 if (ready4Visit) 61                 { 62                     actionOnNode(node, sender); 63                 } 64                 else 65                 { 66                     stack.Push(node.Right); stackReady4Visit.Push(false); 67                     stack.Push(node.Left); stackReady4Visit.Push(false); 68                     stack.Push(node); stackReady4Visit.Push(true); 69                 } 70             } 71         } 72          73         void InorderTraverse<T1>(Action<BinaryTreeNode<T>, T1> actionOnNode, T1 sender) 74         { 75             var stack = new Stack<BinaryTreeNode<T>>(); var stackReady4Visit = new Stack<bool>(); 76              77             stack.Push(this); stackReady4Visit.Push(false); 78              79             while (stack.Count > 0) 80             { 81                 var node = stack.Pop(); var ready4Visit = stackReady4Visit.Pop(); 82                 if (node == null) { continue; } 83                 if (ready4Visit) 84                 { 85                     actionOnNode(node, sender); 86                 } 87                 else 88                 { 89                     stack.Push(node.Right); stackReady4Visit.Push(false); 90                     stack.Push(node); stackReady4Visit.Push(true); 91                     stack.Push(node.Left); stackReady4Visit.Push(false); 92                 } 93             } 94         } 95          96         void PostorderTraverse<T1>(Action<BinaryTreeNode<T>, T1> actionOnNode, T1 sender) 97         { 98             var stack = new Stack<BinaryTreeNode<T>>(); var stackReady4Visit = new Stack<bool>(); 99             100             stack.Push(this); stackReady4Visit.Push(false);101             102             while (stack.Count > 0)103             {104                 var node = stack.Pop(); var ready4Visit = stackReady4Visit.Pop();105                 if (node == null) { continue; }106                 if (ready4Visit)107                 {108                     actionOnNode(node, sender);109                 }110                 else111                 {112                     stack.Push(node); stackReady4Visit.Push(true);113                     stack.Push(node.Right); stackReady4Visit.Push(false);114                     stack.Push(node.Left); stackReady4Visit.Push(false);115                 }116             }117         }118     }
遍历二叉树

以上三种遍历实现代码行数一模一样,如同递归遍历一样,只有三行核心代码的先后顺序有区别。用原作者的话解释就是:"得以统一三种更简单的非递归遍历方法的基本思想:有重合元素的局部有序一定能导致整体有序。基于这种思想,我就构思三种非递归遍历的统一思想:不管是前序,中序,后序,只要我能保证对每个结点而言,该结点,其左子结点,其右子结点都满足以前序/中序/后序的访问顺序,整个二叉树的这种三结点局部有序一定能保证整体以前序/中序/后序访问,因为相邻的局部必有重合的结点,即一个局部的"根"结点是另外一个局部的"子"结点。"。

 

层次遍历

层次遍历类似图的广度优先搜索。

 1     public class BinaryTree<T> 2     { 3         BinaryTreeNode<T> Node { get;set; } 4         public BinaryTree(BinaryTreeNode<T> node) 5         { 6             this.Node = node; 7         } 8          9         public void Traverse<T1>(TraverseOrder order, Action<BinaryTreeNode<T>, T1> actionOnNode, T1 sender)10         {11             if (actionOnNode == null) { return; }12             var node = this.Node;13             if (node == null) { return; }14             15             switch (order)16             {17             case TraverseOrder.Preorder:18                 node.Traverse(order, actionOnNode, sender);19                 break;20             case TraverseOrder.Inorder:21                 node.Traverse(order, actionOnNode, sender);22                 break;23             case TraverseOrder.Postorder:24                 node.Traverse(order, actionOnNode, sender);25                 break;26             case TraverseOrder.Layer:27                 TraverseLayer<T1>( actionOnNode, sender);28                 break;29             default:30                 break;31             }32         }33         34         private void TraverseLayer<T1>(Action<BinaryTreeNode<T>, T1> actionOnNode, T1 sender)35         {36             var queue = new Queue<BinaryTreeNode<T>>();37             queue.Enqueue(this.Node);38             while (queue.Count > 0)39             {40                 var element = queue.Dequeue();41                 if (element != null)42                 {43                     actionOnNode(element, sender);44                     var left = element.Left;45                     var right = element.Right;46                     if (left != null) { queue.Enqueue(left); }47                     if (right != null) { queue.Enqueue(right); }48                 }49             }50         }51     }
层次遍历

 

借用Traverse方法实现其他功能

 1     public class BinaryTree<T> 2     { 3         /**/ 4          5         public int GetNodeCount() 6         { 7             var counter = new NodeCounter(); 8             this.Traverse<NodeCounter>(TraverseOrder.Preorder, actNodeCount, counter); 9             return counter.Count;10         }11         12         static Action<BinaryTreeNode<T>, NodeCounter> actNodeCount = new Action<BinaryTreeNode<T>, NodeCounter>((node, c) => c.Count++);13         14         public int GetLeaveCount()15         {16             var counter = new LeaveCounter();17             this.Traverse<LeaveCounter>(TraverseOrder.Preorder, actLeaveCount, counter);18             return counter.Count;19         }20         21         static Action<BinaryTreeNode<T>, LeaveCounter> actLeaveCount = new Action<BinaryTreeNode<T>, LeaveCounter>(22             (node, c) => 23             {24                 if (node != null)25                 {26                     if (node.Left == null && node.Right == null)27                     {28                         c.Count++;29                     }30                 }31             });32         33         public int GetNonLeaveCount()34         {35             var counter = new NonLeaveCounter();36             this.Traverse<NonLeaveCounter>(TraverseOrder.Preorder, actNonLeaveCount, counter);37             return counter.Count;38         }39         40         static Action<BinaryTreeNode<T>, NonLeaveCounter> actNonLeaveCount = new Action<BinaryTreeNode<T>, NonLeaveCounter>(41             (node, c) => 42             {43                 if (node != null)44                 {45                     if (node.Left != null || node.Right != null)46                     {47                         c.Count++;48                     }49                 }50             });51     }52     53     class NonLeaveCounter54     {55         public int Count { get;set; }56     }57     58     class LeaveCounter59     {60         public int Count { get;set; }61     }62     63     class NodeCounter64     {65         public int Count { get;set; }66     }
获取结点数、叶结点数、非叶结点数