目录
一、前序遍历
二、中序遍历
三、后序遍历
四、层序遍历
五、路径遍历
之前参加一家公司面试被问到二叉树的相关非递归遍历算法,顿时懵逼,只记得递归算法的我瑟瑟发抖,下来之后就作了不少的功课。接下来要分享的,都是我经过对比之后选择的较为简单的非递归遍历方法,使用js语言。如有不足,还望指教。
假设一棵二叉树的结构为
使用栈的数据结构。初始化一个栈数组和结果数组
1.将根节点放入栈中, 栈:[1]
2.取出栈顶的节点,将其放入结果数组中, 结果数组: [1],栈: []
3.将取出的节点的右节点放入栈中, 栈: [3]
4.将取出的节点的左节点放入栈中,栈:[3,2]
5.回到步骤2(循环步骤2-4,直到栈为空)取出栈顶节点,将其放入结果数组中,结果数组:[1,2], 栈:[3]
6.将取出的节点的右节点放入栈中, 栈: [3,5]
7.将取出的节点的左节点放入栈中,栈: [3,5,4]
8.回到步骤2....
最后得到结果数组[1,2,4,5,3,6,7]
var preorderTraversal = function(root) {
let nodestack = [];
let res = [];
nodestack.push(root);
if(root===null){
return [];
}
while(nodestack.length>0){
let node = nodestack.pop();
res.push(node.val);
if(node.right){
nodestack.push(node.right);
}
if(node.left){
nodestack.push(node.left);
}
}
return res;
};
使用栈的数据结构。初始化一个栈数组和结果数组。
1.把根节点放入栈中,然后将根节点重新赋值为根节点的左节点,直到根节点为空。栈: [1,2,4],root = null
2.取出栈顶节点,并将其赋值为根节点,然后将其值放入结果数组,结果数组: [4],栈: [1,2], root = 4
3.将根节点赋值为根节点的的右节点,root = null
4.回到第一步,因为root已经为null,直接到第二步
5.取出栈顶节点,并将其赋值为根节点,然后将其值放入结果数组,结果数组: [4,2],栈: [1], root = 2
6.将根节点赋值为根节点的右节点,root = 5
7.回到步骤1....
最后的结果数组为[4,2,5,1,6,3,7]
var inorderTraversal = function(root) {
let nodestack = [];
let res = [];
if(root===null){
return [];
}
while(root!==null||nodestack.length>0){
while(root!==null){
nodestack.push(root);
root = root.left;
}
root = nodestack.pop();
res.push(root.val);
root=root.right;
}
return res;
};
后序遍历的思路很妙,事实上只需要记住,后序遍历就是与前序遍历的完全相反的算法。
1.将根节点放入栈中,栈: [1]
2.取出栈顶的节点,将其从左边插入结果数组,结果数组:[1],栈:[]
3.将取出的节点的左节点放入栈,栈:[2]
4.将取出的节点的右节点放入栈,栈: [2,3]
5.回到步骤2,取出栈顶的节点,将其从左边插入结果数组,结果数组:[3,1],栈:[2]
6.将取出的节点的左节点放入栈,栈:[2,6]
7.将取出的节点的右节点放入栈,栈: [2,6,7]
8.回到步骤2,取出栈顶的节点,将其从左边插入结果数组,结果数组:[7,3,1],栈:[2,6]
9. .....
最后的结果数组:[4,5,2,6,7,3,1]
var postorderTraversal = function(root) {
let nodestack = [];
let res = [];
if(root===null){
return [];
}
nodestack.push(root);
while(nodestack.length>0){
let node = nodestack.pop();
res.unshift(node.val);
if(node.left){
nodestack.push(node.left);
}
if(node.right){
nodestack.push(node.right);
}
}
return res;
};
使用了队列的数据结构,遍历得到每一层的节点。
1.将根节点放入队列,使层数初始化为第0层,队列: [1],level: 0
2.将遍历队列,将队列中的节点取出,放入结果数组索引为层数的数组中,并将节点的左节点和右节点放入队列,结果数组:[[1]], 队列: [2,3]
3. 层数加一,level: 1
4.回到步骤2,遍历队列,将队列中的节点取出,放入结果数组索引为层数的数组中,并将节点的左节点和右节点放入队列,结果数组:[[1],[2,3]], 队列: [4,5,6,7]
5.层数加一,level: 2
6.回到步骤2,遍历队列,将队列中的节点取出,放入结果数组索引为层数的数组中,并将节点的左节点和右节点放入队列,结果数组:[[1],[2,3], [4,5,6,7]], 队列: []
7.队列为空,循环结束,结果数组为[[1],[2,3], [4,5,6,7]]
var levelOrder = function(root) {
let nodequeue = [];
let res = [];
if(root===null){
return [];
}
nodequeue.push(root);
let level = 0;
while(nodequeue.length>0){
res[level] = [];
let len = nodequeue.length;
for(let i=0;i
使用了两个栈,一个节点栈、一个路径栈
1.将根节点放入节点栈,根节点的值放入路径栈, 节点栈:[1],路径栈:[1]
2.将节点栈栈顶的节点取出赋值给node,将路径栈栈顶的值取出赋值给path ,node: 1, path: 1
3.如果node节点为叶子节点,则将path从左边插入结果数组。
4.将node的左节点放入节点栈,将path+"->"+node的左节点值放入路径栈,节点栈: [2], 路径栈:[1, 1->2]
5.将node的右节点放入节点栈,将path+"->"+node的右节点值放入路径栈,节点栈: [2,3], 路径栈:[1, 1->2,1->3]
6.回到步骤2,将节点栈栈顶的节点取出赋值给node,将路径栈栈顶的值取出赋值给path ,node: 3, path: 1->3
7.如果node节点为叶子节点,则将path从左边插入结果数组。
8.将node的左节点放入节点栈,将path+"->"+node的左节点值放入路径栈,节点栈: [2, 6], 路径栈:[1, 1->2, 1->3->6]
9.将node的右节点放入节点栈,将path+"->"+node的右节点值放入路径栈,节点栈: [2, 6, 7], 路径栈:[1, 1->2, 1->3->6, 1->3->7]
10,回到步骤2,将节点栈栈顶的节点取出赋值给node,将路径栈栈顶的值取出赋值给path ,node: 7, path: 1->3->7
11.此时node节点为叶子节点,将path从左边插入结果数组,结果数组:[1->3->7]
12.......
最后结果数组为[1->2->4, 1->2->5, 1->3->6,1->3->7]
var binaryTreePaths = function(root) {
var nodestack = [];
var res = [];
var pathstack = [];
if(root===null){
return res;
}
nodestack.push(root);
pathstack.push(root.val.toString());
while(nodestack.length>0){
let node = nodestack.pop();
let path = pathstack.pop();
if(node.left===null&&node.right===null){
res.unshift(path);
}
if(node.left){
nodestack.push(node.left);
pathstack.push(path+"->"+node.left.val);
}
if(node.right){
nodestack.push(node.right);
pathstack.push(path+"->"+node.right.val);
}
}
return res;
};