二叉树

树的遍历

二叉树是一种更为典型的树状结构。如它名字所描述的那样,二叉树是每个节点最多有两个子树的树结构,通常子树被称作“左子树”和“右子树”。


树的遍历 - 介绍

前序遍历


前序遍历首先访问根节点,然后遍历左子树,最后遍历右子树。

leetcode打卡第一天_java

中序遍历


中序遍历是先遍历左子树,然后访问根节点,然后遍历右子树。

leetcode打卡第一天_java_02

通常来说,对于二叉搜索树,我们可以通过中序遍历得到一个递增的有序序列。

后序遍历


后序遍历是先遍历左子树,然后遍历右子树,最后访问树的根节点。

leetcode打卡第一天_java_03

值得注意的是,当你删除树中的节点时,删除过程将按照后序遍历的顺序进行。 也就是说,当你删除一个节点时,你将首先删除它的左节点和它的右边的节点,然后再删除节点本身。

另外,后序在数学表达中被广泛使用。 编写程序来解析后缀表示法更为容易。 这里是一个例子:


您可以使用中序遍历轻松找出原始表达式。 但是程序处理这个表达式时并不容易,因为你必须检查操作的优先级。

如果你想对这棵树进行后序遍历,使用栈来处理表达式会变得更加容易。 每遇到一个操作符,就可以从栈中弹出栈顶的两个元素,计算并将结果返回到栈中。


递归和迭代


二叉树的前序遍历:

给定一个二叉树,返回它的 前序 遍历。

 示例:

 [1,null,2,3]  
   1
    \
     2
    /
   3 

 [1,2,3]

进阶: 递归算法很简单,你可以通过迭代算法完成吗?


解法一:递归法

递归法很简单,按照根节点、左子树、右子树的顺序。JavaScript中数组的连接使用concat,且此函数并不改变数组本身。


/**
* Definition for a binary tree node.
* function TreeNode(val) {
*     this.val = val;
*     this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var preorderTraversal = function(root) {
   if (!root) return [];
   var result = [];
   result.push(root.val);
   result = result.concat(preorderTraversal(root.left));
   result = result.concat(preorderTraversal(root.right));
   return result;
};


解法二:迭代法


迭代法意在通过循环解决问题。建立一个栈,将根节点加入栈中,当栈不为空时:

1、取出栈顶元素 curr,访问curr

2、若curr右子节点不为空,则将curr右子节点加入栈

3、若curr左子节点不为空,则将curr左子节点加入栈



/** * Definition for a binary tree node. * function TreeNode(val) { *     this.val = val; *     this.left = this.right = null; * } *//** * @param {TreeNode} root * @return {number[]} */var preorderTraversal = function(root) {    if (!root) return [];    var result = [],        stack = [root];    console.log(stack);    while (stack.length !== 0) {      var curr = stack.pop();      if (curr.right) stack.push(curr.right);      if (curr.left) stack.push(curr.left);      result.push(curr.val);    }    return result;};


arrayObject.pop( ) 删除并返回数组的最后一个元素;

                    push( ) 向数组的末尾添加一个或更多元素,并返回新的长度。

难点:二叉树实际入栈后是这样的:

[ TreeNode {
   val: 1,
   right: TreeNode { val: 2, right: null, left: [TreeNode] },
   left: null } ]

所以,栈顶元素实际是根节点。


中序遍历二叉树:

给定一个二叉树,返回它的中序 遍历。

示例:

 [1,null,2,3]
   1
    \
     2
    /
   3

 [1,3,2]

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

解法一:递归法



/** * Definition for a binary tree node. * function TreeNode(val) { *     this.val = val; *     this.left = this.right = null; * } *//** * @param {TreeNode} root * @return {number[]} */var inorderTraversal = function(root) {    if (!root) return [];    var result = [];    result = result.concat(inorderTraversal(root.left));    result.push(root.val);    result = result.concat(inorderTraversal(root.right));    return result;};

解法二:迭代法


/** * Definition for a binary tree node. * function TreeNode(val) { *     this.val = val; *     this.left = this.right = null; * } *//** * @param {TreeNode} root * @return {number[]} */var inorderTraversal = function(root) {    if (!root) return [];    var  res=[];    //栈      var s=[];    var p = root;     while (p || s.length>0) {        //直至左节点为空,即没有左节点为止        while (p) {            s.push(p);            p = p.left;            console.log(s);        }        //出栈,存放根节点        p = s.pop();        res.push(p.val);        console.log('res',res);        p = p.right;    }    return res;};

代码执行结果:

我的输入:

[1,4,2,3,null,5,7] 二叉树


我的标准输出:
[ TreeNode {
   val: 1,
   right: TreeNode { val: 2, right: [TreeNode], left: [TreeNode] },
   left: TreeNode { val: 4, right: null, left: [TreeNode] } } ]
[ TreeNode {
   val: 1,
   right: TreeNode { val: 2, right: [TreeNode], left: [TreeNode] },
   left: TreeNode { val: 4, right: null, left: [TreeNode] } },
 TreeNode {
   val: 4,
   right: null,
   left: TreeNode { val: 3, right: null, left: null } } ]
[ TreeNode {
   val: 1,
   right: TreeNode { val: 2, right: [TreeNode], left: [TreeNode] },
   left: TreeNode { val: 4, right: null, left: [TreeNode] } },
 TreeNode {
   val: 4,
   right: null,
   left: TreeNode { val: 3, right: null, left: null } },
 TreeNode { val: 3, right: null, left: null } ]
res [ 3 ]
res [ 3, 4 ]
res [ 3, 4, 1 ]
[ TreeNode {
   val: 2,
   right: TreeNode { val: 7, right: null, left: null },
   left: TreeNode { val: 5, right: null, left: null } } ]
[ TreeNode {
   val: 2,
   right: TreeNode { val: 7, right: null, left: null },
   left: TreeNode { val: 5, right: null, left: null } },
 TreeNode { val: 5, right: null, left: null } ]
res [ 3, 4, 1, 5 ]
res [ 3, 4, 1, 5, 2 ]
[ TreeNode { val: 7, right: null, left: null } ]
res [ 3, 4, 1, 5, 2, 7 ]
我的答案:
[3,4,1,5,2,7]




二叉树的后序遍历


解法二:迭代法


/** * Definition for a binary tree node. * function TreeNode(val) { *     this.val = val; *     this.left = this.right = null; * } *//** * @param {TreeNode} root * @return {number[]} */var postorderTraversal = function(root) {    if (!root) return [];    var stack = [root];    var res = [];    while (stack.length > 0) {        var item = stack[stack.length - 1];        //满足这些就可以直接输出它了。它是叶子节点。或它的子节点都ok了。        if ((item.left == null && item.right == null) || (item.left && item.left.isOk && item.right && item.right.isOk) || (item.left && item.left.isOk && item.right == null) || (item.left == null && item.right && item.right.isOk)) {            item.isOk = true;            console.log(item.val);            res.push(item.val);            stack.pop();        } else if (item.left && !item.left.isOk) {            //如果左边的没ok,就把左边的入栈            stack.push(item.left);        } else if (item.right && !item.right.isOk) {            //如果右边的没ok就把右边的入栈。            stack.push(item.right);        }    }    return res;};

本章节更新完毕!!!