1.常用的二叉树的遍历方式:
(1)前序遍历:根、左、右;
(2)中序遍历:左、根、右;
(3)后续遍历:左、右、根;
因为前序遍历和后序遍历比较像,所以我们先上考察比较多的中序遍历
2.中序遍历
2.1栈方法
-
若当前节点存在,就存入栈中,并访问左子树;
-
直到当前节点不存在,就出栈放入结果数组,并通过栈顶节点访问右子树;
-
不断重复前面两步,直到当前节点不存在且栈为空
-
图画演示:
- 从1到4都存在,于是依次存入栈中,访问4的左子树,左子树不存在,将4出栈放入数组,访问4的右子树,右子树不存在,继续从栈顶取出3,访问3的右子树,3的右节点存在,所以将5入栈
- 从1到4都存在,于是依次存入栈中,访问4的左子树,左子树不存在,将4出栈放入数组,访问4的右子树,右子树不存在,继续从栈顶取出3,访问3的右子树,3的右节点存在,所以将5入栈
-
5入栈,访问其左子树,左子树不存在,即将5取出栈顶,并访问其右子树,右子树为空,即将2取出栈顶,并访问其右子树,其右子树为空,即将栈顶1取出,访问1的右子树,右子树为6,将6入栈,反复…
-
通过上面图表可知,每次查找的节点不存在时,即出栈;最后栈为空,没有下一节点的时候结束
-
代码为:
let inOrderTraversal = function(root) {
if(!root) return [];
const stack = []; //先定义一个栈
const res = []; //定义存放最后顺序结果的数组
let cur = root ; //指向树的首结点
while(cur || stack.length!=0){
//左节点依次压入栈中
while(cur){
stack.push(cur);
cur = cur.left;
}
//跳出上面的循环说明左节点为空了,那此时应该从栈顶取出元素
let node = stack.pop();
res.push(node.val);
//查找其右节点,若存在,cur指向该节点
if(node.right != null){
cur = node.right
}
}
return res
}
2.2递归方法
- 左子树——根节点——右子树的方式遍历这棵树,而在访问左子树或者右子树的时候我们按照同样的方式遍历,直到遍历完整棵树
let inOrderTraversal = function(root,arr=[]){
if(root){
inOrderTraversal(root.left,arr);
arr.push(root.val);
inOrderTraversal(root.right,arr);
}
return arr;
}
3.前序遍历
3.1栈方法
-
将父节点压入栈中
-
执行出栈操作,放入结果数组
-
每次将出栈的节点的右孩子先压入栈中,其次压入左孩子节点
-
重复执行第2,3步…
-
图画演示
-
一开始先将父节点1压入栈中,将1出栈,放入结果数组,将其右节点6压入栈中,将其左节点2压入栈中;将2出栈,2没有右节点,所以将其左节点3压入栈中;
-
然后将3出栈,放入结果数组,将其右节点5,左节点4压入栈中;将4出栈放入结果数组,无左右节点;将5出栈放入结果数组,无左右节点;将6出栈放入结果数组,将其右节点8,右节点7放入栈中;将7出栈放入结果数组,无左右节点,将8出栈放入结果数组,无左右节点
-
-
代码为:
let preOrderTraversal = function(root){
if(!root) return [];
const res = []; //结果数组
const stack = [root]; //栈中先放入根节点
while(stack.length!=0){
let node = stack.pop(); //出栈
res.push(node.val); //放入结果数组
if(node.right) stack.push(node.right); //先将右节点压入栈
if(node.left) stack.push(node.left); //再将左节点压入栈
}
return res
}
3.2递归方法
- 根节点——左子树——右子树的方式遍历这棵树,而在访问左子树或者右子树的时候,我们按照同样的方式遍历,直到遍历完整棵树
let preOrderTraversal = function(root,arr=[]) {
if(root){
arr.push(root.val);
preOrderTraversal(root.left,arr);
preOrderTraversal(root.right,arr);
}
return arr
};
4、后序遍历
4.1栈方法
-
将父节点压入栈中
-
执行出栈操作,放入结果数组(与前序的区别就是这里是在头部插入!!)
-
每次将出栈的节点的左孩子先压入栈中,其次压入右孩子节点
-
重复执行第2,3步…
-
图画演示
-
首先还是根节点1入栈出栈,放入结果数组,将其左节点2,右节点6压入栈中;取出栈顶节点6,插入结果数组头部,将6的左节点7,右节点8压入栈中;取出栈顶节点8,插入结果数组头部;取出栈顶节点7,插入结果数组头部
-
取出栈顶节点2,插入结果数组头部,将2的左节点3压入栈中;取出栈顶节点3,插入结果数组头部,将其左节点4,右节点5压入栈中;取出栈顶节点5,插入结果数组头部;取出栈顶节点4,插入结果数组头部
-
-
代码为:
let postOrderTraversal = function(root) {
if(!root) return [];
const res = [];
const stack = [root];
while(stack.length!=0){
let node = stack.pop();
res.unshift(node.val); //记住这里是头部插入
if(node.left) stack.push(node.left); //先压入左节点
if(node.right) stack.push(node.right); //再压入右节点
}
return res
};
4.2递归方法
let postOrderTraversal = function(root,arr=[]) {
if(root){
postOrderTraversal(root.left,arr);
postOrderTraversal(root.right,arr);
arr.push(root.val);
}
return arr
}