如标题所示,需要找出二叉树的所有的路径!看下图:
上图是一个完全二叉树!找出此树的所有的路径!我们来试着想下常用的方法? 首先深度优先遍历(可以用递归,也可以用栈的思想),也可以用广度优先遍历(也可以用队列的思想),那么我们来试下每种方法的实现!下面是模拟的测试数据!
模拟的数据:
let tree = {
"val": 1,
"left": {
"val": 2,
"left": {
"val": 4,
"left": {
"val": 8
},
"right": {
"val": 9
}
},
"right": {
"val": 5
}
},
"right": {
"val": 3,
"left": {
"val": 6
},
"right": {
"val": 7
}
}
};
一 .深度优先遍历
1.递归方法
其实用递归的话,主要找到基线条件和递归条件就行,否则将会进入死循环!那么什么时候不需要递归了呢,那就是找到叶子结点(下面没有任何子结点),此路径就是一个完整的路径!如果找到的不是叶子结点,那就继续遍历改结点的每个孩子结点!
let findTreePath = (tree) => {
let pathArrs = [];//保存所有路径的数组
let map = (tree, pathArr) => {
if (tree) {
pathArr.push(tree.val);
if (!tree.left && !tree.right) {
pathArrs.push(pathArr);
} else {
map(tree.left, [...pathArr]);//这里需要深拷贝下pathArr
map(tree.right, pathArr);
};
};
};
map(tree, []);
return pathArrs;
};
console.log(findTreePath(tree));
2.栈的思想
先说下思路,首先遍历出左侧树,然后将左侧节点一个一个放进栈中,取出栈中的最后节点(叶子节点),拼接成路径加入到答案中,然后最后个节点出栈,接着判断最后个节点是不是叶子节点,不是的话,接着遍历右侧树节点然后放入栈中,直到找到叶子节点,拼接成路径加入到答案中,如果是的话,直接拼接成路径加入到答案中,说的不是很清楚,看下面的代码,注释写的很清楚!
let findTreePath = (tree) => {
let stack = [];//存放栈的数组
let pathArrs = [];//存放多条路径的数组
let rightArr = [];//存放右侧节点的数组,防止重复遍历
while (stack.length > 0 || tree) {
while (tree) {
stack.push(tree); //将左侧的结点放入栈中
tree = tree.left;
};
var node = stack[stack.length - 1]; //取栈中最后一个元素
if (node.right && !rightArr.includes(node.right)) { //往右子树找,防止重复访问
rightArr.push(node.right);
tree = node.right;//往右子树开始找
} else {
if (!node.right && !node.left) {//判断是否为叶子节点
var pathArr = [];
stack.map(p => {
pathArr.push(p.val); //拼接路径
});
pathArrs.push(pathArr); //存放得到的路径
};
stack.pop();//最后个元素出栈
};
}
return pathArrs;
};
console.log(findTreePath(tree));
二 .广度优先遍历
我们也可以用广度优先搜索来实现。我们维护一个队列,存储节点以及根到该节点的路径。一开始这个队列里只有根节点。在每一步迭代中,我们取出队列中的首节点,如果它是叶子节点,则将它对应的路径加入到答案中。如果它不是叶子节点,则将它的所有孩子节点加入到队列的末尾。当队列为空时广度优先搜索结束,我们即能得到答案
let findTreePath = function (root) {
const paths = [];//答案数组
if (root === null) {
return paths;
}
const node_queue = [root];
const path_queue = [
[root.val]
];
while (node_queue.length) {
const node = node_queue.shift();//取出队列第一个节点
const path = path_queue.shift();//取出队列第一个路径
if (!node.left && !node.right) {
paths.push(path);//是叶子节点放入答案中
} else {
if (node.left !== null) {
const pathCopy = [...path];//复制一份数组
pathCopy.push(node.left.val);//拼接路径
node_queue.push(node.left);//把子节点放入队列中
path_queue.push(pathCopy);//把拼接好的路径放入队列中
}
if (node.right !== null) {
const pathCopy = [...path];//复制一份数组
pathCopy.push(node.right.val);//拼接路径
node_queue.push(node.right);//把子节点放入队列中
path_queue.push(pathCopy);//把拼接好的路径放入队列中
}
}
};
return paths;//返回最终的答案(所有的路径)
};
console.log(findTreePath (tree));