Generic tree traversal C# detailed tutorial

Keywords: C# Back-end Binary tree

1, Foreword

Purpose of this article

  • Build a custom generic Tree
  • Define the enumerator of this class to realize sequential traversal
  • Use get accessor to realize the middle order, post order and sequence traversal of the tree

development environment

  1. Operating system: Windows 10 X64
  2. SDK: NET Framework 4.7.2
  3. IDE: Visual Studio 2019

2, Interpretation of some terms

generic paradigm

Generic refers to the operation of multiple data types on the same code through parameterized types. Generic programming is a programming paradigm. It abstracts types by using "parameterized types", so as to realize more flexible reuse.
The difference between a generic type and a normal type is that a generic type is associated with a set of type parameters or type variables.

Generics are usually declared first and then used through type instantiation. The syntax format for defining generics is as follows:

[access modifier] [return type] generic name < type parameter list >

Where "generic name" should conform to the definition of identifier. Angle brackets represent the type parameter list, which can contain one or more type parameters, such as < T, u,  >.

tree

A Tree is a finite set of n (n ≥ 0) nodes.
It is either an empty tree (n = 0) or a non empty tree.
For non empty tree T:

(1) There is and only one node called root;
(2) The other nodes except the root node can be divided into m (M > 0) disjoint finite sets T1, T2,..., Tm, in which each set itself is a tree and is called the SubTree of the root.

The binary tree is m=2, that is, the other nodes except the root node are divided into two disjoint subsets T1 and T2, which are called the left subtree and right subtree of T respectively, and T1 and T2 are binary trees themselves.

Binary tree has the simplest structure and the strongest regularity;
It can be proved that all trees can be transformed into a unique corresponding binary tree without losing generality.

Binary tree traversal

Traversal means that each node in the tree is accessed once and only once along a search route. The operation of the access node depends on the specific application problem. Traversal is one of the most important operations on binary tree and the basis of other operations on binary tree.

According to the recursive definition of binary tree, a non empty binary tree consists of three basic parts: root node and left and right subtrees. Therefore, on any given node, three operations can be performed in a certain order:
(1) access node itself (N),
(2) traverse the left subtree (L) of the node,
⑶ traverse the right subtree (R) of the node.

There are six execution orders for the above three operations:

NLR,LNR,LRN,NRL,RNL,RLN.

The first three orders are symmetrical to the last three orders, so only the first three orders from left to right are discussed.

① Preorder traversal

NLR: Preorder Traversal (also known as Preorder Traversal)
——The operation of accessing the root node occurs before traversing its left and right subtrees.

② Medium order traversal

LNR: inorder traversal
——The operation of accessing the root node occurs in traversing its left and right subtrees.

③ Postorder traversal

LRN: postorder traversal
——The operation of accessing the root node occurs after traversing its left and right subtrees.

④ Sequence traversal

In addition to first order traversal, middle order traversal and second order traversal, sequence traversal can also be carried out on binary trees. Let the number of layers where the root node of binary tree is located be 1, and sequence traversal starts from the root node of binary tree, first visit the root node of the first layer, then visit the nodes on the second layer from left to right, and then the nodes on the third layer, and so on, from top to bottom and from left The process of accessing the nodes of the tree layer by layer to the right is sequence traversal.

3, Algorithm implementation

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

1. Declare enumerator class

Defines an enumerator for a custom generic Tree class

class TreeEnum<T> : IEnumerator<T>
{
    public T[] PreNodeList;
    int position = -1;//Location field, initialized to - 1
    public TreeEnum(T[] ts)//Constructor
    {
        PreNodeList = ts;
    }
    public bool MoveNext()//Defines the MoveNext method of TreeEnum
    {
        position++;
        return (position < PreNodeList.Length);
    }
    public void Reset()//Define the Reset method of TreeEnum
    {
        position = -1;
    }

    public T Current//Defines the Current property of TreeEnum
    {
        get
        { return PreNodeList[position]; }
    }
    object IEnumerator.Current//Implement the Current property of IEnumerator
    {
        get
        { return Current; }
    } 
    public void Dispose()
    {
        throw new NotImplementedException();
    }
}

2. Define Tree generic Tree class

Custom generic Tree class

    class Tree<T> : IEnumerable<T> where T : IComparable<T>

The following are class members and functions

Implementation interface

    IEnumerator<T> IEnumerable<T>.GetEnumerator()//GetEnumerator method that implements IEnumerable < T >
    {
        return GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()//GetEnumerator method that implements IEnumerable
    {
        return GetEnumerator();
    }
    public TreeEnum<T> GetEnumerator()//Define GetEnumerator() of Tree class
    {
        return new TreeEnum<T>(WalkTreeList);
    }
    public IEnumerable<T> GetWalkList//GetWalkList property with yield return statement
    {
        get
        {
            for (int i = 0; i < this.GetWalkTreeList.Length; i++)
                yield return GetWalkTreeList[i];
        }
    }

Generic tree node data

    private T NodeData { get; set; }//Root node
    private Tree<T> LeftTree { get; set; }//Left subtree
    private Tree<T> RightTree { get; set; }//Right subtree

Constructing binary tree

    public Tree(T NewNode) { NodeData = NewNode; }//Parameter constructor
    public void Insert(T NewNode)//Add tree node
    {
        T NodeValue = this.NodeData;
        if (NodeValue.CompareTo(NewNode) > 0)// Judge whether the current node value is greater than the new item
        {
            if (this.LeftTree == null)
            {
                this.LeftTree = new Tree<T>(NewNode);
            }
            else
            {
                this.LeftTree.Insert(NewNode);
            }
        }
        else
        {
            if (this.RightTree == null)
            {
                this.RightTree = new Tree<T>(NewNode);
            }
            else
            {
                this.RightTree.Insert(NewNode);
            }
        }
    }

Traversal binary tree

    public T[] WalkTreeList = new T[16];//Traversal sequence array
    public T[] GetWalkTreeList = new T[16];//Traversal sequence array using get accessor
    public int WalkNum = 0;
    //Make traversal selection
    public void WalkTree(Tree<T> tree, T[] TreeList, int mark, bool New)
    {
        if (New) { WalkNum = 0; New = false; }
        switch (mark)
        {
            case 1://Preorder traversal
                if (tree == null) return;
                TreeList[WalkNum++] = tree.NodeData;
                WalkTree(tree.LeftTree, TreeList, mark, New);
                WalkTree(tree.RightTree, TreeList, mark, New);
                break;
            case 2://Medium order traversal
                if (tree == null) return;
                WalkTree(tree.LeftTree, TreeList, mark, New);
                TreeList[WalkNum++] = tree.NodeData;
                WalkTree(tree.RightTree, TreeList, mark, New);
                break;
            case 3://Postorder traversal
                if (tree == null) return;
                WalkTree(tree.LeftTree, TreeList, mark, New);
                WalkTree(tree.RightTree, TreeList, mark, New);
                TreeList[WalkNum++] = tree.NodeData;
                break;
            case 4://level traversal 
                if (tree == null) return;
                //Traversal using queue first in first out
                Queue<Tree<T>> Q = new Queue<Tree<T>>();//Open up queue space
                Q.Enqueue(tree);//Root node in queue
                while (Q.Count != 0)//When the queue is not empty
                {
                    Tree<T> TheTree = Q.Dequeue();//First element out of the team
                    TreeList[WalkNum++] = TheTree.NodeData;//Record the data of the node into the array
                    if (TheTree.LeftTree != null) { Q.Enqueue(TheTree.LeftTree); }//Left node join the team
                    if (TheTree.RightTree != null) { Q.Enqueue(TheTree.RightTree); }//Right node join the team
                }
                break;
        }
    }

3.Program class and main function

class Program
{
    static void Main(string[] args)
    {
        //Create binary tree
        Tree<int> tree1 = new Tree<int>(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);
        //Preorder traversal with enumerator
        tree1.WalkTree(tree1, tree1.WalkTreeList, 1, true);
        Console.Write("Use the enumerator to traverse the custom generic tree in order, and the result is:");
        foreach (int item in tree1.WalkTreeList)
        {
            Console.Write(item + " ");
        }
        Console.Write("\n");
        //Middle order traversal with get accessor
        tree1.WalkTree(tree1, tree1.GetWalkTreeList, 2, true);
        Console.Write("use get The accessor traverses the custom generic tree in middle order, and the result is:");
        foreach (int item in tree1.GetWalkList)
        {
            Console.Write(item + " ");
        }
        Console.Write("\n");
        //Post order traversal with get accessor
        tree1.WalkTree(tree1, tree1.GetWalkTreeList, 3, true);
        Console.Write("use get The accessor traverses the custom generic tree in sequence, and the result is:");
        foreach (int item in tree1.GetWalkList)
        {
            Console.Write(item + " ");
        }
        Console.Write("\n");
        //Sequence traversal with get accessor
        tree1.WalkTree(tree1, tree1.GetWalkTreeList, 4, true);
        Console.Write("use get The accessor traverses the custom generic tree, and the result is:");
        foreach (int item in tree1.GetWalkList)
        {
            Console.Write(item + " ");
        }
        Console.Write("\n");
    }
}

4, References, etc

This article refers to the following articles

Baidu Encyclopedia: binary tree traversal https://baike.baidu.com/item/%E4%BA%8C%E5%8F%89%E6%A0%91%E9%81%8D%E5%8E%86/9796049?fr=aladdin

Constructing a binary tree class based on C# 2.0 generics https://blog.51cto.com/zhuxianzhong/59356

Learn C# generic overview and build generic classes of binary tree https://blog.csdn.net/qq_40242160/article/details/104940914?utm_source=app&app_version=4.18.0&code=app_1562916241&uLinkId=usr1mkqgl919blen

Thanks for reading!

Posted by ethan89 on Sun, 07 Nov 2021 13:27:22 -0800