二叉树后序遍历算法:递归和非递归(三种思路)

后序遍历 递归

var postorder= function (root, array = []) {
      if (root) {
        postorder(root.left, array);
        postorder(root.right, array);
        array.push(root.val);
      }
      return array;
    };

后序遍历 非递归实现

//方法一:利用一个变量标记
 var postorderTraversal = function (root) {
      const result = [];//保存遍历顺序结果
      const stack = [];
      let last = null; // 标记上一个访问的节点
      let current = root;
      while (current || stack.length > 0) { //思路大概都一样:先找到最下面的左节点
        while (current) {
          stack.push(current);
          current = current.left;
        }
        current = stack[stack.length - 1]; //是指向  而不是弹出
        if (!current.right || current.right == last) { 
        //当 !current.right = true 即current.right=false 则当前节点没有右节点了可 直接读取打印当前节点了       
        //当current=last 时说明  右节点上一次已经访问过了,直接返回打印当前节点。
          current = stack.pop();
          result.push(current.val);
          last = current;
          current = null; 
        } else {
          current = current.right; //如果有左节点 ,则回到一开始的while  继续以遍历当前节点为根节点,找到最下面的左节点。
        }
      }
      return result;
    }
//方法一:利用一个变量标记
var posOrderUnRecur = function(node) { 
 if(!node) {  
  return;
 } 
 var stack = []
 stack.push(node) 
 var tmp = null
 while(stack.length !== 0) {
  tmp = stack[stack.length - 1]  
  if(tmp.left && node !== tmp.left && node !== tmp.right) { //思路一样:都是找到最下面的左节点
   stack.push(tmp.left)
  } else if(tmp.right && node !== tmp.right) {
  //当找到最下面的左节点是,看当前节点是否有右子树;有 则以当前右节点为根节点,继续找最下面左节点
   stack.push(tmp.right)
  } else {   
  //左右子树都遍历过了打印当前节点
   console.log(stack.pop().value)
   node = tmp //标记
  }
 }
}
// 方法二:使用两个栈
var postOrder = function(node) { 
 if(node) {  
  var s1 = []  
  var s2 = []
  s1.push(node)  
  while(s1.length !== 0) {
   node = s1.pop()
   s2.push(node)   
   if(node.left) {
    s1.push(node.left)
   }   
   if(node.right) {
    s1.push(node.right)
   }
  }  
  while(s2.length !== 0) {   
   console.log(s2.pop().value);
  }
 }
}

//方法三:使用一个栈 但是每次入栈是压入两次
//对于每个节点,都压入两遍。
//在循环体中,每次弹出一个节点赋给p,如果p仍等于栈的头结点,说明p的孩子们还没有被遍历,应该把它的孩子们加入栈中,否则,访问p。
//也就是说,第一次弹出,将p的孩子压入栈中,第二次弹出,访问p。

function postorder(root){
	if(root == NULL) return [];
	let arry = []; 
	let stack = [];
	let p= root;
	stack.push(p);
    stack.push(p);
    while(stack.length>0)
    {
        p = stack[stack.length-1];  //指向栈顶元素
        stack.pop(); //弹出
        if(stack.length>0&& p==stack[stack.length-1]) {//如果p等于栈的头结点,说明p的孩子们还没有被操作过
            if(p.right){
            	stack.push(p.right);
            	stack.push(p.right);
            }
            if(p.left){
            	stack.push(p.left),
            	stack.push(p.left);
            }
        }  else
           arry.push(p.val);
    }

    return arry;
}

参考:
JS中的二叉树遍历详解

猜你喜欢

转载自blog.csdn.net/HZ___ZH/article/details/109961280