前序遍历

/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var preorderTraversal = function (root) {
  // 迭代法
  var stack = [];
  var ans = [];
  if (root && root.val) {
    stack.push(root);
    // 利用栈临时存取元素
    while (stack.length > 0) {
      // 从栈顶取出当前元素
      var cur = stack.pop();
      if (cur !== null) {
        ans.push(cur.val);
        // 栈先进后出,所以先放右子树
        if (cur.right) stack.push(cur.right);
        if (cur.left) stack.push(cur.left);
      }
    }
  }
  return ans;
};

中序遍历

/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var inorderTraversal = function (root) {
  // 迭代
  var ans = [];
  var stack = [];
  var cur = root;
  // cur条件是为了启动循环,因为初始时栈为空
  while (cur || stack.length) {
    // 所有左子树依次入栈(根->左->根->左……直到没有左子树了,根就可以出栈了)
    while (cur) {
      // 只有这里有入栈操作,就是判断当前子树是否有左子树
      stack.push(cur);
      cur = cur.left;
    }
    // 出栈的是无左子树的节点,因为没有左子树入栈才会走到这里
    cur = stack.pop();
    ans.push(cur.val);
    // 没有左子树,并且根被记录后右子树入栈(整棵树的右子树——整体左根右)
    cur = cur.right;
  }
  return ans;
  // 内层循环在判断左子树的存在
  // 外层循环在判断右子树的存在
  // 根是否出栈取决于节点是否还有左子树,因为顺序为左根右
  // 当节点没有左子树时可以出栈根
  // 当无右子树,但栈未空时,是当前节点处理完毕,向父节点前进
};

后序遍历

/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var postorderTraversal = function (root) {
  // 迭代
  var stack = [],
    ans = [],
    cur = root;
  while (cur || stack.length) {
    // 整体顺序是依次将所有左子树入栈、所有右子树入栈
    // 右子树入栈取决于栈顶元素是否有右子树
    // 因为只有当cur有值时才会发生入栈操作
    // 而当栈顶元素存在右子树时会将右子树赋予cur促使右子树的入栈
    while (cur) {
      stack.push(cur);
      // 无论是否当前节点有左子树,都要将当前节点左子树赋值给游标
      // 这样才能造成cur为null,以跳出左子树遍历循环
      cur = cur.left;
    }
    if (stack[stack.length - 1].right) {
      // 因为外层循环条件是当前游标有值或栈不空
      // 所以可以将栈顶元素右子树赋予当前游标,然后将栈顶元素右子树致为null
      // 这里取了栈顶元素右子树,但没发生出栈行为
      cur = stack[stack.length - 1].right;
      // 因为一旦给 cur 手动赋值栈顶右子树后,下一次再走到这里的if判断时需要绕开(否则会进入这里)
      // 所以这里给if的判断条件致为null
      stack[stack.length - 1].right = null;
      // 这里相当于把树拆分开了,把右子树拆了出来
    } else {
      // 走到这里说明当前节点既没左子树
      // (上面的内层循环把所有左子树入栈,当没有左子树可入栈时才继续往下走)
      // 也没右子树
      // 这里是以"左右根"的根身份进入结果集的
      ans.push(stack.pop().val);
    }
  }
  return ans;
};