首页 > 其他分享 >【LeetCode二叉树#01】二叉树的遍历(递归/迭代)

【LeetCode二叉树#01】二叉树的遍历(递归/迭代)

时间:2023-02-18 18:44:12浏览次数:56  
标签:vector 遍历 cur res LeetCode 01 二叉树 节点 vec

二叉树递归遍历

写递归算法时候需要遵循的三个点:

  1. 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
  2. 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
  3. 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。

前序遍历

前序遍历为例

LeetCode上的代码模板如下:

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {

    }
};

因为要使用递归,所以肯定得有一个递归函数,那么现在按照上面的三个规则来写

1、确定递归函数的参数和返回值:因为要打印出前序遍历节点的数值,所以参数里需要传入vector来放节点的数值,除了这一点就不需要再处 理什么数据了也不需要有返回值,所以递归函数返回类型就是void,代码如下:

void traversal(TreeNode* cur, vector<int>& vec){
    
}

2.确定终止条件:在递归的过程中,如何算是递归结束了呢,当然是当前遍历的节点是空了,那么本层递归就要结束了,所以如果当前遍历的这个节点是空,就直接return,代码如下:

void traversal(TreeNode* cur, vector<int>& vec){
    if(cur == NULL) return;
}

3.确定单层递归的逻辑:前序遍历是中左右的循序,所以在单层递归的逻辑,是要先取中节点的数值,代码如下:

void traversal(TreeNode* cur, vector<int>& vec){
    if(cur == NULL) return;
    vec.push_back(cur->val);//取出当前节点的值(中)
    traversal(cur->left, vec);//到左子树的节点中取值(左)
    traversal(cur->right, vec);//到右子树的节点中取值(右)
}

因此,前序遍历的完整代码如下:

class Solution {
public:
    //编写递归函数
	void traversal(TreeNode* cur, vector<int>& vec){
		if(cur == NULL)return;
        vec.push_back(cur->val);//取出当前节点的值
        traversal(cur->left, vec);//到左子树的节点中取值
        traversal(cur->right, vec);//到右子树的节点中取值	
	}
    vector<int> preorderTraversal(TreeNode* root) {
		//定义结果数组
        vector<int> res;
        traversal(root, res);
        return res;
    }
};

中序遍历

同理,中序和后序遍历中只需修改递归函数traversal中的单层递归逻辑即可

class Solution {
public:
	void traversal(TreeNode* cur, vector<int>& vec){
		if(cur == NULL)return;
        traversal(cur->left, vec);//到左子树的节点中取值(左)
        vec.push_back(cur->val);//取出当前节点的值(中)
        traversal(cur->right,vec);//到右子树的节点中取值(右)
		
	}
    vector<int> inorderTraversal(TreeNode* root) {
		//定义结果数组
        vector<int> res;
        traversal(root, res);
        return res;
    }
};

后序遍历

class Solution {
public:
    //编写递归函数
    void traversal(TreeNode* cur, vector<int>& vec){
        if(cur == NULL) return;
        traversal(cur->left, vec);
        traversal(cur->right, vec);
        vec.push_back(cur->val);

    }
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        traversal(root, res);
        return res;
    }
};

二叉树非递归遍历

面试时有可能会考察一些简单的递归逻辑的迭代法实现

例如,用迭代法来实现前中后序遍历

前序遍历(迭代法)

图示模拟

通过迭代法进行前序遍历主要是利用栈的方式实现的

如图所示,将当前遍历到的节点存入栈中,保存其值到结果数组后将其弹出,然后根据该节点的左右指针,把该节点的左右子节点再放入栈中

注意:放入栈的顺序要与遍历顺序相反

例如:前序遍历的顺序是 中左右 ,当 5 入栈时实际上是在进行对于 中 的遍历,而 5 的左右子节点入栈时要以 “右左” 的顺序进入,这样在出栈时才能保证顺序为 “左右” ,才能达成 "中左右" 的遍历顺序

代码
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
		//定义一个栈,注意保存的是节点数据类型
        stack<TreeNode*> st;
        //定义一个结果数组
        vector<int> res;
        //检测传入节点是否为空
        if(root == NULL) return res;
        //将根节点压栈
        st.push(root);                           //中
        //当栈中不为空时持续遍历
        while(!(st.empty())){
            //保存当前栈顶节点
            TreeNode* node = st.top();
            //弹出当前节点
            st.pop();
            //保存结果
            res.push_back(node->val);
            //判断当前节点有无左右子节点,有就按顺序压栈(明确你的出栈顺序,入栈时要相反)
            if(node->right)st.push(node->right); //右
            if(node->left)st.push(node->left);   //左 
        }
        return res;//最终遍历结果的顺序:中左右(前序)       
    }
};

后序遍历(迭代法)

因为中序遍历的迭代法不是简单的在前序的基础上修改顺序就可以实现的,所以先说后续遍历

在前序的基础上实现后序的方式很巧妙

后序遍历顺序:左右中

前序遍历顺序:中左右

因为要使用栈来实现迭代遍历,所以在实际代码中前序遍历的入栈顺序是:中右左

此时我们对其进行一个翻转处理,是不是就变成了左右中,即后序遍历的顺序

代码
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
		//定义一个栈,注意保存的是节点数据类型
        stack<TreeNode*> st;
        //定义一个结果数组
        vector<int> res;
        //检测传入节点是否为空
        if(root == NULL) return res;
        //将根节点压栈
        st.push(root);                           //中
        //当栈中不为空时持续遍历
        while(!(st.empty())){
            //保存当前栈顶节点
            TreeNode* node = st.top();
            //弹出当前节点
            st.pop();
            //保存结果
            res.push_back(node->val);
            //判断当前节点有无左右子节点,有就按顺序压栈(明确你的出栈顺序,入栈时要相反)
            if(node->left)st.push(node->left);   //左 
            if(node->right)st.push(node->right); //右
            //数组保存顺序:中右左
        }
        //翻转数组
        reverse(res.begin(), res.end());
        return res;//最终遍历结果的顺序:左右中(后序)       
    }
};

中序遍历(迭代法)

通过前序和后序遍历的实现可以发现,这个过程其实可以分为遍历节点处理节点两部分

并且在前序和后序遍历中,要遍历的节点与要处理的节点为同一顺序,因此可以按照上面的模式写出代码

但是,中序遍历的过程中,遍历和处理节点并不能够同时进行(顺序不一致),因此需要新的实现逻辑

中序遍历的动画如下:

二叉树中序遍历(迭代法)

首先,中序遍历的顺序是 左中右

因此从头结点 5 开始,我们定义一个指针一直遍历该二叉树的左指针指向的节点(左子节点)并压栈,直到指针指向空

然后开始从栈顶取节点

此时取的肯定是叶子节点,但是我们仍要判断其是否有左右节点(显然是没有的,要不然上面的指针也不会指向空)

将该节点的值保存到结果数组中,重复上述操作

代码
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
		//定义栈
        stack<TreeNode*> st;
        vector<int> res;
        //将指针指向根节点
        TreeNode* cur = root;
        //遍历
        while(!(st.empty()) || cur ! = NULL){
            //判断是否遍历到最底层
            if(cur ! = NULL){
                st.push(cur);//压栈
                cur = cur->left;//继续向左遍历
            }else{//当遍历到了左边的最底层,开始出栈(处理数据,即放进res)
                cur = st.top();//让指针指向当前弹出的节点
                res.push_back(cur->val);
                //判断每个出栈的节点是否有左右子节点
                cur = cur->right;//如果有,则又会触发if的第一个条件,继续将右子节点压栈
                //不存在的话cur指向空就右来到else这
            }
        }
        return res;      
    }
};

标签:vector,遍历,cur,res,LeetCode,01,二叉树,节点,vec
From: https://www.cnblogs.com/DAYceng/p/17133282.html

相关文章

  • 华为认证题库H12-811(101-200)
    101、​网络管理员在路由器设备上使用了TracertRoute功能后、路由器发出的数据包中,IPv4首部的Protocol宇段取值为?()​A、17​B、2​C、6​D、1​试题答案:[['D']]​试题解析:​......
  • Python 学习01 基础知识
    ......
  • 【算法训练营day48】LeetCode198. 打家劫舍 LeetCode213. 打家劫舍II LeetCode337. 打
    LeetCode198.打家劫舍题目链接:198.打家劫舍独上高楼,望尽天涯路dp[i]表示的是偷窃0-i房屋所能获得的最大金额。classSolution{public:introb(vector<int>&n......
  • 【LeeCode】二叉树理论
    二叉树分类没有数值满⼆叉树如果⼀棵⼆叉树只有度为0的结点和度为2的结点,并且度为0的结点在同⼀层上,则这棵⼆叉树为满⼆叉树​满⼆叉树,也可以说深度为k,有2^k-1个节点的⼆叉......
  • 电学基础知识01
    一.电路的基本组成1,电路:电路是电流的流通路径,它是由一些电气设备和元器件按一定方式连接而成的.复杂的电路呈网状,又称网络.电路和网络这两个术语是通用的.2,电路的......
  • 代码随想录算法训练营Day18 二叉树
    代码随想录算法训练营代码随想录算法训练营Day18二叉树|513.找树左下角的值112.路径总和113.路径总和ii106.从中序与后序遍历序列构造二叉树105.从前序与中序遍历......
  • Leetcode27:移除元素
    题目描述:给你一个数组nums 和一个值val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用O(1)额外空间并......
  • #yyds干货盘点# LeetCode程序员面试金典:数字流的秩
    题目:假设你正在读取一串整数。每隔一段时间,你希望能找出数字x的秩(小于或等于x的值的个数)。请实现数据结构和算法来支持这些操作,也就是说:实现track(intx) 方法,每读......
  • #yyds干货盘点# LeetCode面试题:四数之和
    1.简述:给你一个由n个整数组成的数组 nums,和一个目标值target。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a],nums[b],nums[c],nums[d]] (若两个四元......
  • 用python绘制1960年到2019年全国GDP增长图
    frompyecharts.chartsimportBar,Timelinefrompyecharts.optionsimport*#处理数据f=open("D:/1960-2019全球GDP数据.csv","r",encoding="GB2312")#读取每一行,返回是......