Binary tree definition
A binary tree is a tree structure that has the following characteristics:
- Each node has at most two subtrees, that is, no node with a degree greater than 2 (degree is the number of direct subnodes of the tree node).
- The subtrees of a binary tree have left and right subtrees, and their order cannot be arbitrarily reversed
What does a binary tree do?
The BST that Babel builds at compile time is a binary tree, the DIff in vue, and the virtual DOM, all of which are dependent on binary trees. Binary tree power is far more than this, the use of binary tree before the order traversal display directory structure, the use of binary tree sequence traversal to achieve expression tree, in the compiler is very useful, the use of binary tree subsequent traversal to achieve the calculation of directory files and information. In a word, binary tree on the computer field can be said to be everywhere, skilled use of binary tree, improve the efficiency of the program, improve the readability of the program, so many advantages, quickly learn ah
Binary tree traversal
In general, there are four ways to traverse a binary tree
- Fore-order traversal: parent -> left -> right subtree
- Middle order traversal: left subtree -> parent -> right subtree
- Back-order traversal: left subtree -> right subtree -> parent
- Hierarchical traversal: accesses all nodes of the current layer layer by layer, from top to bottom and left to right
Chestnuts, as shown
Previous traversal result: ABDHIECFG
Middle order traversal result: HDIBEAFCG
Subsequent traversal result: HIDEBFGCA
Hierarchy traversal: ABCDEFGHI
JS binary tree expression
“node“
function TreeNode(val) {
this.val = val;
this.left = this.right = null;
}
Copy the code
“Convert the above image to a tree in JS:“
var tree = {
val: "A",
left: {
val: "B",
left: {
val: "D",
left: {
val: "H",
left: null,
right: null
},
right: {
val: "I",
left: null,
right: null
}
},
right: {
val: "E",
left: null,
right: null
}
},
right: {
val: "C",
left: {
val: "F",
left: null,
right: null
},
right: {
val: "G",
left: null,
right: null
}
}
}
Copy the code
Through the calendar calculation method
Generally speaking, tree traversal can be divided into recursive traversal and non-recursive traversal. The advantage of recursive traversal is that the code is simple and easy to understand, but the disadvantage is that the execution efficiency is low. Non-recursive traversal is just the opposite, efficient, but large amount of code, difficult to understand. The following three recursive traversal methods are introduced. In fact, they can also be used as templates. The essence of many problems about binary trees still lies in traversal.
The recursive traversal
“Sequential traversal (recursion) :“
Function preOrder(root) {if(root) {console.log(root.value) PreOrder (root.left) preOrder(root.right)}}Copy the code
“Middle order traversal (recursive) :“
function inOrder(root) {
if(root) {
inOrder(root.left)
console.log(root.val)
inOrder(root.right)
}
}
Copy the code
“Post-order traversal (recursion) :“
function postOrder(root) {
if(root) {
postOrder(root.left)
postOrder(root.right)
console.log(root.val)
}
}
Copy the code
Test the binary tree defined above
PreOrder (tree) // ABDHIECFG inOrder (tree) // HDIBEAFCG postOrder (tree) // HIDEBFGCACopy the code
As expected, by the way, the above three recursive traversals are implemented using the system stack.
Non-recursive traversal
Next, I’ll introduce non-recursive methods, which may be harder to understand than recursion, but will be easier to write if you get to the core
“Sequential traversal (non-recursive) :“
function preOrder(root) {
if(! root) {return false} // Stop if the root node is empty
let stack = [] // Initialization stack, used to store already accessed nodes, easy to trace back
let p = root // Assign the root node to p
while(stack.length || p) { // the stack is not empty or p is not empty
if(p) { // When p is not empty, go straight to the left, remembering to visit the node first and then push the node console.log(p.val) stack.push(p) p = p.left } else { // When p is empty, take the last node you passed and go right p = stack.pop() p = p.right } } } Copy the code
“Middle-order traversal (non-recursive) :“
function inOrder(root) {
if(! root) {return false} // Stop if the root node is empty
let stack = [] // Initialization stack, used to store already accessed nodes, easy to trace back
let p = root // Assign the root node to p
while(stack.length || p) { // the stack is not empty or p is not empty
if(p) { // When p is not empty, go straight to the left. This is the difference from the previous traversal stack.push(p) p = p.left } else { // When p is empty, take the last node you passed and go right p = stack.pop() console.log(p.val) p = p.right } } } Copy the code
I don’t know if you noticed, it’s almost the same as the previous sequence, but the difference is when to access the node. The front order is to press the stack and then access, the middle order is to press the stack first, and then access out of the stack.
“Post-order traversal (non-recursive)“
Many people think that the subsequent traversal is the most difficult. Indeed, if you write it in the order of left -> right -> root, it will involve the judgment of the access state of the node, which will be more complicated. But I’m not going to do that, I want you to be able to write down the middle order and the back order as soon as you’ve mastered pre-order traversal and non-recursion. Trust me, ok? My idea is this: “The order of backward traversal is left -> right -> root, right? So if I first traversal in the way of root -> right -> left, and then invert the result, it becomes left -> right -> root.” Most importantly, if you iterate root -> right -> left, you’re going to iterate pretty much the same way, just changing a line or two. Here is the code that follows the above thread
function postOrder(root) {
if(! root) {return false} // Stop if the root node is empty
let stack = [] // Initialization stack, used to store already accessed nodes, easy to trace back
let result = [] // Save the root -> right -> left access results, to the end of the reverse output
let p = root // Assign the root node to p
while(stack.length || p) { // the stack is not empty or p is not empty if(p) { // When p is not empty, go straight to the right, remember to visit the node first and then push the node result.push(p.val) // If the value of the node is pushed on the stack, the output of the whole stack will be inverted stack.push(p) p = p.right / / right } else { // When p is empty, take the last node that passes through and go left p = stack.pop() p = p.left } } result.reverse().forEach(val= > console.log(val)) // Reverse the output, this is the result of the order traversal } Copy the code
You see, this is much easier, the main idea is still pretty much the same as the previous iteration, with a stack to store the results
Okay, now for the last one, hierarchical traversal. There is no recursion for hierarchical traversal, we maintain access in layer order through an array of simulated queues. The root node is first queued. When the queue is not empty, the body of the loop is executed: the first node of the queue is taken out. If the node has a left subtree, the left subtree of the node is put into the queue. If the node has a right subtree, the right subtree of the node is queued. The loop then continues until the queue is empty.
Level traversal
function floorOrder(root) {
if(! root) {return false} // Stop if the root node is empty
let queue = [] // Initialize the queue
queue.push(root) // The root node joins the queue
while(queue.length) { // If the queue is not empty, the loop body continues
let p = queue.shift() // take the first node of the queue and assign it to p. Note that the queue length has been reduced by 1 since the queue exit console.log(p.val) if(p.left) { // if the left node of p is not empty, the queue is joined queue.push(p.left) } if(p.right) { // If the right node of p is not empty, the queue is joined queue.push(p.right) } } } Copy the code
conclusion
Binary tree are introduced in this definition, characteristics, USES, node data structure before and after the sequence of the recursive non-recursive algorithm, and hierarchical calendar calculation method, your friend can take the algorithm implementation whether to run the result is right, if where there is not the right place, eager to friends can leave a message under the feedback, thanks! Personally, for the above introduction to the way of traversal, can be used as a template to remember, do not understand can be used to simulate the implementation of the algorithm, painting painting you may understand! Binary tree traversal is the basis of binary tree correlation algorithm, we must be skilled, come on together!
My personal website: www.jianfengke.com/
This article is formatted using MDNICE