dfs
Depth-First-Search is a kind of search algorithm. It traverses the nodes of the tree along the depth of the tree and searches the branches of the tree as deep as possible. When all edges of node v have been explored, it will be traced back to the starting node on the side where node v was found. This process continues until the source node has been explored to all other nodes. If there are still undiscovered nodes, select one of the undiscovered nodes as the source node and repeat the above operation until all nodes have been explored.
Simply put, DFS traces back from one node in the graph to the last one, and then traces back to the next path until it reaches all the nodes, so it goes back and forth until there is no path.
DFS and BFS are generally used to solve the traversal of graphs, but here, since they are the front-end, I use DFS and BFS to traverse DOM trees.
The following is implemented in the form of stack or recursion:
DOM Node
<div class="parent"> <div class="c-1"> <div class="c-1-1"> </div> <div class="c-1-2"> </div> <div class="c-1-3"> </div> <div class="c-1-4"> </div> <div class="c-1-5"> </div> </div> <div class="c-2"> <div class="c-2-1"> </div> <div class="c-2-2"> </div> <div class="c-2-3"> </div> <div class="c-2-4"> <div class="c-2-4-1"> </div> <div class="c-2-4-2"> </div> <div class="c-2-4-3"> </div> <div class="c-2-4-4"> </div> <div class="c-2-4-5"> </div> </div> <div class="c-2-5"> </div> </div> <div class="c-3"> </div> <div class="c-4"> </div> </div>
DFS Implementation
var node = document.querySelectorAll('.parent')[0]; //Recursive Writing function DFS1 (node, nodeList = []){ if (node != null){ nodeList.push(node); let children = node.children for(let i = 0; i < children.length; i++){ DFS1(children[i], nodeList) } } return nodeList } let nodeList = DFS1(node); console.log(nodeList); //Stack Writing function DFS2(node){ let nodeList = []; if (node){ //Stack Last in First Out let stack = []; stack.push(node); while (stack.length) { let _node = stack.pop(); nodeList.push(_node); let children = _node.children; //It's written from right to left. // for (let i = 0; i < children.length; i++) { // stack.push(children[i]); // } //right for (let i = children.length-1; i >= 0; i--) { stack.push(children[i]); } } } return nodeList; } let nodeList2 = DFS2(node); console.log(nodeList2);
As a result, the above DFS1 and DFS2 results are the same.
breadth-first search
Breadth-First-Search starts from the root node and traverses the nodes along the width of the graph. If all the nodes have been visited, the algorithm terminates. BFS is also a blind search. Queue data structure is generally used to assist the implementation of BFS.
Or use the DOM node above. BFS is written as follows.
The code is implemented as a queue.
var node = document.querySelectorAll('.parent')[0]; function BFS1(node, nodeList = []) { if (!node){ return; } //Queue first in first out var sequeue = []; sequeue.push(node); while (sequeue.length){ var _node = sequeue.shift(); nodeList.push(_node) for(var i = 0; i < _node.children.length; i++){ sequeue.push(_node.children[i]) } } return nodeList } let nodeList = BFS1(node); console.log(nodeList);
give the result as follows
There are two ways to realize object deep cloning.
DFS deep cloning
Two issues should be paid attention to in-depth cloning
1. Ring Data Problem: If an object has a ring object, such as obj.a.b.c==== obj.a, it will cause recursion to go into a dead loop, leading to stack explosion errors.
2. Boundary Processing: There are not only primitive types in objects, but also data types such as functions and Set s. We need to deal with them one by one. The following code only solves the problem of duplication of functions.
let _toString = Object.prototype.toString; let map = { array: 'Array', object: 'Object', function: 'Function', string: 'String', null: 'Null', undefined: 'Undefined', boolean: 'Boolean', number: 'Number' } function getType(obj){ return _toString.call(obj).slice(8, -1) } function isTypeOf(obj, type){ return map[type] && map[type] === getType(obj) } //Deep Cloning //dfs /** * * Solve three recursive problems. Ring data problem boundary processing (such as function, Set, etc.) */ const DFSdeepClone = function (obj, visitedArr = []){ let _obj = {}; if (isTypeOf(obj, 'array') || isTypeOf(obj, 'object')){ let index = visitedArr.indexOf(obj); if (index > -1){ _obj = visitedArr[index] } else{ visitedArr.push(obj) for (let key in obj){ _obj[key] = DFSdeepClone(obj[key], visitedArr) } } } else if(isTypeOf(obj, 'function')){ _obj = eval( '(' + obj.toString() + ')')//Processing function } else{ _obj = obj;//Processing raw values } return _obj; } let testObj = { a: 1, b: { c: 1, d: 2 }, circle: null, e: function() { console.log(1); } } let cloneTestObj = DFSdeepClone(testObj); let cloneTestObj2 = testObj; console.log(cloneTestObj); console.log('Changes after deep cloning'); cloneTestObj.b = {};//Changes after deep cloning console.log(cloneTestObj); console.log(testObj); cloneTestObj2.b = {}; //Changes to references console.log('Changes to references'); console.log(cloneTestObj2); console.log(testObj); //Ring data let testCircle = { a: 1, b: { c: 1, d: 2, circle: null, }, e: function() { console.log(1); } } testCircle.b.circle = testCircle.b; cloneTestCircle = DFSdeepClone(testCircle);//Not dealing with the ring problem is going to explode the stack into a dead loop. console.log(cloneTestCircle);
BFS deep cloning
let _toString = Object.prototype.toString; let map = { array: 'Array', object: 'Object', function: 'Function', string: 'String', null: 'Null', undefined: 'Undefined', boolean: 'Boolean', number: 'Number' } function getType(obj){ return _toString.call(obj).slice(8, -1) } function isTypeOf(obj, type){ return map[type] && map[type] === getType(obj) } //Breadth-first in-depth cloning and queuing //Use copyObj to build a data structure identical to the original object, and assign processable values (such as original values, functions) to the corresponding nodes after processing. const BFSdeepClone = function (obj, visitedArr = []){ let copyObj = {}; let sequeue = [obj];//Enter the queue //At the same time, copyObj joined the queue. let copySequeue = [copyObj]; while(sequeue.length){ let _obj = sequeue.shift(); let _copyObj = copySequeue.shift(); if (isTypeOf(_obj, 'array') || isTypeOf(_obj, 'object')){ for(item in _obj){ let val = _obj[item]; if (isTypeOf(val, 'object')){ let index = visitedArr.indexOf(val) if (~index){ //It's circular data. _copyObj[item] = visitedArr[index]; } else{ //New object, give copyObj an empty object with corresponding attributes sequeue.push(val); _copyObj[item] = {}; copySequeue.push(_copyObj[item]); visitedArr.push(val); } } else if (isTypeOf(val, 'array')){ sequeue.push(val); _copyObj[item] = []; copySequeue.push(_copyObj[item]) } else if(isTypeOf(val, 'function')){ _copyObj[item] = eval( '(' + val.toString() + ')');//Processing function } else{ _copyObj[item] = val;//Processing raw values } } } else if(isTypeOf(obj, 'function')){ _copyObj = eval( '(' + _obj.toString() + ')');//Processing function } else{ _copyObj = _obj;//Processing raw values } } return copyObj } let testObj = { a: 1, b: { c: 1, d: 2 }, circle: null, e: function() { console.log(1); } } let cloneTestObj = BFSdeepClone(testObj); let cloneTestObj2 = testObj; console.log(cloneTestObj); //Ring data let testCircle = { a: 1, b: { c: 1, d: 2, circle: null, }, e: function () { console.log(1); } } testCircle.b.circle = testCircle.b; cloneTestCircle = BFSdeepClone(testCircle);//Not dealing with the ring problem is going to explode the stack into a dead loop. console.log(cloneTestCircle); /** * Print as follows { a: 1, b: { c: 1, d: 2 }, circle: null, e: [Function] } { a: 1, b: { c: 1, d: 2, circle: { c: 1, d: 2, circle: [Circular] } }, e: [Function] } */