zoukankan      html  css  js  c++  java
  • 数据结构之二叉树遍历与深度计算

         刚刚辞职交接完毕,话说有家公司给我打了n次电话想让我去,但是薪水问题没有谈拢,薪水不低,但是没达到我的期望,开发的项目俺还是蛮喜欢的,可惜了~~~~~
         准备找新工作中,想起好多公司有考数据结构的习惯,于是复习了下,链表比较简单,一会翻看完了。但是二叉树这里让我稍稍郁闷了下。
         二叉树的遍历是基础,包括先序遍历,中序遍历和后续遍历。自己写了程序才发现好多知识都不记得了,才发现原来三种遍历都是同样的算法,不同在于操作节点的位置不同,代码是递归的,等有时间再写非递归的吧。
    要想遍历二叉树必须有先初始化一个二叉树,以下是代码,不必多说,比C看起来容易理解多了,首先是Node类(节点),这个可是基础呃~~~
        class Node
        {
            
    private Node _leftChildNode;//左子树
            private Node _rightChildNode;//右子树
            private string _vlaue;//节点值

            
    public Node LeftChildNode
            {
                
    get { return _leftChildNode; }
                
    set { _leftChildNode = value; }
            }

            
    public Node RightChildNode
            {
                
    get { return _rightChildNode; }
                
    set { _rightChildNode = value; }
            }

            
    public string Value
            {
                
    get { return _vlaue; }
            }

            
    public Node(string value)
            {
                _vlaue 
    = value;
            }
        }
    有了节点就来初始化二叉树吧。go go go~~
            static void InitBinaryTree(Node root)
            {
                Node nodePlus 
    = new Node("+");
                Node nodeMod 
    = new Node("/");
                Node nodeA 
    = new Node("a");
                Node nodeMultiply 
    = new Node("*");
                Node nodeE 
    = new Node("e");
                Node nodeF 
    = new Node("f");
                Node nodeB 
    = new Node("b");
                Node nodeSub 
    = new Node("-");
                Node nodeC 
    = new Node("c");
                Node nodeD 
    = new Node("d");
                root.LeftChildNode 
    = nodePlus;
                root.RightChildNode 
    = nodeMod;
                nodePlus.LeftChildNode 
    = nodeA;
                nodePlus.RightChildNode 
    = nodeMultiply;
                nodeMod.LeftChildNode 
    = nodeE;
                nodeMod.RightChildNode 
    = nodeF;
                nodeMultiply.LeftChildNode 
    = nodeB;
                nodeMultiply.RightChildNode 
    = nodeSub;
                nodeSub.LeftChildNode 
    = nodeC;
                nodeSub.RightChildNode 
    = nodeD;
            }
    OK,数据源有了,现在就来上主菜,遍历二叉树喽~
    采用递归方式写一个方法,需求如下:
    遍历二叉树的话首先要传入根节点
    1)如果节点为空则返回
    2)如果节点不为空,调用方法本身分别遍历左子树和右子树。
    3)先序遍历在传入的node后并且node不为空时操作(本例中是输出node的Value值)。
    判断node是否为空
    Do operation here.
    遍历左子树
    遍历右子树
    4)中序遍历在遍历左子树后操作。
    判断node是否为空
    遍历左子树
    Do operation here.
    遍历右子树
    5)后序遍历在遍历右子树后操作。
    判断node是否为空
    遍历左子树
    遍历右子树
    Do operation here.
    还是看代码吧,有的时候代码比描述更重要,吼吼~~~~
            static void TraversalBinaryTree(Node node, TraversalType traversalType)
            {
                
    if (node != null)
                {
                    
    if (traversalType == TraversalType.TT_First)
                    {
                        Console.WriteLine(node.Value);
                    }
                    TraversalBinaryTree(node.LeftChildNode, traversalType);
                    
    if (traversalType == TraversalType.TT_Middle)
                    {
                        Console.WriteLine(node.Value);
                    }
                    TraversalBinaryTree(node.RightChildNode, traversalType);
                    
    if (traversalType == TraversalType.TT_Last)
                    {
                        Console.WriteLine(node.Value);
                    }
                    
    return;
                }
                
    else
                {
                    
    return;
                }
            }
    方法的参数有些特殊,除了Node外还有个TraversalType,这个就是我们三种遍历方式的标志了,同样按照惯例被声明为了enum类型。
            enum TraversalType
            {
                TT_First 
    = 1, TT_Middle, TT_Last
            }
    OK,二叉树的遍历代码完成,剩下的就需要写测试代码了,别急,我们还有获得二叉树深度的方法没写那,放在一起测试吧,呵呵。
    怎么获得二叉树的深度那,这个有点麻烦了,不是一下就可以看出来的,不过对于递归方法来说有个原则是百试不爽的,那就是把具体问题抽象成“数学公式”。有一个基本规律,那就是下层深度是其上层深度+1。(智商没问题的都应该清楚吧,呵呵~~~~~)
    1)同样使用递归,首先判断node是否为null,如果是null返回0,也就是说二叉树是空的,深度为0。
    2)如果左子树为空,右子树不为空,也就是说该节点有下层,而下层深度是该深度+1。
    3)如果左子树不为空,右子树为空,同样该节点有下层,而下层深度是该深度+1。
    4)如果左子树不为空,右子树也不为空,那么就需要比较左子树和右子树的深度,哪个深度大取哪个。
    抽象成数学公式为:
                                          GetDeep(node.RightChildNode) + 1  (node.LeftChildNode == null && node.RightChildNode != null)
    GetDeep(Node node)= {  GetDeep(node.LeftChildNode) + 1    (node.LeftChildNode != null && node.RightChildNode == null)
                                          Max(GetDeep(node.LeftChildNode),GetDeep(node.RightChildNode)) + 1
                                                                                (node.LeftChildNode != null && node.RightChildNode != null)
                                              1                                                   (其他情况)
    具体代码如下:
            static int GetDeep(Node node)
            {
                
    if (node != null)
                {
                    
    if (node.LeftChildNode == null && node.RightChildNode != null)
                    {
                        
    return GetDeep(node.RightChildNode) + 1;
                    }
                    
    else if (node.LeftChildNode != null && node.RightChildNode == null)
                    {
                        
    return GetDeep(node.LeftChildNode) + 1;
                    }
                    
    else if (node.LeftChildNode != null && node.RightChildNode != null)
                    {
                        
    int left = GetDeep(node.LeftChildNode);
                        
    int right = GetDeep(node.RightChildNode);
                        
    return (left > right ? left : right) + 1;
                    }
                    
    else
                    {
                        
    return 1;
                    }
                }
                
    else
                {
                    
    return 0;
                }
            }
    OK,到这里我们需要的东西都完成了,下面就该测试了,下面是完整代码:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.InteropServices;

    namespace BinaryTree
    {
        
    class Program
        {
            
    static int left = 0;
            
    static int right = 0;

            
    static void Main(string[] args)
            {
                Node root 
    = new Node("#");
                InitBinaryTree(root);
                
    do
                {
                    Console.WriteLine();
                    Console.WriteLine(
    "Please input the type of Tranversal.\n1:First\n2:Middle\n3:Last");
                    
    string input = Console.ReadLine();
                    
    int travertalType;
                    
    if (int.TryParse(input, out travertalType))
                    {
                        TraversalBinaryTree(root, (TraversalType)travertalType);
                        
    int deep = GetDeep(root);
                        Console.WriteLine(String.Format(
    "Deep is {0}.", deep));
                        Console.WriteLine(
    "OK,press any key to continue.\nEsc:Quit");
                    }
                    
    else
                    {
                        Console.WriteLine(
    "Input Error.press any key to continue.\nEsc:Quit");
                    }
                } 
    while (Console.ReadKey().Key != ConsoleKey.Escape);
            }

            
    static void InitBinaryTree(Node root)
            {
                Node nodePlus 
    = new Node("+");
                Node nodeMod 
    = new Node("/");
                Node nodeA 
    = new Node("a");
                Node nodeMultiply 
    = new Node("*");
                Node nodeE 
    = new Node("e");
                Node nodeF 
    = new Node("f");
                Node nodeB 
    = new Node("b");
                Node nodeSub 
    = new Node("-");
                Node nodeC 
    = new Node("c");
                Node nodeD 
    = new Node("d");
                root.LeftChildNode 
    = nodePlus;
                root.RightChildNode 
    = nodeMod;
                nodePlus.LeftChildNode 
    = nodeA;
                nodePlus.RightChildNode 
    = nodeMultiply;
                nodeMod.LeftChildNode 
    = nodeE;
                nodeMod.RightChildNode 
    = nodeF;
                nodeMultiply.LeftChildNode 
    = nodeB;
                nodeMultiply.RightChildNode 
    = nodeSub;
                nodeSub.LeftChildNode 
    = nodeC;
                nodeSub.RightChildNode 
    = nodeD;
            }

            
    static void TraversalBinaryTree(Node node, TraversalType traversalType)
            {
                
    if (node != null)
                {
                    
    if (traversalType == TraversalType.TT_First)
                    {
                        Console.WriteLine(node.Value);
                    }
                    TraversalBinaryTree(node.LeftChildNode, traversalType);
                    
    if (traversalType == TraversalType.TT_Middle)
                    {
                        Console.WriteLine(node.Value);
                    }
                    TraversalBinaryTree(node.RightChildNode, traversalType);
                    
    if (traversalType == TraversalType.TT_Last)
                    {
                        Console.WriteLine(node.Value);
                    }
                    
    return;
                }
                
    else
                {
                    
    return;
                }
            }

            
    static int GetDeep(Node node)
            {
                
    if (node != null)
                {
                    
    if (node.LeftChildNode == null && node.RightChildNode != null)
                    {
                        
    return GetDeep(node.RightChildNode) + 1;
                    }
                    
    else if (node.LeftChildNode != null && node.RightChildNode == null)
                    {
                        
    return GetDeep(node.LeftChildNode) + 1;
                    }
                    
    else if (node.LeftChildNode != null && node.RightChildNode != null)
                    {
                        
    int left = GetDeep(node.LeftChildNode);
                        
    int right = GetDeep(node.RightChildNode);
                        
    return (left > right ? left : right) + 1;
                    }
                    
    else
                    {
                        
    return 1;
                    }
                }
                
    else
                {
                    
    return 0;
                }
            }

            
    enum TraversalType
            {
                TT_First 
    = 1, TT_Middle, TT_Last
            }
        }

        
    class Node
        {
            
    private Node _leftChildNode;
            
    private Node _rightChildNode;
            
    private string _vlaue;

            
    public Node LeftChildNode
            {
                
    get { return _leftChildNode; }
                
    set { _leftChildNode = value; }
            }

            
    public Node RightChildNode
            {
                
    get { return _rightChildNode; }
                
    set { _rightChildNode = value; }
            }

            
    public string Value
            {
                
    get { return _vlaue; }
            }

            
    public Node(string value)
            {
                _vlaue 
    = value;
            }
        }
    }
    测试结果如下:)

    经过分析后发现条件判断有写罗嗦了,实际可以合并,合并后的GetDeep方法如下:
            static int GetDeep(Node node)
            {
                
    if (node != null)
                {
                    
    //if (node.LeftChildNode != null && node.RightChildNode == null)
                    
    //{
                    
    //    return GetDeep(node.LeftChildNode) + 1;
                    
    //}
                    
    //else if (node.RightChildNode != null && node.LeftChildNode == null)
                    
    //{
                    
    //    return GetDeep(node.RightChildNode) + 1;
                    
    //}
                    
    //else if (node.RightChildNode != null && node.LeftChildNode != null)
                    
    //{
                    
    //    int left = GetDeep(node.LeftChildNode);
                    
    //    int right = GetDeep(node.RightChildNode);
                    
    //    return (left > right ? left : right) + 1;
                    
    //}
                    
    //else
                    
    //{
                    
    //    return 1;
                    
    //}
                    int left = GetDeep(node.LeftChildNode);
                    
    int right = GetDeep(node.RightChildNode);
                    
    return (left > right ? left : right) + 1;
                }
                
    else
                {
                    
    return 0;
                }
            }
    敬告

    作者:pangxiaoliang
    出处:http://www.cnblogs.com/pangxiaoliang
    本文版权归pangxiaoliang和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,谢谢合作。
  • 相关阅读:
    IOS Date, NSDateFormatter, compare, dateFromString:mydatestr
    IOS Retain,nil,alloc,init
    IOS NSArray,NSDictionary
    object c基础, 基本类型(NSString,char*NSDate,NSData),集合NSArray,NSMutableArray,NSDictionary,NSMutableDictionary,NSSet,NSMutableSet
    IOS UIProgressView 用法
    UIButton 用法
    XCode 快捷键,MAC 快捷键
    苹果软件系列产品介绍
    android 之多线程应用[message,messagequeue,handler,looper,asynchtask]
    Linux查看程序被哪个端口占用
  • 原文地址:https://www.cnblogs.com/pangxiaoliang/p/1547011.html
Copyright © 2011-2022 走看看