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
- Operating system: Windows 10 X64
- SDK: NET Framework 4.7.2
- 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
Constructing a binary tree class based on C# 2.0 generics https://blog.51cto.com/zhuxianzhong/59356
Thanks for reading!