深度优先遍历(DFS)
深度优先遍历(Depth-First-Search)是从根节点开始追溯,直到最后一个节点,然后回溯,继续追溯下一条路径,直到到达所有的节点,如此往复,直到没有路径为止。深度DFS属于盲目搜索,无法保证搜索到的路径为最短路径,也不是在搜索特定的路径,而是通过搜索来查看有哪些路径可以选择。
简单的树形结构示例
// 1
// 2 3
// 4 5 6 7
//8 9
var tree = {
val: 1,
left: {
val: 2,
left: {
val: 4,
left: {
val: 8
}
},
right: {
val: 5
}
},
right: {
val: 3,
left: {
val: 6
},
right: {
val: 7,
right: {
val: 9
}
}
}
}
// 深度优先遍历,利用栈,从根节点开始,依次将右、左节点入栈
// 后进先出,优先遍历后push进的数据
function dfs(tree) {
let stack = [tree],
result = []
while (stack.length) {
let last = stack.pop()
result.push(last.val)
let left = last.left,
right = last.right
if (right) stack.push(right)
if (left) stack.push(left)
}
return result
}
console.log(dfs(tree)) // [ 1, 2, 4, 8, 5, 3, 6, 7, 9 ]
广度优先遍历(BFS)
广度优先遍历(Breadth-First-Search)是从根节点开始,沿着图的宽度遍历节点,如果所有节点均被访问过,则算法终。BFS 同样属于盲目搜索,一般用队列数据结构来辅助实现BFS。
// 广度优先遍历,利用队列,先进先出,从根节点开始,依次将左节点、右节点push进数组
// 先进先出,优先遍历已经push进数组的数据
function bfs(tree) {
let queue = [tree],
result = []
while (queue.length) {
let first = queue.shift()
result.push(first.val)
let left = first.left,
right = first.right
if (left) queue.push(left)
if (right) queue.push(right)
}
return result
}
console.log(bfs(tree)) // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
应用
1.树形结构转数组
利用数组转树形结构得到一个树形结构
let arr = [
{ pid: 0, id: 1, name: '1' },
{ pid: 1, id: 2, name: '2' },
{ pid: 1, id: 3, name: '3' },
{ pid: 2, id: 4, name: '4' },
{ pid: 2, id: 5, name: '5' },
{ pid: 3, id: 6, name: '6' },
{ pid: 3, id: 7, name: '7' },
{ pid: 4, id: 8, name: '8' },
{ pid: 5, id: 9, name: '9' },
];
let tree = arrayToTree(arr)
function DFS(tree){
tree = [...tree]
let result = [];
while(tree.length){
let last = tree.pop();
result.push({ pid: last.pid, id: last.is, name: last.name });
let children = last.children;
if(children&&children.length){
for(let i = children.length - 1; i >= 0; i--){
tree.push(children[i])
}
}
}
return result
}
console.log(DFS(tree))
// [
// { pid: 0, id: undefined, name: '1' },
// { pid: 1, id: undefined, name: '2' },
// { pid: 2, id: undefined, name: '4' },
// { pid: 4, id: undefined, name: '8' },
// { pid: 2, id: undefined, name: '5' },
// { pid: 5, id: undefined, name: '9' },
// { pid: 1, id: undefined, name: '3' },
// { pid: 3, id: undefined, name: '6' },
// { pid: 3, id: undefined, name: '7' }
// ]
function BFS(tree){
tree = [...tree]
let result = [];
while(tree.length){
let first = tree.shift();
result.push({ pid: first.pid, id: first.is, name: first.name });
let children = first.children;
if(children&&children.length){
for(let i = 0; i < children.length; i++){
tree.push(children[i])
}
}
}
return result;
}
console.log(BFS(tree))
// [
// { pid: 0, id: undefined, name: '1' },
// { pid: 1, id: undefined, name: '2' },
// { pid: 1, id: undefined, name: '3' },
// { pid: 2, id: undefined, name: '4' },
// { pid: 2, id: undefined, name: '5' },
// { pid: 3, id: undefined, name: '6' },
// { pid: 3, id: undefined, name: '7' },
// { pid: 4, id: undefined, name: '8' },
// { pid: 5, id: undefined, name: '9' }
// ]
2.全排列
将数组中的项进行全排列,得到所有的可能的排列结果
function fn(arr){
let result = [];
let len = arr.length, map = {}, path = [];
function dfs(){
if(path.length === len){
result.push([...path]);
return
}
for(let i = 0; i < len; i++){
if(!map[i]){
map[i] = true;
path.push(arr[i]);
dfs();
map[i] = false;
path.pop()
}
}
}
dfs()
return result
}
console.log(fn([1,2,3,4]))
// [
// [1, 2, 3, 4], [1, 2, 4, 3],
// [1, 3, 2, 4], [1, 3, 4, 2],
// [1, 4, 2, 3], [1, 4, 3, 2],
// [2, 1, 3, 4], [2, 1, 4, 3],
// [2, 3, 1, 4], [2, 3, 4, 1],
// [2, 4, 1, 3], [2, 4, 3, 1],
// [3, 1, 2, 4], [3, 1, 4, 2],
// [3, 2, 1, 4], [3, 2, 4, 1],
// [3, 4, 1, 2], [3, 4, 2, 1],
// [4, 1, 2, 3], [4, 1, 3, 2],
// [4, 2, 1, 3], [4, 2, 3, 1],
// [4, 3, 1, 2], [4, 3, 2, 1]
// ]
3.合法的括号对组合
function fn(n){
let result = [];
function dfs(s, left, right){
if(left < right || (left + right) > 2*n) return
if(left === n && right === n){
result.push(s)
return;
}
dfs(s+'(', left+1, right)
dfs(s+')', left, right+1)
}
dfs('', 0, 0)
return result
}
console.log(fn(3))
// [ '((()))', '(()())', '(())()', '()(())', '()()()' ]
暂时能想到的应用就这些,以后随时添加。
以上全部内容,如有疑问,欢迎指正。