首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

代码随想录Day12

编程知识
2024年08月12日 19:46

二叉树遍历

分为前序、中序、后续、层序四种
其中前中后序属于深度优先搜索,层序属于广度优先搜索

前序遍历顺序:

根节点->左子树->右子树

中序遍历顺序:

左子树->根节点->右子树

后序遍历顺序:

左子树->右子树->根节点
不难发现,前中后其实就是根节点在遍历中的位置
至于层序遍历,顾名思义,就是一层一层的从左到右遍历

递归遍历(前中后)

  1. 确定递归函数的参数和返回值:因为要打印出前序遍历节点的数值,所以参数里需要传入vector来放节点的数值,除了这一点就不需要再处理什么数据了也不需要有返回值,所以递归函数返回类型就是void。
  2. 确定终止条件:在递归的过程中,如何算是递归结束了呢,当然是当前遍历的节点是空了,那么本层递归就要结束了,所以如果当前遍历的这个节点是空,就直接return。
  3. 确定单层递归的逻辑:前序遍历是中左右的顺序,所以在单层递归的逻辑,是要先取中节点的数值。

上代码(●'◡'●)

前序:
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> result;
        traversal(root, result);
        return result;
    }
};
中序:
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> result;
        traversal(root, result);
        return result;
    }
};
后序:
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> result;
        traversal(root, result);
        return result;
    }
};

迭代遍历(前中后)

递归的底层实现其实就是栈
所以我们可以用栈来实现二叉树的前中后序遍历
但是由于会比较麻烦,三种遍历没法统一,所以我们来看另一种方法:
使用栈的话,无法同时解决访问节点(遍历节点)和处理节点(将元素放进结果集)不一致的情况。
那我们就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记。
如何标记呢,就是要处理的节点放入栈之后,紧接着放入一个空指针作为标记。 这种方法也可以叫做标记法。
迭代
可以看出我们将访问的节点直接加入到栈中,但如果是处理的节点则后面放入一个空节点, 这样只有空节点弹出的时候,才将下一个节点放进结果集。

上代码(●'◡'●)

前序:
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop();
                if (node->right) st.push(node->right);  // 右
                if (node->left) st.push(node->left);    // 左
                st.push(node);                          // 中
                st.push(NULL);
            } else {
                st.pop();
                node = st.top();
                st.pop();
                result.push_back(node->val);
            }
        }
        return result;
    }
};
中序:
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
                if (node->right) st.push(node->right);  // 添加右节点(空节点不入栈)

                st.push(node);                          // 添加中节点
                st.push(NULL); // 中节点访问过,但是还没有处理,加入空节点做为标记。

                if (node->left) st.push(node->left);    // 添加左节点(空节点不入栈)
            } else { // 只有遇到空节点的时候,才将下一个节点放进结果集
                st.pop();           // 将空节点弹出
                node = st.top();    // 重新取出栈中元素
                st.pop();
                result.push_back(node->val); // 加入到结果集
            }
        }
        return result;
    }
};
后序:
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop();
                st.push(node);                          // 中
                st.push(NULL);

                if (node->right) st.push(node->right);  // 右
                if (node->left) st.push(node->left);    // 左

            } else {
                st.pop();
                node = st.top();
                st.pop();
                result.push_back(node->val);
            }
        }
        return result;
    }
};

统一的代码模式,看着确实舒服 d=====( ̄▽ ̄*)b

层序遍历

层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。这种遍历的方式和之前的都不太一样。
需要借用一个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。
而这种层序遍历方式就是图论中的广度优先遍历,只不过我们应用在二叉树上。
层序遍历

上代码(●'◡'●)

迭代:
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> que;
        if (root != NULL) que.push(root);
        vector<vector<int>> result;
        while (!que.empty()) {
            int size = que.size();
            vector<int> vec;
            // 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                vec.push_back(node->val);
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
            result.push_back(vec);
        }
        return result;
    }
};
递归:
class Solution {
public:
    void order(TreeNode* cur, vector<vector<int>>& result, int depth)
    {
        if (cur == nullptr) return;
        if (result.size() == depth) result.push_back(vector<int>());
        result[depth].push_back(cur->val);
        order(cur->left, result, depth + 1);
        order(cur->right, result, depth + 1);
    }
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> result;
        int depth = 0;
        order(root, result, depth);
        return result;
    }
};

写博不易,请大佬点赞支持一下8~

From:https://www.cnblogs.com/Murder-sans/p/18355719/dmsxl_Day12
本文地址: http://shuzixingkong.net/article/1034
0评论
提交 加载更多评论
其他文章 概率论沉思录:合情推理
最近蔻享学术主办了每周一次的《概率论沉思录》读书会活动,恰好我也正在读该书中译版,通过该活动我了解到了不同学科的老师(数学/物理/统计/计算机)对这本书的不同理解,而我自己对该书的理解也在这个过程中逐渐深入了。于是准备每周都持续更新一下我的读书笔记。本书作者是一位物理学家,不同于基于Kolmogor
记录一次物理专业编程大作业完成过程
有一天毕业多年的大学同学在班级微信群里问有没有人能帮忙写一段代码实现一个功能。我一看这段描述简直就头大了,程序员都比较害怕这种没有格式的文字,甚至连个换行都没有,说实话多看一眼就感觉莫名烦躁。我也就没敢讲话,即使有同学在群里已经开始点名了,也始终一言不发。
记录一次物理专业编程大作业完成过程 记录一次物理专业编程大作业完成过程 记录一次物理专业编程大作业完成过程
记录兼职运维的一天
1.背景 7月底部门的运维大哥离职了,奈何又没有新运维接替,至于为什么没有补位,懂得都懂,按老大的意思是先让开发一人顶一块,8月底争取补上。 打心底我有点排斥这事,但是人到中年又有什么办法呢,上有老下有小,唯有苟。 分派给我的部分是服务器漏洞的修复,小弟虽然懂几个linux命令但是在“漏洞修复”这个
记录兼职运维的一天 记录兼职运维的一天 记录兼职运维的一天
面试官:说说读写锁的实现原理?
在实际项目开发中,并发编程一定会用(提升程序的执行效率),而用到并发编程那么锁机制就一定会用,因为锁是保证并发编程的主要手段。 在 Java 中常用的锁有以下几个: synchronized(内置锁):Java 语言内置的关键字,JVM 层级锁实现,使用起来较为简单直观。 ReentrantLock
面试官:说说读写锁的实现原理? 面试官:说说读写锁的实现原理? 面试官:说说读写锁的实现原理?
盘点国内外有哪些软件测试认证
在软件测试行业,技术实力固然重要,但手握权威认证更能为职业发展增添砝码。无论你是刚入行的新人,还是经验丰富的测试工程师,获取一张含金量高的软件测试认证都能让你的职场之路更加平坦。那么,国内外有哪些值得考取的软件测试认证呢?让我们一起来盘点。 你是否正在为选择哪种测试认证而纠结?是国内的认证更适合你,
盘点国内外有哪些软件测试认证 盘点国内外有哪些软件测试认证 盘点国内外有哪些软件测试认证
TGI 多-LoRA: 部署一次,搞定 30 个模型的推理服务
你是否已厌倦管理多个 AI 模型所带来的复杂性和高成本? 那么, 如果你可以部署一次就搞定 30 个模型推理服务会如何? 在当今的 ML 世界中,哪些希望充分发挥其数据的价值的组织可能最终会进入一个“微调的世界”。在这个世界,各个组织会构建大量模型,其中每个模型都针对特定任务进行了高度特化。但是,如
TGI 多-LoRA: 部署一次,搞定 30 个模型的推理服务 TGI 多-LoRA: 部署一次,搞定 30 个模型的推理服务 TGI 多-LoRA: 部署一次,搞定 30 个模型的推理服务
【架构师视角系列】风控场景下配置中心的设计思考
本文将提供风控场景下配置中心的设计思考。风控场景通常需要频繁修改策略进行攻防对抗,一般策略管理平台与策略执行引擎是两个服务,目的是为了解耦,使得业务需求的变更对策略执行引擎执行的影响最小化。通常策略引擎获取策略配置的方法有以下几种,分别是:共享存储、远程调用或配置中心。
【架构师视角系列】风控场景下配置中心的设计思考 【架构师视角系列】风控场景下配置中心的设计思考 【架构师视角系列】风控场景下配置中心的设计思考
国内首个支持国产化信创的开源云原生平台
国产化信创是指中国本土信息技术和创新产业的发展和推广。随着各种形势的复杂变化,推动国产化和信创已成为信息产业发展的重要方向。在这一背景下,国内的技术企业和开发者们纷纷投入到开源国产化和自主创新的浪潮中,力图摆脱对国外技术和服务的依赖。从硬件到软件,再到云原生。 众所周知,在各个技术领域都有国产化信创
国内首个支持国产化信创的开源云原生平台 国内首个支持国产化信创的开源云原生平台 国内首个支持国产化信创的开源云原生平台