IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 手撕二叉树遍历(前序 + 中序 + 后序 递归 + 非递归 代码实现 + 例题) -> 正文阅读

[数据结构与算法]手撕二叉树遍历(前序 + 中序 + 后序 递归 + 非递归 代码实现 + 例题)


前引


刚刚才写完了手撕最小堆的博客 就想了 是不是也得写一下二叉树遍历呢 哈哈 因为前段时间才写过 而且那个时候理解花了很多时间 所以现在手撕了三个遍历 大概花了5分钟左右 力扣三道题 前中后序遍历也就一次性全部AC啦 把这篇写了 我就去吃晚饭了惹 那进入下面的题目吧


手撕数据结构 总结博客链接


手撕数据结构(最小堆 + 二叉树前中后非递归遍历 + 快排归并排序 + KMP匹配算法 + AVL + 红黑树)


二叉树遍历介绍


二叉树 真的是经典的不能再经典 对于其三个 非递归的遍历 必须熟练熟练的掌握! 面试肯定是非常常考的 肯定不会考你递归的 那不然也太弱智了哈哈


二叉树遍历 首先需要先搞清楚 什么是前序 什么是中序 什么是后序 我们后面都会用到这张图 分别再将 这里就先不说了
遍历当然不仅仅是需要用在二叉搜索树 任意的树都可以遍历 但是对于二叉搜索树的前中后序遍历的话 就有一些其他的性质了 这个后面再说
在这里插入图片描述


1、二叉树前序遍历


在讲代码实现前 我们把上面的前序的结果给出来
在这里插入图片描述

我们可以理解 我们最偏向于先输出值 然后其次是向左节点移动 最后向右节点移动 每当移动后 我们又会按照这个顺序进行动作


1、二叉树前序遍历代码(递归)


作为最经典的递归实现 递归代码如下

class Solution {
public:
    void preorder_visit(TreeNode* root,vector<int>& ret)
    {
        if(!root)   return;
        ret.emplace_back(root->val);
        preorder_visit(root->left,ret);
        preorder_visit(root->right,ret);
    }

    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> ret;
        preorder_visit(root,ret);
        return ret;
    }
};

2、二叉树前序遍历代码(非递归)


感觉我讲怎么非递归 也不好讲
我是以一种抽象的具象化来写的代码
我认为就是 前序的话 我们每当访问到一个节点时 即刻放入数组中
而遍历到最左边的时候 看是否有右边的结点 如果有 再进入循环 没有的话 也无所谓 当前指针等于nullptr 进入下一轮循环即可


大家还是结合代码理解一下吧

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        TreeNode* ptr = root; 
        stack<TreeNode*> stack;
        vector<int> ret;

        while(ptr || stack.size())
        {
            while(ptr)
            {
                stack.emplace(ptr);        //放入指针
                ret.emplace_back(ptr->val);//即刻放入
                ptr = ptr->left;		 
            }
            
            ptr = stack.top()->right; //访问顶部的右边指针
            stack.pop();			  //已经用过了 则直接pop
        }
        return ret;
    }
};

2、二叉树中序遍历


一样的为了大家方便理解 还是花点时间我自己再做一下中序遍历的结果
在这里插入图片描述

中序遍历的话 我们还是直接看下面的代码吧 大家跟着这个图一起理解


1、二叉树中序遍历代码(递归)


直接给代码了

class Solution {
public:
    void inorder_visit(TreeNode* root,vector<int>& ret)
    {
        if(!root)   return;
        inorder_visit(root->left,ret);
        ret.emplace_back(root->val);
        inorder_visit(root->right,ret);
    }

    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ret;

        inorder_visit(root,ret);
        return ret;
    }
};

2、二叉树中序遍历代码(非递归)


这部分我还是花点时间来写吧
我的理解是 我们还是跟着递归代码来写
首先 不再是遇到节点就push数字了 而是从stack顺着递归的顺序来push 如果是从stack里面出来的再push 然后ptr还是一样的 从stack.top()->right没变 变得只是 push数字的顺序


代码实现如下

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        TreeNode* ptr = root; 
        stack<TreeNode*> stack;
        vector<int> ret;

        while(ptr || stack.size())
        {
            while(ptr)
            {
                stack.emplace(ptr); //储存指针
                ptr = ptr->left;  
            }
            
            ptr = stack.top();   //倒出来指针
            stack.pop();		 //用过了
            ret.emplace_back(ptr->val); // 把值再放进去 按照递归顺序
            ptr = ptr->right;			// 看看右边指针
        }
        return ret;
    }
};


3、二叉树后序遍历


老样子 放一下后序遍历结果图
在这里插入图片描述


1、二叉树后序遍历代码(递归)


直接放代码了

class Solution {
public:
    void postorder_visit(TreeNode* root,vector<int>& ret)
    {
        if(!root)   return;
        postorder_visit(root->left,ret);
        postorder_visit(root->right,ret);
        ret.emplace_back(root->val);
    }

    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> ret;
        postorder_visit(root,ret);

        return ret;
    }
};

2、二叉树后序遍历代码(非递归)


后序相对 前序与中序就不一样了一点 也要难了一点 但是只是有那么一点不同 因为我们需要直到是否当前节点已经被用尽了
对 我是这样理解的 用尽了 必须要求右边节点在当前节点前被push进入数组 如果前一个右边指针不是pre指针 那么说明右边要不就是nullptr 如果是空指针 则我们可以直接推入数组了 因为说明当前这个指针已经是最后一个了
我理解的代码 也就是这样写的 写出来就是如下 不是很好理解 希望大家多花点时间理解以下代码


那最后一个就直接放代码了

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        TreeNode* ptr = root,*pre = nullptr; \\pre指针 记录前一个被推入数组 
        stack<TreeNode*> stack;
        vector<int> ret;

        while(ptr || stack.size())
        {
            while(ptr)
            {
                stack.emplace(ptr);
                ptr = ptr->left;
            }
            
            ptr = stack.top();
            if(!ptr->right || ptr->right == pre) //如果右边指针为空 或者右边已经被推入了 则可以直接推入
            {
                ret.emplace_back(ptr->val);
                pre = ptr;
                stack.pop();
                ptr = nullptr;
            }
            else    ptr = ptr->right;
        }
        return ret;
    }
};

二叉树遍历例题


下面就放三个 经典前中后序的力扣题目 大家也可以去通过这三道题目去验证自己的代码是否正确 终于写完了 现在正在EDG打DK 我得赶快写了 回寝室看比赛了 太激动了 先写到这里

144. 二叉树的前序遍历
94. 二叉树的中序遍历
145. 二叉树的后序遍历

Love 6 刷题记录博客 144. 二叉树的前序遍历 (迭代 递归 Morris)
Love 6 刷题记录博客 94. 二叉树的中序遍历
Love 6 刷题记录博客 145. 二叉树的后序遍历(神级Morris)

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-11-14 21:58:23  更:2021-11-14 21:58:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 10:29:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码