【数据结构】【C#】027-二叉树(BT):🌱创建,遍历(非递归)

遍历的实现

上一篇记录了二叉树的四种遍历:先序,中序,后序,层序;
有递归实现,也有非递归,递归比较简单,主要探讨非递归做法

使用C#语言实现相关算法


二叉树的数据节点定义:

/// <summary>
/// 二叉树节点
/// </summary>
/// <typeparam name="T"></typeparam>
public class TreeNode<T>
{
    T data;//数据域
    TreeNode<T> left; //左孩子
    TreeNode<T> right;//右孩子

    public T Data
    {
        get
        {
            return data;
        }

        set
        {
            data = value;
        }
    }

    public TreeNode<T> Left
    {
        get
        {
            return left;
        }

        set
        {
            left = value;
        }
    }

    public TreeNode<T> Right
    {
        get
        {
            return right;
        }

        set
        {
            right = value;
        }
    }
    

    public TreeNode(T _data, TreeNode<T> _left, TreeNode<T> _right)
    {
        this.data = _data;
        this.left = _left;
        this.right = _right;
    }

    public TreeNode(T _data) : this(_data, null, null)
    {

    }

    //设置 左右孩子
    public void SetLRChild(TreeNode<T> _left, TreeNode<T> _right)
    {
        this.left = _left;
        this.right = _right;
    }

    //设置 左孩子
    public void SetLChild(TreeNode<T> _left)
    {
        this.left = _left;
    }

    //设置 右孩子
    public void SetRChild(TreeNode<T> _right)
    {
        this.right = _right;
    }
}

创建,四种遍历(非递归)操作:

public class BinTree<T>
{
   private static string output;

    private static void VisitNode(TreeNode<T> node)
    {
        output += node.Data.ToString() + " ";
    }

    public static void DisPlayOutPut()
    {
        Debug.Log(output);
        output = string.Empty;
    }//显示遍历结果

0、创建二叉树

将形如:"{3,1,#,2,#,#,4}"字符串 string转换为 int 类型的 二叉树

/// <summary>
    /// 创建二叉树 ;eg {3,1,#,2,#,#,4}
    /// </summary>
    /// <param name="s"></param>
    /// <returns></returns>
    public static TreeNode<int> StringToBinaryTree (string s)
    {
        string[] tokens = s.TrimEnd('}').TrimStart('{').Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToArray();
        if(tokens.Length==0)
        {
            return null;
        }
        TreeNode<int> rootNode;
        rootNode = tokens[0] == "#" ? null : new TreeNode<int>(int.Parse(tokens[0]));

        Queue<TreeNode<int>> q = new Queue<TreeNode<int>>();
        q.Enqueue(rootNode);

        int index = 1;
        while(index<tokens.Length)
        {
            var t = q.Dequeue();
            if(tokens[index]!="#")
            {
                t.Left = new TreeNode<int>(int.Parse(tokens[index]));
                q.Enqueue(t.Left);
            }
            index++;

            if (index < tokens.Length && tokens[index] != "#")
            {
                t.Right = new TreeNode<int>(int.Parse(tokens[index]));
                q.Enqueue(t.Right);
            }
            index++;

        }
        return rootNode;
    }

    //非递归:

1、先序遍历(非递归):

在第1次碰到节点,入栈S.Push(node);前访问即可
    /// <summary>
    /// 先序遍历
    /// </summary>
    /// <param name="root"></param>
    public static void PreOrderTraversal(TreeNode<T> rootNode)
    {
        TreeNode<T> node = rootNode;

        LinkStack<TreeNode<T>> S = new LinkStack<TreeNode<T>>();//使用了自己定义的链栈
        //Stack<TreeNode<T>> S = new Stack<TreeNode<T>>(); //系统提供的

        while (node != null || !S.IsEmpty())
        {
            while (node != null)
            {
                VisitNode(node); //访问该节点

                S.Push(node);
                node = node.Left;
            }
            if (!S.IsEmpty())
            {
                node = S.Pop();
                node = node.Right;
            }
        }
       
    }

中序遍历(非递归):

在第2次碰到节点,出栈S.Pop(node);后访问即可
    /// <summary>
    /// 中序遍历
    /// </summary>
    /// <param name="rootNode"></param>
    public static void InOrderTraversal(TreeNode<T> rootNode)
    {
        TreeNode<T> node = rootNode;

        LinkStack<TreeNode<T>> S = new LinkStack<TreeNode<T>>();//使用了自己定义的链栈
        
        while (node != null || !S.IsEmpty())
        {
            while (node != null)
            {
                S.Push(node);
                node = node.Left;
            }
            if (!S.IsEmpty())
            {
                node = S.Pop();
                VisitNode(node); //访问该节点
                node = node.Right;
            }
        }
    }

后序遍历(重点)(非递归):

后序的非递归实现较难点,使用双栈,其中一栈为 输出栈OutStack:专门在最后输出访问节点
将节点 入两栈后,转向去访问右孩子 :node = node.Right;
将节点出栈后,转向去访问左孩子:node = node.Left;
上面两条与前中序的非递归有所不同
最后完全出完OutStack栈,便得到后序遍历结果
    /// <summary>
    /// 后序遍历:(重点)
    /// 
    /// 使用 : 双栈法
    /// </summary>
    /// <param name="rootNode"></param>
    public static void PostOrderTraversal(TreeNode<T> rootNode)
    {
        TreeNode<T> node = rootNode;

        LinkStack<TreeNode<T>> S = new LinkStack<TreeNode<T>>();//使用了自己定义的链栈
        //Stack<TreeNode<T>> S = new Stack<TreeNode<T>>(); //系统提供的

        LinkStack<TreeNode<T>> OutStack = new LinkStack<TreeNode<T>>();//使用了自己定义的链栈
        //Stack<TreeNode<T>> OutStack = new Stack<TreeNode<T>>();//系统提供的

        while (node != null || !S.IsEmpty())
        {
            while (node != null)
            {
                S.Push(node); //入栈
                OutStack.Push(node); //入输出栈
                node = node.Right; //右孩子
            }

            if (!S.IsEmpty())
            {
                node = S.Pop();
                node = node.Left; //左孩子
            }
        }

         while (OutStack.Count > 0)
        {
            TreeNode<T> outNode = OutStack.Pop();
            VisitNode(outNode); //访问该节点
        }
    }

层序遍历(重点)(非递归):

利用 变量 deepth 记录当前遍历的层次
利用 变量 levelNodesCount 当前遍历的层的节点总数
    /// <summary>
    /// 层序遍历:(重点)
    /// 使用 :队列
    /// </summary>
    /// <param name="rootNode"></param>
    public static void LayerOrderTraversal(TreeNode<T> rootNode)
    {
       if (rootNode == null) return; //若是空树,直接返回

        LinkQueue<TreeNode<T>> queue = new LinkQueue<TreeNode<T>>();   //创建队列,使用自定义的链队列   
        //Queue<TreeNode<T>> queue;//系统提供的

        int deepth = 0;//记录当前遍历层次

        int levelNodesCount = 0; //当前遍历的层的节点总数

        TreeNode<T> outNode; 

        queue.Enqueue(rootNode);

        while (!queue.IsEmpty())
        {
            ++deepth; //(此题不使用)

            levelNodesCount = queue.Count; 

            for (int i = 0; i < levelNodesCount; ++i)
            {
                outNode = queue.Dequeue(); //出队 

                VisitNode(outNode); //访问该节点

                //若输出节点,左右孩子不空,依次入队
                if (outNode.Left != null) queue.Enqueue(outNode.Left);
                if (outNode.Right != null) queue.Enqueue(outNode.Right);
            }

        }

    }
}//类结束括号

测试用例:

二叉树结构:


private string t = "{1,2,3,4,5,#,#,6,7}";
root = BinTree<int>.StringToBinaryTree(t);//创建二叉树

VS

//创建二叉树
void CreatBinTree()
{

//root = new TreeNode<int>(1);
//TreeNode<int> t2 = new TreeNode<int>(2);
//TreeNode<int> t3 = new TreeNode<int>(3);
//TreeNode<int> t4 = new TreeNode<int>(4);
//TreeNode<int> t5 = new TreeNode<int>(5);
//TreeNode<int> t6 = new TreeNode<int>(6);
//TreeNode<int> t7 = new TreeNode<int>(7);

//root.SetLRChild(t2, t3);
//t2.SetLRChild(t4, t5);
//t4.SetLRChild(t6, t7);
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class _017_BinTree : MonoBehaviour
{
   //二叉树结构: 
    private string tree = @"     
              1
             / \
            2   3
           / \
          4   5
         / \ 
        6   7              
                           ";

    private string t = "{1,2,3,4,5,#,#,6,7}";

    TreeNode<int> root; //二叉树根节点

    //创建二叉树
    void CreatBinTree()
    {
       
     //root = new TreeNode<int>(1);
        //TreeNode<int> t2 = new TreeNode<int>(2);
        //TreeNode<int> t3 = new TreeNode<int>(3);
        //TreeNode<int> t4 = new TreeNode<int>(4);
        //TreeNode<int> t5 = new TreeNode<int>(5);
        //TreeNode<int> t6 = new TreeNode<int>(6);
        //TreeNode<int> t7 = new TreeNode<int>(7);

        //root.SetLRChild(t2, t3);
        //t2.SetLRChild(t4, t5);
        //t4.SetLRChild(t6, t7);
    }

    void Start()
    {
         root = BinTree<int>.StringToBinaryTree(t);//创建二叉树

        
        Debug.Log("二叉树结构:" + "\n" + tree);

        //遍历:
        Debug.Log("------------先序遍历(非递归)-------------");
        BinTree<int>.PreOrderTraversal(root);
        BinTree<int>.DisPlayOutPut();

        Debug.Log("------------中序遍历(非递归)-------------");
        BinTree<int>.InOrderTraversal(root);
        BinTree<int>.DisPlayOutPut();

        Debug.Log("------------后序遍历(非递归)-------------");
        BinTree<int>.PostOrderTraversal(root);
        BinTree<int>.DisPlayOutPut();

        Debug.Log("------------层序遍历(非递归)-------------");
        BinTree<int>.LayerOrderTraversal(root);
        BinTree<int>.DisPlayOutPut();
        

    }

}

测试结果:


注:

二叉树的遍历是很多应用的核心步骤。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容