Figure 1

The data structure described here is the "Tree", in which the circle a on the top is called the root node and other circles are called nodes. Of course, root can be considered as a special case of node.

TreeUnlike the previously learned linear structure, it is a one-to-many nonlinear structure,Has two basic features:

1,The root node does not have any parent node. All nodes except root have only one parent node.

2,All nodes in the tree can have 0 or more successor nodes.

So the following are not trees:

Figure 2

Below are some annoying but veryImportant Terms:

1. node: indicates the data element in the tree, which is composed of the relationship between the data item and the data element. In Figure 1, there are 10 nodes in total.

2. Degree of node: Number of Subtrees owned by the node. in figure 1, the degree of node A is 3.

3. Degree of tree: the maximum degree of each node in the tree. In Figure 1, the degree of the tree is 3.

4. leaf node: A node with a degree of 0, also called a terminal node. In Figure 1, node E, F, G, H, I, and J are all leaf nodes.

5. branch node: A node with a degree of less than 0. It is also called a non-terminal node or an internal node. In Figure 1, node A, B, C, and D are branch nodes.

6. Child: the root of the tree. In Figure 1, Node B, C, and D are children of node.

7. Parent: the upper node of a node is the parent node of the node. In Figure 1, the parent nodes B, C, and D are node.

8. Ancestor: All nodes from the root node to the branch on which the node passes. In Figure 1, the ancestor of node E is a and B.

9. descendant (descendant): Any node in the subtree with a node as the root. In Figure 1, all nodes except a are descendants of.

10. Brother: children of the same parent. In Figure 1, Node B, C, and D are mutual brothers.

11. Level of node: the number of branches in the path from the root node to a node in the tree is called the level of the node. The level of the root node is defined as 1, and the level of the other nodes is equal to the level of the parent node plus 1.

12. Cousin (sibling): the two sides of the same layer have different nodes. In Figure 1, G and H are mutual cousins.

13. Depth of tree: the maximum number of layers of nodes in the tree. In Figure 1, the depth of the tree is 3.

14. unordered tree: The order between the child nodes of any node in the tree forms an irrelevant tree. A tree usually refers to an unordered tree.

15. Ordered Tree: each child node of any node in the tree has a strictly ordered tree. A binary tree is an Ordered Tree, because each child node in a binary tree is definitely defined as the Left or Right child node of the node.

16. Forest (forest): a set of M (M ≥ 0) trees. The concepts of trees and forests in nature are quite different, but the concepts of trees and forests are quite different in data structures. According to the definition, a tree consists of a root node and a sub-tree. If the root node of the tree is deleted, the tree becomes a forest containing M trees. Of course, a tree can also be called a forest.

Binary Tree

In layman's terms, each node can only be divided into binary trees (Standard nonsense, huh), as shown in the figure below:

Figure 3

Note: Binary Trees are ordered trees.That is to say, the left and right subnodes under each node are placed in order, so (a) and (B) are considered to be two different Binary Trees!

Binary Tree has two classic cases: Complete Binary Tree and full binary tree)

Figure 4

For example, a full binary tree means that each node has two branches and all leaf nodes are in the same level. (Obviously, for a full binary tree with a deep degree of K, the total number of nodes is)

The so-called Complete Binary Tree is: leaf nodes may only appear on the maximum two layers of the hierarchy, in addition, the maximum level of a node's "left branch" and "sub-node" is equal to or greater than 1 of the "sub-node" under "right branch. (More popular: Except for the last layer, all other layers are full. If the last layer is not full, the leaf node can only be left, that is, only the right node can be left empty)

Mathematical features of Binary Trees:

1,A non-empty binary tree has a maximum of nodes (I ≥1) on layer I ).

For example, taking full binary tree (a) as an example, the first layer only has node A, that is, the power 0 of 2 is 1, and the second layer has B and c nodes, that is, the second (2-1) of 2 is 2...

2,If the depth of the required empty tree is 0, a binary tree with a depth of K can have a maximum of nodes (k ≥ 0 ).

In fact, when we introduced the full binary tree above, we have already said that the depth of the full binary tree is K. There is a node, which is the maximum number of nodes in the binary tree.

3,The depth K of A Complete Binary Tree with N nodes is

For example, if the total number of nodes in the middle (a) tree is 15, then the depth K = lg (15) + 1 = 3 + 1 = 4

4,For a non-empty Binary Tree, if the number of nodes whose degree is 0 is and the number of nodes whose degree is 2 is

For example, in the middle (a) tree, the nodes with a moderate value of 0 are H, I, J, K, L, and M (that is, leaf nodes), and other nodes A, B, C, d, E, F, and g all have 7 nodules with a degree of 2 and 7 = 6 + 1.

5,For nodes with NFull Binary TreeIf the number of all nodes starts from 1 in the order of top to bottom and left to right, for nodes with the serial number of I, there are:

Figure 5

(1)If I> 1, the number of the parent node of node I is I/2 ("/" indicates the entire Division). If I = 1, the node is the root node, no parent node.

For example, if you select a node, for example, D (sequence number is 4), the parent node number of D is 4/2 = 2, that is, Node B

(2)If 2I ≤ n, the number of the left child node of the node is 2I. If 2I> N, the node has no left child.

For example, if you want to find a node 5 (E point), then 2*5 <= 10, then the left subnode Number of node e is 2*5 = 10, that is, J point.

(3)If 2I + 1 is less than or equal to N, the number of the right child node of the node is 2I + 1. If 2I + 1> N, the node has no right child.

For example, if you want to find a node 4 (point D), then 2*4 + 1 <= 10, then the sequence of the right subnode of point D is 2*4 + 1 = 9, that is, point I

Binary Tree Storage Structure

1,Sequential Storage

For a full Binary Tree, such as 5, it can be expressed

According to mathematical feature 5 just now, as long as you know the serial number I of a node, you can determine the parent node of the node, and the sequence number of the left and right subnodes (if there are left and right subnodes), so we can change the non-linear tree structure into a one-to-one linear structure.

However, feature 5 is not an incomplete binary tree, but we can add some empty nodes to the incomplete binary tree to make up a Complete Binary Tree.

^ Represents an empty node (null)

In this way, sequential storage can be used, but the disadvantage is obvious: the storage space is wasted.

2,Binary linked list Storage

Add three basic attributes (lchild), rchild (right child node), and data (node value) to each node. If the Left or Right child node is empty, it is represented by null (represented by ^ In the image)

For example, based on whether there is a header node reference, it can be divided into two linked lists with no leading nodes "and" two linked lists with leading nodes"

3,Triple linked list Storage

Binary linked list storage, if you want to find the parent node or root node from a node, it will be very troublesome, so to improve, you can add a parent node attribute for each node, it becomes the following structure.

Next let's take a lookCodeImplementation: (The following shows the implementation of a binary linked list with no leading node)

Node. CS (node of the binary linked list)

Namespace tree and binary tree {public class node <t> {private t data; private node <t> lchild; // left subnode private node <t> rchild; // public node (t data, node <t> ln, node <t> RN) {This. data = data; this. lchild = ln; this. rchild = rn;} public node (node <t> ln, node <t> RN) {This. data = default (t); this. lchild = ln; this. rchild = rn;} public node (t data) {This. data = data; lchild = NULL; rchild = NULL;} public node () {DATA = default (t); lchild = NULL; rchild = NULL ;} public t data {get {return this. data;} set {This. data = value ;}} public node <t> lchild {get {return this. lchild;} set {This. lchild = value ;}} public node <t> rchild {get {return this. rchild;} set {This. rchild = value ;}}}}

tree bitree. CS

Namespace tree and binary tree {public class bitree <t> {private node <t> root; // <summary> // root node (attribute) /// </Summary> Public node <t> root {get {return root;} set {root = value ;}} /// <summary> /// constructor /// </Summary> Public bitree () {root = NULL ;} /// <summary> /// constructor /// </Summary> /// <Param name = "data"> </param> Public bitree (t data) {node <t> P = new node <t> (data); root = P ;}/// <summary> // Constructor Count /// </Summary> /// <Param name = "data"> </param> /// <Param name = "ln"> </param> // /<Param name = "RN"> </param> Public bitree (t data, node <t> ln, node <t> RN) {node <t> P = new node <t> (data, LN, RN); root = P ;} /// <summary> /// determines whether the tree is empty. /// </Summary> /// <returns> </returns> Public bool isempty () {If (root = NULL) {return true;} else {return false ;}} /// <summary> /// obtain the left subnode of node P /// </Summary> /// <Param name = "p"> </param> // <returns> </returns> Public node <t> getlchild (node <t> P) {return p. lchild ;} /// <summary> /// obtain the right subnode of node P /// </Summary> /// <Param name = "p"> </param> // /<returns> </returns> Public node <t> getrchild (node <t> P) {return p. rchild ;} /// <summary> /// insert data from the left subnode under Node P /// </Summary> /// <Param name = "data"> </param> // /<Param name = "p"> </param> Public void insertl (t data, Node <t> P) {node <t> TMP = new node <t> (data); TMP. lchild = P. lchild; p. lchild = TMP ;} /// <summary> /// Insert the right sub-node data under Node P /// </Summary> /// <Param name = "data"> </param>/ // <Param name = "p"> </param> Public void insertr (t data, node <t> P) {node <t> TMP = new node <t> (data); TMP. rchild = P. rchild; p. rchild = TMP ;} /// <summary> /// Delete the left subnode of node P /// </Summary> /// <Param name = "p"> </param> /// <returns> </Returns> Public node <t> deletel (node <t> P) {If (P = NULL) | (P. lchild = NULL) {return NULL;} node <t> TMP = P. lchild; p. lchild = NULL; return TMP ;} /// <summary> /// Delete the right subnode of node P /// </Summary> /// <Param name = "p"> </param> // /<returns> </returns> Public node <t> deleter (node <t> P) {If (P = NULL) | (P. rchild = NULL) {return NULL;} node <t> TMP = P. rchild; p. rchild = NULL; return TMP ;} /// <Summary> /// determine whether node P is a leaf node // </Summary> /// <Param name = "p"> </param> // /<returns> </returns> Public bool isleaf (node <t> P) {If (P! = NULL) & (P. lchild = NULL) & (P. rchild = NULL) {return true ;}else {return false ;}}}}

InsertAlgorithmAs follows:

Binary tree traversal:

For binary trees, there are four classic traversal methods.

1. Forward Traversal(Also called sequential traversal) --> recursively traverse by node --> lchild --> rchild (that is, "first itself" --> then "Left subnode" --> last "right subnode ")

2. Sequential Traversal--> Recursively traverse by lchild> node> rchild (first "Left subnode", then "own node", and finally "right subnode ")

3. Post-order traversal--> Recursively traverse nodes in the order of lchild --> rchild --> node (first "Left subnode", then "right subnode", and finally "own node ")

4. layer Traversal-- This is not an explanation. You can simply understand the literal meaning.

OK. Finally, let's perform code verification and test:

Using system; using system. collections; using system. collections. generic; namespace tree and binary tree {class program {static void main (string [] ARGs) {# region // construct tree bitree <string> tree = new bitree <string> ("A"); node <string> root = tree. root; tree. insertl ("B", root); tree. insertr ("C", root); node <string> B = root. lchild; node <string> C = root. rchild; tree. insertl ("D", B); tree. insertr ("e", B); tree. insertl ("F ", C); tree. insertr ("g", c); node <string> d = B. lchild; node <string> E = B. rchild; tree. insertl ("H", d); tree. insertr ("I", d); tree. insertl ("J", e); # endregion console. writeline ("preorder traversal start >>> \ n"); // preorder traversal preorder (Root); console. writeline ("\ n ---------------------- \ n"); console. writeline ("Start of central order traversal >>> \ n"); // inorder traversal (Root); console. writeline ("\ n ---------------------- \ n"); console. writeline ("start after sequential traversal>> \ N "); // traverse postorder (Root) in the descending order; console. writeline ("\ n ---------------------- \ n"); console. writeline ("sequence traversal starts >>> \ n"); // The levelorder (Root) is traversed in the descending order; console. read () ;}/// <summary> // pre-order traversal (that is, root --> left --> right) /// </Summary> /// <Param name = "root"> </param> static void preorder (node <string> root) {If (root! = NULL) {// process the root console first. write ("{0}", Root. data); // reprocess the root preorder (root. lchild); // re-process the right sub-node preorder (root. rchild) ;}}/// <summary> /// center-order traversal (left --> root --> right) /// </Summary> /// <Param name = "root"> </param> static void inorder (node <string> root) {If (root = NULL) {return;} // The first left subnode inorder (root. lchild); // restart the root node console. write ("{0}", Root. data); // then the right subnode inorder (root. rchild );}// /<Summary> /// post-order traversal /// </Summary> /// <Param name = "root"> </param> static void postorder (node <string> root) {If (root = NULL) {return;} postorder (root. lchild); postorder (root. rchild); console. write ("{0}", Root. data );} /// <summary> /// traverse through layers /// </Summary> /// <Param name = "root"> </param> static void levelorder (node <string> root) {If (root! = NULL) {queue <node <string> q = new queue <node <string> (); q. enqueue (Root); While (Q. count> 0) {node <string> TMP = Q. dequeue (); // process the root node console first. write ("{0}", TMP. data); If (TMP. lchild! = NULL) {// enter Q. enqueue (TMP. lchild);} If (TMP. rchild! = NULL) {// enter Q. enqueue (TMP. rchild) ;}}}} on the right subnode );}}}}}}

Running result:

*Start traversing in the forward order >>>*

*A B d h I e J C f g*

*------------------------*

*Start of the Middle-order traversal >>>*

*H d I B j e a F C G*

*------------------------*

*Start to traverse in the descending order >>>*

*H I D j e B f g C*

*------------------------*

*Sequence traversal starts >>>*

*A B c d e f g h I j*