泛型树遍历C#详细教程

一、前言

本篇目的

  • 构建一个自定义泛型树Tree
  • 定义该类的枚举器,实现先序遍历
  • 用get访问器,实现树的中序,后序,层序遍历

开发环境

  1. 操作系统: Windows 10 X64
  2. SDK:NET Framework 4.7.2
  3. IDE:Visual Studio 2019

二、部分名词解释

泛型

泛型,是指通过参数化类型来实现在同一份代码上操作多种数据类型,泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。
泛型类型和普通类型的区别在于泛型类型与一组类型参数或类型变量关联。

通常先声明泛型,然后通过类型实例化来使用泛型。定义泛型的语法格式如下:

[访问修饰符][返回类型] 泛型名称<类型参数列表>

其中,“泛型名称”要符合标识符的定义。尖括号表示类型参数列表,可以包含一个或多个类型参数,如

树(Tree)是n(n≥0)个结点的有限集。
它或为空树(n = 0),或为非空树。
对于非空树T:

(1)有且仅有一个称之为根的结点;
(2)除根结点以外的其余结点可分为m(m>0)个互不相交的有限集T1, T2, …, Tm, 其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)。

二叉树为m=2,即除根结点以外的其余结点分为两个互不相交的子集T1和T2,分别称为T的左子树和右子树,且T1和T2本身又都是二叉树。

二叉树的结构最简单,规律性最强;
可以证明,所有树都能转为唯一对应的二叉树,不失一般性。

二叉树遍历

所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问 题。 遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。

从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:
⑴访问结点本身(N),
⑵遍历该结点的左子树(L),
⑶遍历该结点的右子树(R)。

以上三种操作有六种执行次序:

NLR、LNR、LRN、NRL、RNL、RLN。

前三种次序与后三种次序对称,故只讨论先左后右的前三种次序。

①先序遍历

NLR:前序遍历(Preorder Traversal 亦称(先序遍历))
——访问根结点的操作发生在遍历其左右子树之前。

②中序遍历

LNR:中序遍历(Inorder Traversal)
——访问根结点的操作发生在遍历其左右子树之中(间)。

③后序遍历

LRN:后序遍历(Postorder Traversal)
——访问根结点的操作发生在遍历其左右子树之后。

④层序遍历

除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

三、算法实现

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

1.声明枚举器类

定义自定义泛型树Tree类的枚举器

class TreeEnum : IEnumerator
{
    public T[] PreNodeList;
    int position = -1;//位置字段,初始化为-1
    public TreeEnum(T[] ts)//构造函数
    {
        PreNodeList = ts;
    }
    public bool MoveNext()//定义TreeEnum的MoveNext方法
    {
        position++;
        return (position < PreNodeList.Length);
    }
    public void Reset()//定义TreeEnum的Reset方法
    {
        position = -1;
    }

    public T Current//定义TreeEnum的Current属性
    {
        get
        { return PreNodeList[position]; }
    }
    object IEnumerator.Current//实现IEnumerator的Current属性
    {
        get
        { return Current; }
    } 
    public void Dispose()
    {
        throw new NotImplementedException();
    }
}

2.定义Tree泛型树类

自定义了泛型树Tree类

    class Tree : IEnumerable where T : IComparable

以下为类成员及函数

实现接口
    IEnumerator IEnumerable.GetEnumerator()//实现IEnumerable的GetEnumerator方法
    {
        return GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()//实现IEnumerable的GetEnumerator方法
    {
        return GetEnumerator();
    }
    public TreeEnum GetEnumerator()//定义Tree类的GetEnumerator()
    {
        return new TreeEnum(WalkTreeList);
    }
    public IEnumerable GetWalkList//含yield return语句的GetWalkList属性
    {
        get
        {
            for (int i = 0; i < this.GetWalkTreeList.Length; i++)
                yield return GetWalkTreeList[i];
        }
    }
泛型树结点数据
    private T NodeData { get; set; }//根结点
    private Tree LeftTree { get; set; }//左子树
    private Tree RightTree { get; set; }//右子树
构造二叉树
    public Tree(T NewNode) { NodeData = NewNode; }//含参构造函数
    public void Insert(T NewNode)//添加树结点
    {
        T NodeValue = this.NodeData;
        if (NodeValue.CompareTo(NewNode) > 0)// 判断当前节点值是否大于新项
        {
            if (this.LeftTree == null)
            {
                this.LeftTree = new Tree(NewNode);
            }
            else
            {
                this.LeftTree.Insert(NewNode);
            }
        }
        else
        {
            if (this.RightTree == null)
            {
                this.RightTree = new Tree(NewNode);
            }
            else
            {
                this.RightTree.Insert(NewNode);
            }
        }
    }
遍历二叉树
    public T[] WalkTreeList = new T[16];//遍历序列数组
    public T[] GetWalkTreeList = new T[16];//使用get访问器的遍历序列数组
    public int WalkNum = 0;
    //进行遍历选择
    public void WalkTree(Tree tree, T[] TreeList, int mark, bool New)
    {
        if (New) { WalkNum = 0; New = false; }
        switch (mark)
        {
            case 1://前序遍历
                if (tree == null) return;
                TreeList[WalkNum++] = tree.NodeData;
                WalkTree(tree.LeftTree, TreeList, mark, New);
                WalkTree(tree.RightTree, TreeList, mark, New);
                break;
            case 2://中序遍历
                if (tree == null) return;
                WalkTree(tree.LeftTree, TreeList, mark, New);
                TreeList[WalkNum++] = tree.NodeData;
                WalkTree(tree.RightTree, TreeList, mark, New);
                break;
            case 3://后序遍历
                if (tree == null) return;
                WalkTree(tree.LeftTree, TreeList, mark, New);
                WalkTree(tree.RightTree, TreeList, mark, New);
                TreeList[WalkNum++] = tree.NodeData;
                break;
            case 4://层序遍历
                if (tree == null) return;
                //利用队列先进先出进行遍历
                Queue> Q = new Queue>();//开辟队列空间
                Q.Enqueue(tree);//根结点入队列
                while (Q.Count != 0)//队列非空时
                {
                    Tree TheTree = Q.Dequeue();//首元素出队
                    TreeList[WalkNum++] = TheTree.NodeData;//将该结点的数据记录到数组中
                    if (TheTree.LeftTree != null) { Q.Enqueue(TheTree.LeftTree); }//左结点入队
                    if (TheTree.RightTree != null) { Q.Enqueue(TheTree.RightTree); }//右结点入队
                }
                break;
        }
    }

3.Program类及主函数

class Program
{
    static void Main(string[] args)
    {
        //创建二叉树
        Tree tree1 = new Tree(10);
        tree1.Insert(3);
        tree1.Insert(4);
        tree1.Insert(-3);
        tree1.Insert(6);
        tree1.Insert(8);
        tree1.Insert(5);
        tree1.Insert(2);
        tree1.Insert(14);
        tree1.Insert(9);
        tree1.Insert(23);
        tree1.Insert(41);
        tree1.Insert(16);
        tree1.Insert(20);
        tree1.Insert(0);
        tree1.Insert(1);
        //用枚举器进行先序遍历
        tree1.WalkTree(tree1, tree1.WalkTreeList, 1, true);
        Console.Write("用枚举器对自定义泛型树进行先序遍历,结果为:");
        foreach (int item in tree1.WalkTreeList)
        {
            Console.Write(item + " ");
        }
        Console.Write("\n");
        //用get访问器进行中序遍历
        tree1.WalkTree(tree1, tree1.GetWalkTreeList, 2, true);
        Console.Write("用get访问器对自定义泛型树进行中序遍历,结果为:");
        foreach (int item in tree1.GetWalkList)
        {
            Console.Write(item + " ");
        }
        Console.Write("\n");
        //用get访问器进行后序遍历
        tree1.WalkTree(tree1, tree1.GetWalkTreeList, 3, true);
        Console.Write("用get访问器对自定义泛型树进行后序遍历,结果为:");
        foreach (int item in tree1.GetWalkList)
        {
            Console.Write(item + " ");
        }
        Console.Write("\n");
        //用get访问器进行层序遍历
        tree1.WalkTree(tree1, tree1.GetWalkTreeList, 4, true);
        Console.Write("用get访问器对自定义泛型树进行层序遍历,结果为:");
        foreach (int item in tree1.GetWalkList)
        {
            Console.Write(item + " ");
        }
        Console.Write("\n");
    }
}

四、参考文献等

本篇参考了以下文章

百度百科:二叉树遍历 https://baike.baidu.com/item/%E4%BA%8C%E5%8F%89%E6%A0%91%E9%81%8D%E5%8E%86/9796049?fr=aladdin

基于C# 2.0泛型构造一个二叉树类 https://blog.51cto.com/zhuxianzhong/59356

学习C#泛型概述,构建二叉树的泛型类 https://blog.csdn.net/qq_40242160/article/details/104940914?utm_source=app&app_version=4.18.0&code=app_1562916241&uLinkId=usr1mkqgl919blen

感谢阅读!

你可能感兴趣的:(c#,后端,泛型,二叉树)