In the last article, we talked about a lot of theoretical knowledge. Although it is very boring, those are the prerequisites for our study today. When you look at the code, you will discover how important this theoretical knowledge is. First of all, we still have to explain that the main content of our study is a binary tree, because a binary tree is the most typical application of a tree. Whether it is an exam or an interview, it is a must-know-and-learn content.
First of all, before learning the operation of the tree, we must first understand that the core of the operation of the tree is "traversal". Why do you say that? Unlike stacks and queues, the tree structure is actually not one-dimensional anymore. It has branches and different perspectives. More importantly, it has the concept of hierarchy. One-dimensional space is our common "line". It has only length but no height, and this length is its only dimension. The stack and queue are obviously one-dimensional. The tree is different. Because of the concept of hierarchy, it has a "height", that is, it is upgraded to a two-dimensional concept. Just like the bunch of nouns introduced in the previous article, there is the concept of "tree height (depth)".
After being able to traverse a tree, we can add, delete, and modify the nodes of the tree based on the traversal. These basic logical operations are all based on the traversal. Think about it carefully. Stacks and queues, don't these logical operations actually start from traversal? Regardless of whether it is popping into the stack or dequeuing into the team, we are all based on a fixed traversal rule (FILO, FIFO).
For two-dimensional things, how to traverse it is an important content. We only need to traverse the one-dimensional data structure sequentially, while the two-dimensional data results cannot simply be traversed one by one in order, because there is a hierarchical relationship between the nodes, so we have to consider the current If there are no child nodes for the node, what should we do in our traversal operation?
Fortunately, we are standing on the shoulders of giants to learn this knowledge. Many predecessors have summed up some very simple tree traversal methods for us, how simple is it? First, let’s take a look at how to build a tree, which is the binary tree we showed in the previous article.
Chain storage structure of binary tree
Using chained storage of binary trees is very simple and very vivid. Let me put down the question about sequential storage of binary trees, because in the next article we will explain under what circumstances sequential storage is used.
class BiTree
{
public $data;
public $lChild;
public $rChild;
}
In fact, in chain storage, we just use one by one to save the tree. Each binary tree node has a data field, which is the data attribute. The other two properties can be regarded as two forked pointers, namely the left child node lChild and the right child node rChild of this node. Comparing stacks and queues, we just replaced the next node with two child nodes on the left and right. In essence, it is not much different from stacks and queues. To put it bluntly, from the point of view of data structure, we still use one-dimensional storage to represent the two-dimensional concept, and the transformation of this concept is that we need to start from the perspective of understanding the concept.
Binary Tree Building
// 建立二叉树
function CreateBiTree($arr, $i)
{
if (!isset($arr[$i])) {
return null;
}
$t = new BiTree();
$t->data = $arr[$i];
$t->lChild = CreateBiTree($arr, $i * 2);
$t->rChild = CreateBiTree($arr, $i * 2 + 1);
return $t;
}
With such a simple method, we can complete the establishment of a chain binary tree. Please take a closer look, friends, this simple operation actually contains a lot of mystery:
- We use an array to represent each node of the tree in turn, such as inputting A, B, C, D, E in turn... (We will see them again in the sequential storage of the tree)
- The content of the assignment is the data of the current $i subscript. Note that we performed recursive operations when assigning values to the left and right children
- When learning stacks, we learned that "recursion" is a stack operation, so in this code, we build the tree in the form of a stack
- Notice the i 2 and i 2 + 1 each time, right? Please review the properties of
Finally, we test whether this method can successfully establish a chain tree structure.
$treeList = ['', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'];
$tree = CreateBiTree($treeList, 1);
print_r($tree);
// BiTree Object
// (
// [data] => A
// [lChild] => BiTree Object
// (
// [data] => B
// [lChild] => BiTree Object
// (
// [data] => D
// [lChild] => BiTree Object
// (
// [data] => H
// [lChild] =>
// [rChild] =>
// )
// [rChild] => BiTree Object
// (
// [data] => I
// [lChild] =>
// [rChild] =>
// )
// )
// [rChild] => BiTree Object
// (
// [data] => E
// [lChild] => BiTree Object
// (
// [data] => J
// [lChild] =>
// [rChild] =>
// )
// [rChild] => BiTree Object
// (
// [data] => K
// [lChild] =>
// [rChild] =>
// )
// )
// )
// [rChild] => BiTree Object
// (
// [data] => C
// [lChild] => BiTree Object
// (
// [data] => F
// [lChild] => BiTree Object
// (
// [data] => L
// [lChild] =>
// [rChild] =>
// )
// [rChild] => BiTree Object
// (
// [data] => M
// [lChild] =>
// [rChild] =>
// )
// )
// [rChild] => BiTree Object
// (
// [data] => G
// [lChild] => BiTree Object
// (
// [data] => N
// [lChild] =>
// [rChild] =>
// )
// [rChild] => BiTree Object
// (
// [data] => O
// [lChild] =>
// [rChild] =>
// )
// )
// )
// )
The printed content should be very clear, right? Node A has two children on the left and right, nodes B and C, node B has two children on the left and right, D and E, and so on. The final structure is exactly the same as the structure of the binary tree diagram above. Here, we also need to pay attention to that, for the passed-in array, we give the first element, that is, the data of the 0 subscript is empty, and build the tree from the second element, which is the element of the 1 subscript. This is also to be able to use the property 5 binary tree intuitively and conveniently to quickly build this tree.
Traversal of binary tree
After talking about the establishment of a binary tree, in fact, we have already come into contact with a form of traversal of a binary tree. Pay attention to the code in our tree creation method. We first assign values to the data of the node, then create the left and right child nodes of this node, and then continue to use the same operation to create all the nodes all the way. . Now, we reverse this operation. Instead of creating nodes, we read the contents of these nodes. First, read the contents of the nodes, and then read the contents of the left and right child nodes of this node. This is "first" Sequence traversal".
Preorder traversal
/**
* 前序遍历
*/
function PreOrderTraverse(?BiTree $t)
{
if ($t) {
echo $t->data, ',';
PreOrderTraverse($t->lChild);
PreOrderTraverse($t->rChild);
}
}
PreOrderTraverse($tree);
// A,B,D,H,I,E,J,K,C,F,L,M,G,N,O,
Isn’t it amazing? We even used the same traversal method to build a tree. It can be seen that traversal plays an important role for a complex data structure such as a binary tree.
You can see the order of the nodes read out by traversal, which seems to be different from the order we entered! That's right, pre-order traversal is through recursion, first in one direction to the end, when this node has no child nodes, through the characteristics of the recursive stack and then pop up. and output the content of the current node before traversing the child node. Note that this sentence is very important! So our order is A, B, D, H. When H has no child nodes, we return to the parent node D and then enter its right child node I. The specific order can be referred to the following figure:
The node order of pre-order traversal and pre-order tree building in our code is completely different. This point should also be clarified. property 5 binary tree, we directly specified the data subscript for it in the process of building the tree. In the traversal process, the entire tree is scanned and traversed node by node.
In-order traversal
As the name suggests, middle-order traversal actually outputs the content of the current node after traversing the left child node, so we only need to fine-tune the code of the first-order traversal.
/**
* 中序遍历
*/
function InOrderTraverse(?BiTree $t)
{
if ($t) {
InOrderTraverse($t->lChild);
echo $t->data, ',';
InOrderTraverse($t->rChild);
}
}
InOrderTraverse($tree);
// H,D,I,B,J,E,K,A,L,F,M,C,N,G,O,
The step of in-order traversal is that we will go directly to the leftmost child node first, when we encounter the last node, output the content, which is the H node in the figure, and then return to its parent node D node At this time, output D according to the principle of middle order, and then enter its right child node and output I. After the traversal of the subtree of node D and itself is completed, it returns to node B, the superior node of node D, outputs B, and then enters node E, the right child of node B. Enter the leftmost child node J of E again, and then refer to the traversal form of the D node to complete the traversal of the entire tree. Refer to the figure below for the specific sequence:
Post-order traversal
After learning the pre-order and middle-order, you can see from the name that the post-order is to output the content of the node after traversing the left and right children of a node. Of course, the code can be simply fine-tuned.
/**
* 后序遍历
*/
function PostOrderTraverse(?BiTree $t)
{
if ($t) {
PostOrderTraverse($t->lChild);
PostOrderTraverse($t->rChild);
echo $t->data, ',';
}
}
PostOrderTraverse($tree);
// H,I,D,J,K,E,B,L,M,F,N,O,G,C,A,
The specific principle will not be explained in detail. I believe that after learning the pre-order and middle-order, you will be able to immediately understand the meaning of post-order traversal. Directly on the picture:
Sequence traversal
Finally, what we are going to talk about is layer sequence traversal. Now that there is the keyword "layer", I believe everyone can immediately think of whether it is traversed layer by layer! That's right, layer sequence traversal means this. We output the corresponding node information layer by layer according to the level of the tree. It should be noted that here we will use the queue instead of the stack.
/**
* 层序遍历
*/
$q = InitLinkQueue();
function LevelOrderTraverse(?BiTree $t)
{
global $q;
if (!$t) {
return;
}
EnLinkQueue($q, $t);
$node = $q;
while ($node) {
$node = DeLinkQueue($q);
if ($node->lChild) {
EnLinkQueue($q, $node->lChild);
}
if ($node->rChild) {
EnLinkQueue($q, $node->rChild);
}
echo $node->data, ',';
}
}
LevelOrderTraverse($tree);
// A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,
InitLinkQueue() EnLinkQueue(), EnLinkQueue() These are the logical operation methods for the queue that we wrote when we learned the queue before. Isn’t it very happy? The previous knowledge is used again. The core idea of layer sequence traversal is to use the concept of queues. When a node is encountered, it will be put into the team, and then it will be judged whether it has sub-nodes, and then the sub-nodes will be put into the team one after another. Every time a node is traversed, the node at the head of the team is removed from the team, thus completing the ability to traverse the tree level. The text description is still too abstract, we still show this process through pictures:
Have you discovered that the output result of the layer sequence traversal is exactly the same as the array order when we built the tree. It's fun, so the world of code always has endless fun waiting for us to discover!
Summarize
Is there any confusion about today's content? If you are confused, find more information and study it carefully. The first, middle, and second order all use the stack to traverse the nodes of the tree, while the layer order traversal uses the queue. One after another, the content you learned before will come in handy! But this is just the beginning. When learning graphs, we will see stacks and queues again in depth traversal and breadth traversal. They are all relatives.
These four traversal methods often appear in exams and interviews. Whether it is their principle or drawing or writing various traversal sequences based on graphics, they are very common assessment content, so everyone is getting started in this article On the basis of, it is necessary to further understand these types of traversals based on some textbooks, and master them proficiently.
Test code:
Reference materials:
"Data Structure" Second Edition, Yan Weimin
"Data Structure" Second Edition, Chen Yue
"Data structure high score notes" 2020 edition, Tianqin postgraduate entrance examination
Searchable on their respective media platforms [Hardcore Project Manager]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。