牛客网刷题之二叉树的中序遍历

 前言:

与牛客的相知相遇:

一次偶然的机会我接触到了牛客网,从那次我就发现牛客网好像是一个全能型的网站,里面有各种语言的练习题、算法题、大厂的面试题、还有求职等各项功能。从那以后我就开始了我的牛客之旅。

链接我就放在这了需要的伙伴们自取👉注册即可免费刷题

目录

二叉树的中序遍历

1、题目描述及示例

 2、递归方法实现

1.二叉树递归的知识点

2.思路

3.具体做法

4.代码实现

3、非递归实现(拓展)

1.栈的知识点

2.思路

3.具体做法

4.图示

5.代码实现


二叉树的中序遍历

1、题目描述及示例

 

 

 2、递归方法实现

1.二叉树递归的知识点

递归是一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。因此递归过程,最重要的就是查看能不能讲原本的问题分解为更小的子问题,这是使用递归的关键。

而二叉树的递归,则是将某个节点的左子树、右子树看成一颗完整的树,那么对于子树的访问或者操作就是对于原树的访问或者操作的子问题,因此可以自我调用函数不断进入子树。

2.思路

什么是二叉树的中序遍历,简单来说就是“左根右”,展开来说就是对于一棵二叉树,我们优先访问它的左子树,等到左子树全部节点都访问完毕,再访问根节点,最后访问右子树。同时访问子树的时候,顺序也与访问整棵树相同。

从上述对于中序遍历的解释中,我们不难发现它存在递归的子问题,根节点的左右子树访问方式与原本的树相同,可以看成一颗树进行中序遍历,因此可以用递归处理:

  • 终止条件: 当子问题到达叶子节点后,后一个不管左右都是空,因此遇到空节点就返回。
  • 返回值: 每次处理完子问题后,就是将子问题访问过的元素返回,依次存入了数组中。
  • 本级任务: 每个子问题优先访问左子树的子问题,等到左子树的结果返回后,再访问自己的根节点,然后进入右子树。

3.具体做法

  • step 1:准备数组用来记录遍历到的节点值,Java可以用List,C++可以直接用vector。
  • step 2:从根节点开始进入递归,遇到空节点就返回,否则优先进入左子树进行递归访问。
  • step 3:左子树访问完毕再回到根节点访问。
  • step 4:最后进入根节点的右子树进行递归。

4.代码实现

①Java代码实现

import java.util.*;
public class Solution {
    public void inorder(List<Integer> list, TreeNode root){
        //遇到空节点则返回
        if(root == null) 
            return;
        //先去左子树
        inorder(list, root.left); 
        //再访问根节点
        list.add(root.val); 
        //最后去右子树
        inorder(list, root.right); 
    }
    
    public int[] inorderTraversal (TreeNode root) {
        //添加遍历结果的数组
        List<Integer> list = new ArrayList(); 
        //递归中序遍历
        inorder(list, root); 
        //返回的结果
        int[] res = new int[list.size()]; 
        for(int i = 0; i < list.size(); i++)
            res[i] = list.get(i);
        return res;
    }
}

②C++代码实现

class Solution {
public:
    void inorder(vector<int> &res, TreeNode* root){
        //遇到空节点则返回
        if(root == NULL) 
            return;
        //先遍历左子树
        inorder(res, root->left); 
        //再遍历根节点
        res.push_back(root->val); 
        //最后遍历右子树
        inorder(res, root->right); 
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        //递归中序遍历
        inorder(res, root);  
        return res;
    }
};

③python代码实现

import sys
class Solution:
    def inorder(self, list: List[int], root: TreeNode):
        # 遇到空节点则返回
        if not root: 
            return
        # 先遍历左子树
        self.inorder(list, root.left) 
        # 再遍历根节点
        list.append(root.val) 
        # 最后遍历右子树
        self.inorder(list, root.right) 
        
    def inorderTraversal(self , root: TreeNode) -> List[int]:
        # 由于python存在最大的递归深度约束,这一步是更改最大深度的限制
        sys.setrecursionlimit(1500) 
        res = [] # 添加遍历结果的list
        # 递归中序遍历
        self.inorder(res, root) 
        return res

复杂度分析:

  • 时间复杂度:O(n),其中n为二叉树的节点数,遍历二叉树所有节点
  • 空间复杂度:O(n),最坏情况下二叉树化为链表,递归栈深度为n

3、非递归实现(拓展)

1.栈的知识点

栈是一种仅支持在表尾进行插入和删除操作的线性表,这一端被称为栈顶,另一端被称为栈底。元素入栈指的是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;元素出栈指的是从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素

2.思路

前序遍历类似,我们利用栈来代替递归。如果一棵二叉树,对于每个根节点都优先访问左子树,那结果是什么?从根节点开始不断往左,第一个被访问的肯定是最左边的节点,

1

2

3

4

5

//每次找到最左节点

while(root != NULL){

    s.push(root);

    root = root->left;

}

然后访问该节点的右子树,最后向上回到父问题。因为每次访问最左的元素不止对一整棵二叉树成立,而是对所有子问题都成立,因此循环的时候自然最开始都是遍历到最左,然后访问,然后再进入右子树,我们可以用栈来实现回归父问题。

3.具体做法

  • step 1:优先判断树是否为空,空树不遍历。
  • step 2:准备辅助栈,当二叉树节点为空了且栈中没有节点了,我们就停止访问。
  • step 3:从根节点开始,每次优先进入每棵的子树的最左边一个节点,我们将其不断加入栈中,用来保存父问题。
  • step 4:到达最左后,可以开始访问,如果它还有右节点,则将右边也加入栈中,之后右子树的访问也是优先到最左。

4.图示

 5.代码实现

①Java代码实现

import java.util.*;
public class Solution {
    public int[] inorderTraversal (TreeNode root) {
        //添加遍历结果的数组
        List<Integer> list = new ArrayList(); 
        Stack<TreeNode> s = new Stack<TreeNode>();
        //空树返回空数组
        if(root == null) 
            return new int[0];
        //当树节点不为空或栈中有节点时
        while(root != null || !s.isEmpty()){ 
            //每次找到最左节点
            while(root != null){ 
                s.push(root);
                root = root.left;
            }
            //访问该节点
            TreeNode node = s.pop(); 
            list.add(node.val); 
            //进入右节点
            root = node.right; 
        }
        //返回的结果
        int[] res = new int[list.size()]; 
        for(int i = 0; i < list.size(); i++)
            res[i] = list.get(i);
        return res;
    }
}

②C++代码实现

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        //辅助栈
        stack<TreeNode*> s; 
        //当树节点不为空或栈中有节点时
        while(root != NULL || !s.empty()){ 
            //每次找到最左节点
            while(root != NULL){ 
                s.push(root);
                root = root->left;
            }
            //访问该节点
            TreeNode* node = s.top(); 
            s.pop();
            res.push_back(node->val); 
            //进入右节点
            root = node->right; 
        }
        return res;
    }
};

③python代码实现

class Solution:
    def inorderTraversal(self , root: TreeNode) -> List[int]:
        # s是辅助栈
        res, s = [], [] 
        # 当树节点不为空或栈中有节点时
        while root or s: 
            # 每次找到最左节点
            while root: 
                s.append(root)
                root = root.left
            # 访问该节点
            node = s[-1] 
            s.pop() 
            res.append(node.val)
            # 进入右节点
            root = node.right 
        return res

复杂度分析:

  • 时间复杂度:O(n),其中nnn为二叉树的节点数,遍历二叉树所有节点
  • 空间复杂度:O(n),辅助栈空间最大为链表所有节点数

若文章有何不足之处,还望各位伙伴们指出不足,最后刷题网站的链接我就放在这里了,需要的伙伴们自取 👉注册即可免费刷题

评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

敲代码的小王!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值