二叉树的遍历
关于二叉树的遍历方式,要知道二叉树遍历的基本方式都有哪些。二叉树主要有两种遍历方式:
- 深度优先遍历:先往深走,遇到叶子节点再往回走。
- 前序遍历(递归法,迭代法)
- 中序遍历(递归法,迭代法)
- 后序遍历(递归法,迭代法)
- 广度优先遍历:一层一层的去遍历。
- 层次遍历(迭代法)
这里前中后,其实指的就是中间节点的遍历顺序,只要大家记住 前中后序指的就是中间节点的位置就可以了,并记住口诀:
- 前序遍历:中左右
- 中序遍历:左中右
- 后序遍历:左右中
递归遍历
先序遍历
/**
* @param {TreeNode} root
* @return {number[]}
*/
var preorderTraversal = function(root) {
let arr = [];
preorder(root,arr)
return arr;
};
// 这里将线序遍历二次封装主要是因为题目要求返回的结果是数组输出,所以我们需要定义一个全局数组来储存每次的处理结果
function preorder(root,arr){
if(root==null) return;
arr.push(root.val);
preorder(root.left,arr);
preorder(root.right,arr);
}
后序遍历
/**
* @param {TreeNode} root
* @return {number[]}
*/
var postorderTraversal = function(root) {
let arr = [];
preorder(root,arr)
return arr;
};
function preorder(root,arr){
if(root==null) return;
preorder(root.left,arr);
preorder(root.right,arr);
arr.push(root.val);
}
中序遍历
/**
* @param {TreeNode} root
* @return {number[]}
*/
var inorderTraversal = function(root) {
if(!root) return [];
let stack = [], arr = [];
while(stack.length || root ){
while(root){
stack.push(root);
root = root.left;
}
root = stack.pop();
arr.push(root.val);
root = root.right;
}
return arr;
};
迭代遍历
为什么我们可以用迭代法(非递归)的方法来实现二叉树的前中后序递归·遍历呢?
递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。
先序遍历
前序遍历是中左右,每次先处理的是中间节点,那么先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子。
由于栈的特点是先进后出,所以在入栈时就必须得将先出的元素后入,这样就能达到想要的顺序。
/**
* @param {TreeNode} root
* @return {number[]}
*/
var preorderTraversal = function(root) {
if(!root) return [];
let stack = [],arr = [];
stack.push(root);
while(stack.length){
let node = stack.pop();
if(node !== null) arr.push(node.val);
else continue;
stack.push(node.right);
stack.push(node.left);
}
return arr;
};
后序遍历
再来看后序遍历,先序遍历是中左右,后续遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了,如下图:
/**
* @param {TreeNode} root
* @return {number[]}
*/
var postorderTraversal = function(root) {
if(!root) return [];
let stack = [], arr = [];
let node = root;
stack.push(root);
while(stack.length>0){
node = stack.pop();
if(node !== null) arr.push(node.val);
else continue;
stack.push(node.left);
stack.push(node.right);
}
return arr.reverse();
};
中序遍历
再看看中序遍历,中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中),这就造成了处理顺序和访问顺序是不一致的。
那么在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。
/**
* @param {TreeNode} root
* @return {number[]}
*/
var inorderTraversal = function(root) {
if(!root) return [];
let stack = [], arr = [];
while(stack.length || root ){
while(root){
stack.push(root);
root = root.left;
}
root = stack.pop();
arr.push(root.val);
root = root.right;
}
return arr;
};