zoukankan      html  css  js  c++  java
  • 重拾算法(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 virtual void Traverse(TraverseOrder order, NodeWorker<T> worker)
      9         {
     10             if (worker == null) { return; }
     11 
     12             var left = this.Left;
     13             var right = this.Right;
     14             switch (order)
     15             {
     16             case TraverseOrder.Preorder:
     17                 /* recursive preorder traverse
     18                 worker.DoActionOnNode(this);
     19                 if (left != null) { Left.Traverse(order, worker); }
     20                 if (right != null) { Right.Traverse(order, worker); }
     21                 */
     22                 PreorderTraverse(worker);
     23                 break;
     24             case TraverseOrder.Inorder:
     25                 /* recursive inorder traverse
     26                 if (left != null) { Left.Traverse(order, worker); }
     27                 worker.DoActionOnNode(this);
     28                 if (right != null) { Right.Traverse(order, worker); }
     29                 */
     30                 InorderTraverse(worker);
     31                 break;
     32             case TraverseOrder.Postorder:
     33                 /* recursive postorder traverse
     34                 if (left != null) { Left.Traverse(order, worker); }
     35                 if (right != null) { Right.Traverse(order, worker); }
     36                 worker.DoActionOnNode(this);
     37                 */
     38                 PostorderTraverse(worker);
     39                 break;
     40             default:
     41                 break;
     42             }
     43         }
     44         
     45         void PreorderTraverse(NodeWorker<T> worker)
     46         {
     47             var stack = new Stack<BinaryTreeNode<T>>();
     48             stack.Push(this); 
     49             
     50             while (stack.Count > 0)
     51             {
     52                 var node = stack.Pop(); 
     53                 //if (node == null) { continue; }
     54                 //else
     55                 {
     56                     var right = node.Right;
     57                     var left = node.Left;
     58                     worker.DoActionOnNode(node);
     59                     if (right != null) { stack.Push(right); }
     60                     if (left != null) { stack.Push(left); }
     61                 }
     62             }
     63         }        
     64         /* This works fine and is better for tuition. The code above is an optimized version.
     65         void PreorderTraverse(NodeWorker<T> worker)
     66         {
     67             var stack = new Stack<BinaryTreeNode<T>>(); var stackReady4Visit = new Stack<bool>();
     68             
     69             stack.Push(this); stackReady4Visit.Push(false);
     70             
     71             while (stack.Count > 0)
     72             {
     73                 var node = stack.Pop(); var ready4Visit = stackReady4Visit.Pop();
     74                 //if (node == null) { continue; }
     75                 if (ready4Visit)
     76                 {
     77                     worker.DoActionOnNode(node);
     78                 }
     79                 else
     80                 {
     81                     var right = node.Right;
     82                     var left = node.Left;
     83                     if (right != null) { stack.Push(right); stackReady4Visit.Push(false); }
     84                     if (left != null) { stack.Push(left); stackReady4Visit.Push(false); }
     85                     stack.Push(node); stackReady4Visit.Push(true);
     86                 }
     87             }
     88         }
     89         */
     90         
     91         void InorderTraverse(NodeWorker<T> worker)
     92         {
     93             var stack = new Stack<BinaryTreeNode<T>>(); var stackReady4Visit = new Stack<bool>();
     94             
     95             stack.Push(this); stackReady4Visit.Push(false);
     96             
     97             while (stack.Count > 0)
     98             {
     99                 var node = stack.Pop(); var ready4Visit = stackReady4Visit.Pop();
    100                 //if (node == null) { continue; }
    101                 if (ready4Visit)
    102                 {
    103                     worker.DoActionOnNode(node);
    104                 }
    105                 else
    106                 {
    107                     var right = node.Right;
    108                     var left = node.Left;
    109                     if (right != null) { stack.Push(right); stackReady4Visit.Push(false); }
    110                     stack.Push(node); stackReady4Visit.Push(true);
    111                     if (left != null) { stack.Push(left); stackReady4Visit.Push(false); }
    112                 }
    113             }
    114         }
    115         
    116         void PostorderTraverse(NodeWorker<T> worker)
    117         {
    118             var stack = new Stack<BinaryTreeNode<T>>(); var stackReady4Visit = new Stack<bool>();
    119             
    120             stack.Push(this); stackReady4Visit.Push(false);
    121             
    122             while (stack.Count > 0)
    123             {
    124                 var node = stack.Pop(); var ready4Visit = stackReady4Visit.Pop();
    125                 //if (node == null) { continue; }
    126                 if (ready4Visit)
    127                 {
    128                     worker.DoActionOnNode(node);
    129                 }
    130                 else
    131                 {
    132                     var right = node.Right;
    133                     var left = node.Left;
    134                     stack.Push(node); stackReady4Visit.Push(true);
    135                     if (right != null) { stack.Push(right); stackReady4Visit.Push(false); }
    136                     if (left != null) { stack.Push(left); stackReady4Visit.Push(false); }
    137                 }
    138             }
    139         }
    140     }
    141     public abstract class NodeWorker<T>
    142     {
    143         public abstract void DoActionOnNode(BinaryTreeNode<T> node);
    144     }
    前中后序遍历二叉树

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

    层次遍历

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

     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(TraverseOrder order, NodeWorker<T> worker)
    10         {
    11             if (worker == 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, worker);
    19                 break;
    20             case TraverseOrder.Inorder:
    21                 node.Traverse(order, worker);
    22                 break;
    23             case TraverseOrder.Postorder:
    24                 node.Traverse(order, worker);
    25                 break;
    26             case TraverseOrder.Layer:
    27                 TraverseLayer(worker);
    28                 break;
    29             default:
    30                 break;
    31             }
    32         }
    33         
    34         private void TraverseLayer(NodeWorker<T> worker)
    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                     worker.DoActionOnNode(element);
    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<T>();
     8             this.Traverse(TraverseOrder.Preorder, counter);
     9             return counter.Count;
    10         }
    11         
    12         public int GetLeaveCount()
    13         {
    14             var counter = new LeaveCounter<T>();
    15             this.Traverse(TraverseOrder.Preorder, counter);
    16             return counter.Count;
    17         }
    18         
    19         public int GetNonLeaveCount()
    20         {
    21             var counter = new NonLeaveCounter<T>();
    22             this.Traverse(TraverseOrder.Preorder, counter);
    23             return counter.Count;
    24         }
    25     }
    26     
    27     class NonLeaveCounter<T> : NodeWorker<T>
    28     {
    29         public int Count { get;set; }
    30         public override void DoActionOnNode(BinaryTreeNode<T> node)
    31         {
    32             if (node != null)
    33             {
    34                 if (node.Left != null || node.Right != null)
    35                 {
    36                     this.Count++;
    37                 }
    38             }
    39         }
    40     }
    41     
    42     class LeaveCounter<T> : NodeWorker<T>
    43     {
    44         public int Count { get;set; }
    45         public override void DoActionOnNode(BinaryTreeNode<T> node)
    46         {
    47             if (node != null)
    48             {
    49                 if (node.Left == null && node.Right == null)
    50                 {
    51                     this.Count++;
    52                 }
    53             }
    54         }
    55     }
    56     
    57     class NodeCounter<T> : NodeWorker<T>
    58     {
    59         public int Count { get;set; }
    60         public override void DoActionOnNode(BinaryTreeNode<T> node)
    61         {
    62             if (node != null)
    63             {
    64                 this.Count++;
    65             }
    66         }
    67     }
    获取结点数、叶结点数、非叶结点数
  • 相关阅读:
    C# 网络编程之基于SMTP发送电子邮件
    C#实现邮件发送的功能
    Java发邮件基础篇
    java发送邮件高级篇
    Windows下bat脚本自动发邮件
    Python发送QQ邮件
    信息系统项目管理师EV、PV、AC、BAC、CV、SV、EAC、ETC、CPI、SPI概念说明
    DOS命令整理
    JAVA对时间的操作
    JAVA 调用HTTP接口POST或GET实现方式(转)
  • 原文地址:https://www.cnblogs.com/bitzhuwei/p/algorithm-1-non-recursive-traverse-binary-tree.html
Copyright © 2011-2022 走看看