Tree introduction
What is a tree?
- An abstract model of hierarchical data
- Common trees in front-end work include: DOM tree, cascading selection, tree controls…
- There are no trees in JS, but you can build trees with Object and Array.
- Common operations on trees: depth/width first traversal, middle first and order second traversal
What is depth/breadth first traversal?
- Depth-first traversal: Search as deep a branch of the tree as possible
- Breadth-first traversal: Visits the node closest to the root node first
Depth-first traversal algorithm solution
- Accessing the root node
- Children of root node are traversed depth-first one by one
const tree = {
val: 'a'.children: [{val: 'b'.children: [{val: 'd'.children: []}, {val: 'e'.children[],}],}, {val: 'c'.children: [{val: 'f'.children: []}, {val: 'g'.children: [],}],}],};/ / the recursive method
const dfs = (root) = >{
console.log(root.val);
root.children.forEach(item= >{
dfs(item);
})
}
dfs(tree);
// Print: a b D e c f g
Copy the code
Breadth-first traversal algorithm solution
- Create a queue and queue the root node
- Take the team leader out of the team and visit
- Put the children in the team one by one
- Repeat steps 2 and 3 until the queue is empty
const tree = {
val: 'a'.children: [{val: 'b'.children: [{val: 'd'.children: []}, {val: 'e'.children[],}],}, {val: 'c'.children: [{val: 'f'.children: []}, {val: 'g'.children: [],}],}],};/ / the recursive method
const bfs = (root) = >{
let q = [root];
while(q.length > 0) {const n = q.shift();
console.log(n.val);
n.children.forEach(item= >{
q.push(item);
})
}
}
bfs(tree);
// Print: abcdefg
Copy the code
What is a binary tree
- Each node in the tree can have a maximum of two child nodes
- Object is commonly used to simulate binary trees in JS
const binaryTree = {
val : 1.left: {val : 2.left : null.right: null
},
right: {val:3.left:null.right:null}}Copy the code
Sequential traversal method (root left and right)
- Accessing the root node
- Preemptive traversal of the left subtree of the root node
- Preemptive traversal of the right subtree of the root node
const bt = {
val: 1.left: {
val: 2.left: {
val: 4.left: null.right: null,},right: {
val: 5.left: null.right: null,}},right: {
val: 3.left: {
val: 6.left: null.right: null,},right: {
val: 7.left: null.right: null,}}};// Recursive method
const preorder = (root) = >{
if(! root){return;
}
console.log(root.val);
preorder(root.left);
preorder(root.right)
}
// Non-recursive methods
const preorder2 = (root) = >{
if(! root) {return; }const stack = [root];
while(stack.length){
const n = stack.pop();
console.log(n.val);
// Right is entered first and left is entered later
if(n.right){
stack.push(n.right);
}
if(n.left){
stack.push(n.left);
}
}
}
preorder(bt)
// Print: 1245367
Copy the code
Middle order traversal calculation method (left root right)
- Middle order traversal of the left subtree of the root node
- Accessing the root node
- Middle order traversal is performed on the right subtree of the root node
const bt = {
val: 1.left: {
val: 2.left: {
val: 4.left: null.right: null,},right: {
val: 5.left: null.right: null,}},right: {
val: 3.left: {
val: 6.left: null.right: null,},right: {
val: 7.left: null.right: null,}}};const preorder = (root) = >{
if(! root){return;
}
preorder(root.left);
console.log(root.val);
preorder(root.right)
}
const preorder2 = (root) = >{
if(! root) {return; }const stack = [];
let p = root;
while(stack.length || p){
while(p){
stack.push(p);
p = p.left;
}
const n = stack.pop();
console.log(n.val);
p = n.right;
}
}
preorder(bt)
// Print: 4 2 5 1 6 3 7
Copy the code
After order traversal calculation method (root left and right)
- A post-order traversal of the left subtree of the root node is performed
- A post-order traversal is performed on the right subtree of the root node
- Accessing the root node
const bt = {
val: 1.left: {
val: 2.left: {
val: 4.left: null.right: null,},right: {
val: 5.left: null.right: null,}},right: {
val: 3.left: {
val: 6.left: null.right: null,},right: {
val: 7.left: null.right: null,}}};const preorder = (root) = >{
if(! root){return;
}
preorder(root.left);
preorder(root.right)
console.log(root.val);
}
const preorder2 = (root) = >{
if(! root) {return; }// Left/right root --> back in first out: root right/left
const stack = [root];
const outputStack = [];
while(stack.length){
const n = stack.pop();
outputStack.push(n);
if(n.left){
stack.push(n.left);
}
if(n.right){ stack.push(n.right); }}while(outputStack.length){
const n = outputStack.pop();
console.log(n.val);
}
}
preorder(bt)
// Print: 4 5 2 6 7 3 1
Copy the code
LeetCode:104. Maximum depth of a binary tree
Their thinking
- To find the maximum depth, consider using depth-first traversal
- In the depth-first traversal process, record the level of each node and find the largest level
The problem solving steps
- Create a new variable to record the maximum depth
- Depth-first traverses the entire tree, recording the hierarchy of each node while constantly refreshing the maximum depth variable
- Return the maximum depth variable at the end of the traversal
The problem solving coding:
/** * Definition for a binary tree node. * function TreeNode(val, left, right) { * this.val = (val===undefined ? 0 : val) * this.left = (left===undefined ? null : left) * this.right = (right===undefined ? null : right) * } */
/ * * *@param {TreeNode} root
* @return {number}* /
var maxDepth = function(root) {
let res = 0;
const dfs = (n , len) = >{
if(! n){return ;
}
if(! n.left && ! n.right){ res =Math.max(res,len);
}
dfs(n.left, len + 1);
dfs(n.right, len + 1);
}
dfs(root,1);
return res;
};
Copy the code
LeetCode:111. Minimum depth of binary tree
Their thinking
- To find the minimum depth, consider using breadth-first traversal
- During breadth-first traversal, when a leaf node is encountered, the traversal is stopped and the node level is returned
The problem solving steps
- Breadth-first traverses the entire tree and records the hierarchy of each node
- When a leaf node is encountered, return to the node level and stop traversal
The problem solving coding:
/** * Definition for a binary tree node. * function TreeNode(val, left, right) { * this.val = (val===undefined ? 0 : val) * this.left = (left===undefined ? null : left) * this.right = (right===undefined ? null : right) * } */
/ * * *@param {TreeNode} root
* @return {number}* /
var minDepth = function(root) {
// breadth-first traversal + hierarchy
if(! root){return 0;
}
let q = [[root,1]].while(q.length){
let [n,len] = q.shift();
if(! n.left && ! n.right){return len;
}
if(n.left){
q.push([n.left,len+1])}if(n.right){
q.push([n.right,len+1])}}};Copy the code
LeetCode:102. Sequence traversal of binary trees
Their thinking
- The sequence traversal order is breadth-first traversal
- However, the hierarchy of the current node needs to be recorded during traversal so that it can be added to different arrays
The problem solving steps
- Breadth-first traversal of a binary tree
- As you traverse, you record the hierarchy of each node and add it to a different array
The problem solving Coding:
/** * Definition for a binary tree node. * function TreeNode(val, left, right) { * this.val = (val===undefined ? 0 : val) * this.left = (left===undefined ? null : left) * this.right = (right===undefined ? null : right) * } */
/ * * *@param {TreeNode} root
* @return {number[][]}* /
/ / method
var levelOrder2 = function(root) {
if(! root){return[]}let q = [[root,0]].const res = [];
while(q.length){
const [n,level] = q.shift();
if(! res[level]){ res.push([n.val]); }else{
res[level].push(n.val);
}
n.left && q.push([n.left,level + 1]);
n.right && q.push([n.right,level + 1]);
}
return res;
};
/ / method 2
var levelOrder = function(root) {
if(! root){return [];
}
const q = [root];
const res = [];
while(q.length){
let len = q.length;
res.push([]);/** add a layer */
while(len--){
const n = q.shift();
res[res.length - 1].push(n.val); n.left && q.push(n.left); n.right && q.push(n.right); }}return res;
}
Copy the code
LeetCode:94. Middle order traversal of binary trees
Middle order traversal (left middle right)
/** * Definition for a binary tree node. * function TreeNode(val, left, right) { * this.val = (val===undefined ? 0 : val) * this.left = (left===undefined ? null : left) * this.right = (right===undefined ? null : right) * } */
/ * * *@param {TreeNode} root
* @return {number[]}* /
/ * * recursion * /
var inorderTraversal = function(root) {
const res = [];
const inorder = (root) = > {
if(! root) {return;
}
inorder(root.left);
res.push(root.val);
inorder(root.right);
}
inorder(root);
return res;
};
/ * / * * iteration
var inorderTraversal = function(root) {
const res = [];
const stk = [];
while (root || stk.length) {
while (root) {
stk.push(root);
root = root.left;
}
root = stk.pop();
res.push(root.val);
root = root.right;
}
return res;
};
Copy the code
Leetcode:112. Sum of paths
Their thinking
- During depth-first traversal, the sum of the node values of the current path is recorded
- At the leaf node, determine whether the sum of the node values of the current path equals the target value
The problem solving steps
- Depth first traverses binary tree. At leaf nodes, judge whether the sum of node values of the current path equals the target value, and return true if so
- If there is no match, false is returned
The problem solving coding
/** * Definition for a binary tree node. * function TreeNode(val, left, right) { * this.val = (val===undefined ? 0 : val) * this.left = (left===undefined ? null : left) * this.right = (right===undefined ? null : right) * } */
/ * * *@param {TreeNode} root
* @param {number} targetSum
* @return {boolean}* /
var hasPathSum = function(root, targetSum) {
if(! root){return false;
}
let res = false;
const dfs = (n,val) = >{
if(! n.left && ! n.right && val === targetSum){ res =true;
}
n.left && dfs(n.left, val + n.left.val);
n.right && dfs(n.right, val + n.right.val);
}
dfs(root,root.val);
return res;
};
Copy the code
Front-end and tree: Traverses all node values of JSON
const json = {
a: {b: {c:1}},
d: [1.2]};const dfs = (n,path) = >{
console.log(n,path);
Object.keys(n).forEach(k= >{
console.log(k)
dfs(n[k],path.concat(k));
})
}
dfs(json,[])
Copy the code