码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2014-07-18 19:12:44      阅读:280      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   strong   os   

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

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

前中后序遍历二叉树

bubuko.com,布布扣
  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 = 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                 else
111                 {
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     }
遍历二叉树

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

 

层次遍历

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

bubuko.com,布布扣
 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方法实现其他功能

bubuko.com,布布扣
 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 NonLeaveCounter
54     {
55         public int Count { get;set; }
56     }
57     
58     class LeaveCounter
59     {
60         public int Count { get;set; }
61     }
62     
63     class NodeCounter
64     {
65         public int Count { get;set; }
66     }
获取结点数、叶结点数、非叶结点数

重拾算法(1)——优雅地非递归遍历二叉树及其它,布布扣,bubuko.com

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

标签:style   blog   http   color   strong   os   

原文地址:http://www.cnblogs.com/bitzhuwei/p/algorithm-1-non-recursive-traverse-binary-tree.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!