C ++ Learning Part 7-Tree (Binary Tree)

As a data structure, the tree structure plays a very important role in the algorithm. So the length of this article may be very long, with a lot of theoretical knowledge. A tree structure is a data structure that consists of nodes and edges connecting nodes.
The root is a special node of a tree, because the root is the only node without a parent node, and the leaf node refers to a node without child nodes.
As shown in the figure,
Insert picture description here
node 0 is the root node of the entire tree. Here is a concept for the tree. We usually refer to the number of children of the node as degrees. From the above figure, we see two points 0 and 2 The degree is 3, the degree of nodes 1, 3, 8 is 2, and the degree of nodes 4, 5, 6, 7, 9, 10, 11, 12 is 0.
Next, the length of the path from the root node to other nodes x is called the depth of the node x. The depth of the root node in a tree is the deepest, just like the big tree in real life, the leaves above the root are the farthest of.
After having a general understanding of the tree structure, then start learning about the binary tree.
Binary tree means that a tree has a root node, and the number of child nodes of all nodes does not exceed 2, then this tree is called a binary tree.
As shown in the figure,
Insert picture description here
from the above figure, we can find that the left and right nodes of a binary tree look very similar to the binary tree, which means that the binary tree itself is a recursive tree structure.
Then we can divide it into three parts like this:

  • Node value
  • Left subtree (binary tree)
  • Right subtree (binary tree)
    C ++ builds as follows
struct Tree
{
	int val,left,right;
}
struct Tree T[MAX];
//或者
int val[MAX],left[MAX],right[MAX];

Tree depth (recursive)

int getDepth(struct Tree a)
{
	int l=0,r=0;
	if(a.left!=0)//因为根结点为0,所以默认左右子树不能指向0
	{
		l=getDepth(T[a.left]);
	}
	if(a.right!=0)
	{
		r=getDepth(T[a.right]);
	}
	return max(l,r)+1;
}

The depth of the current node refers to the maximum of its left subtree depth and right subtree depth plus its own level 1.
The width of the tree (recursive)

int ans;
int width(struct Tree a)
{
	int l=0,r=0;
	if(a.left!=0)
	{
		l=width(T[a.left]);
	}
	if(a.right!=0)
	{
		r=width(T[a.right]);
	}
	ans=max(ans,l+r+1);//取左子树高度+右子树高度+本身结点1,最大值存到ans
	return max(l,r)+1;
}

Compared with the height, you will find that the gap between them is only one line of code, I have added a comment.

Next is the traversal of the tree, we first assign a value to the val of each node

for(int i=0;i<=6;i++)
{
	T[i].val=i;
}

Preorder traversal, roots around, for a binary tree, we first output its root, and then output its left and right subtrees.

void preorder(struct Tree a)
{
	printf("%d ",a.val);
	if(a.left!=0)
	{
		preorder(T[a.left]);
	}
	if(a.right!=0)
	{
		preorder(T[a.right]);
	}
}

In middle order traversal, left root right, the same reason, first output the left subtree, then output the root, and then output the right subtree.

void midorder(struct Tree a)
{
	if(a.left!=0)
	{
		midorder(T[a.left]);
	}
	printf("%d ",a.val);
	if(a.right!=0)
	{
		midorder(T[a.right]);
	}
}

Post-order traversal, the order of the left and right roots are the same.

void backorder(struct Tree a)
{
	if(a.left!=0)
	{
		backorder(T[a.left]);
	}
	if(a.right!=0)
	{
		backorder(T[a.right]);
	}
	printf("%d ",a.val);
}

The traversal of the binary tree will visit each node of the tree once, so the algorithm complexity is O (n). However, when using recursion to implement the traversal algorithm, it should be noted that once the number of nodes in the tree is large and unevenly distributed, it is likely to cause the recursion depth to be too deep.
Finally, the key point is to build a binary tree . We will find that the roots of the pre-order and post-order are at the endpoints of the left or right subtree, respectively. The root is an independent existence, and the left and right subtrees are usually clustered on the left side of the root or the root On the right, it is difficult to separate. In the middle order, its root is hidden in the middle, it is difficult to see which one is the root, but once the root is found, the left and right subtrees are clearly divided.
Therefore, we can use the pre-order or post-order to find the root, and come to the middle order to divide the left and right subtrees, so that it can be clearly seen.
Taking the above picture as an example, an example is to build a tree in pre-middle order. The
pre-order traversal is: 0 1 3 4 2 5
6

int pos;
vector <int> pre,mid;
	pre.push_back(0);
	pre.push_back(1);
	pre.push_back(3);
	pre.push_back(4);
	pre.push_back(2);
	pre.push_back(5);
	pre.push_back(6);
	mid.push_back(3);
	mid.push_back(1);
	mid.push_back(4);
	mid.push_back(0);
	mid.push_back(5);
	mid.push_back(2);
	mid.push_back(6);
	rec(0,7);

First give the tree-building code

int rec(int l,int r)//前中
{
	if(l>=r) return 0;//当左侧>=右侧时已经不满足建树,返回0,但并不是指向根,因为根没有父节点
	int  root = pre[pos++];
	int m=distance(mid.begin(),find(mid.begin(),mid.end(),root));//找出根的位置
	T[root].left=rec(l,m);
	T[root].right=rec(m+1,r);
	return root;
} 

pos is used to indicate the current position. If it is the preamble, the root node is at the beginning, that is, it starts from 0, otherwise it starts from the end and goes forward.

Subscript (pos) 0 1 2 3 4 5 6
prologue 0 1 3 4 2 5 6
Middle order 3 1 4 0 5 2 6

When we find a root, we will find its position in the mid, and the node with the root as the left in the mid forms its left subtree, and the node with the root as the right forms its right sub Tree, then, let ’s build the left subtree, then the nodes of the left subtree are all the nodes from the leftmost l of the current subtree to the current root node m, and the right subtree is from From the left side of the root node, m + 1 to the rightmost r of the current subtree, and then dichotomize in turn to return to the current root node.
Analyze that the first root is 0, and then I start to build 3 1 4 on the left side of m (0). After pos ++, I found the next root is 1. Continue to the 3 on the left side of m (1). Start building trees, then return the current 3 as the left subtree of 1, start building trees for the 4 on the right side of m (1), then return the current 4 as the right subtree of 1, and then finish building the left and right subtrees of 1, Returns the left subtree with current root 1 as 0. At this point, pos has reached 4, start to build trees 5 2 6 on the right side of m (0), find the next root is 2, start building trees on 5 left side of m (2), and return 5 as the left subtree of 2, Similarly, 6 is returned as the right subtree of 2. After the left and right subtrees of 2 are completed, the current root = 2 is returned as the right subtree of 0. After the tree is built, you can try to use the previous traversal code to verify.
If you understand the pre-order and mid-order tree-building, you may wish to try the post-order and mid-order tree-building.
Compare what I have given and see what is different


int reb(int l,int r)
{
	if(l>=r) return 0;
	int  root = back[pos--];//在赋值阶段将pos赋值为back最后一个值的下标
	int m=distance(mid.begin(),find(mid.begin(),mid.end(),root));
	T[root].right=reb(m+1,r);
	T[root].left=reb(l,m);
	return root;
}
Published 13 original articles · Likes0 · Visits 493

Guess you like

Origin blog.csdn.net/SmallHedgehog/article/details/105458953