V:表示树的根节点
L:树的左子树
R:树的右子树
先序遍历:V | L | R
访问根节点,访问左子树,访问右子树。右顾左盼
沿着左子树的方向,将右子树推入栈中(后进先出),将左孩子推入栈中
使用递归的方式遍历:
function preorder(root){
//递归基
if(!root) return;
var arr=[];
arr.push(root.val);
preorder(root.left);
preorder(root.right);
}
}
使用迭代进行遍历
function visit(root,s,arr){
//当根节点存在的时候,遍历到叶子节点结束
while(root){
//将根节点放入访问栈中
arr.push(root.val);
//先访问左子树,因此先将右子树压入栈中,在将右子树压入栈中
s.push(root.right);
root=root.left;
}
}
function preorder(root){
var s=[],arr=[];
while(true){
visit(root,s,arr);
//如果当前栈为空,结束
if(s.length<=0) break;
//弹出栈顶元素,当前的左子树遍历完,弹出右子树进行访问
root=s.pop();
}
}
}
中序遍历:L | V | R
自顶向下的过程转交访问控制权,每遍历完一层,未遍历的树与该层没有任何关系。
访问根节点,将访问权限交给左子树,当左子树访问完,访问权交给根节点,最后访问右子树
使用递归实现中序遍历
function inOrder(root){
var arr=[];
//递归基
if(!root) return;
inOrder(root.left);
arr.push(root.val);
inOrder(root.right);
return arr;
}
使用迭代实现中序遍历
function visit(root,s){
while(root){
//先访问左子树,因此将将将根节点压入栈中,访问的时候先访问左子树,在访问右子树
s.push(root);
root=root.left;
}
}
function inOrder(root){
var s=[],arr=[];
while(true){
visit(root,s);
if(s.length<=0) break;
//如果当前弹出的是左子树,那么先将左子树根节点存储起来,访问右子树
//如果当前是根节点,那么访问当前根节点的右子树,相当于上一个根节点左子树遍历完成,开始遍历根节点
root=s.pop();
arr.push(root.val);
root=root.right;
}
}
后序遍历:L | R | V
递归实现遍历
function postOrder(root){
var arr=[];
if(!root) return;
postOrder(root.left);
postOrder(root.right);
arr.push(root.val);
}
先序遍历顺序:root->left->right
将左右子树推入栈中的顺序进行交换,root->right->left
最后放问的数组进行反转,就得到left->right->root
后序遍历:left->right->root
function postOrder(root){
if(!root) return;
var s=[],arr=[];
while(true){
//arr是访问的数组
visit(root,s,arr);
if(s.length<=0) break;
root=s.pop();
}
//反转数组
arr.reverse();
return arr;
}
function visit(root,s,arr){
//当遍历到退化树(叶子节点),结束遍历
while(root){
//将节点的值推入栈中,arr为访问数组
arr.push(root.val);
s.push(root.left);
s.push(root.right);
}
}