【算法与数据结构】144、145、94LeetCode二叉树的前中后遍历(递归法、迭代法)

news2024/10/7 8:29:43

文章目录

  • 一、题目
  • 二、递归算法
  • 三、迭代算法
  • 四、完整代码

所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。

一、题目

在这里插入图片描述
在这里插入图片描述

二、递归算法

  思路分析:这道题比较简单,不多说了,大家直接看代码就行。注意前中后遍历是指中间节点的遍历顺序。同时中序和后序的代码也很类似,这里给出三道题代码。
  前序遍历程序如下

class Solution {
public:
    // 前序遍历
    void traversal_preOrder(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        vec.push_back(cur->val);                // 中
        traversal_preOrder(cur->left, vec);     // 左
        traversal_preOrder(cur->right, vec);    // 右
    }

    vector<int> preorderTraversal(TreeNode* root) {
        if (root == NULL) return {};
        if (root->left == NULL && root->right == NULL) return { root->val };
        vector<int> result;
        traversal_preOrder(root, result);
        return result;
    }
};

复杂度分析可以参考这篇文章二叉树多种遍历的时间复杂度和空间复杂度。

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

  中序遍历程序如下

// 中序遍历
class Solution2 {
public:  
    void traversal_midOrder(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        traversal_midOrder(cur->left, vec);     // 左
        vec.push_back(cur->val);                // 中
        traversal_midOrder(cur->right, vec);    // 右
    }

    vector<int> inorderTraversal(TreeNode* root) {
        if (root == NULL) return {};
        if (root->left == NULL && root->right == NULL) return { root->val };
        vector<int> result;
        traversal_midOrder(root, result);
        return result;
    }
};

  后序遍历程序如下

// 后序遍历
class Solution3 {
public:
    void traversal_postOrder(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        traversal_postOrder(cur->left, vec);     // 左
        traversal_postOrder(cur->right, vec);    // 右
        vec.push_back(cur->val);                 // 中
    }

    vector<int> postorderTraversal(TreeNode* root) {
        if (root == NULL) return {};
        if (root->left == NULL && root->right == NULL) return { root->val };
        vector<int> result;
        traversal_postOrder(root, result);
        return result;
    }
};

三、迭代算法

  遍历树节点的时候要注意是右节点先入栈,左节点后入栈,这样在出栈的时候就是左节点先出栈。
  前序遍历程序如下

// 前序遍历迭代法 中左右
class Solution4 {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        if (root == NULL) return {};
        if (root->left == NULL && root->right == NULL) return { root->val };
        stack<TreeNode*> st;
        vector<int> result;
        st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            st.pop();
            result.push_back(node->val);
            if (node->right) st.push(node->right);    // 空节点不入栈
            if (node->left) st.push(node->left);      // 空节点不入栈,左节点后入栈,先出栈           
        }
        return result;
    }
};

  中序遍历是左中右,需要一层层找到最左边的节点,在遍历的过程当中依次将遍历元素压入栈,最左边元素就在栈顶,可以首先输出,就实现左中右顺序的遍历。
  中序遍历程序如下

// 中序遍历迭代法 左中右
class Solution5 {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        if (root == NULL) return {};
        if (root->left == NULL && root->right == NULL) return { root->val };
        stack<TreeNode*> st;
        vector<int> result;
        TreeNode* node = root;
        while (node != NULL || !st.empty()) {   // 栈非空或节点非空, 每次循环更新node
            if (node != NULL) {
                st.push(node);
                node = node->left;
            }
            else {
                node = st.top();
                st.pop();
                result.push_back(node->val);
                node = node->right;    // 右节点
            }    
        }
        return result;
    }
};

  后序遍历只需要将前序遍历翻转一下就能实现。
  后序遍历程序如下

// 后序遍历迭代法 左右中
class Solution6 {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> result;
        if (root == NULL) return result;
        st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            st.pop();
            result.push_back(node->val);
            if (node->left) st.push(node->left);    // 相对于前序遍历,这更改一下入栈顺序 (空节点不入栈)
            if (node->right) st.push(node->right);  // 空节点不入栈
        }
        reverse(result.begin(), result.end()); // 将结果反转之后就是左右中的顺序了
        return result;
    }
};

四、完整代码

# include <iostream>
# include <vector>
# include <stack>
using namespace std;
// 树节点定义
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
// 前序遍历递归法
class Solution {
public:   
    void traversal_preOrder(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        vec.push_back(cur->val);                // 中
        traversal_preOrder(cur->left, vec);     // 左
        traversal_preOrder(cur->right, vec);    // 右
    }

    vector<int> preorderTraversal(TreeNode* root) {
        if (root == NULL) return {};
        if (root->left == NULL && root->right == NULL) return { root->val };
        vector<int> result;
        traversal_preOrder(root, result);
        return result;
    }
};
// 中序遍历递归法
class Solution2 {
public:  
    void traversal_midOrder(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        traversal_midOrder(cur->left, vec);     // 左
        vec.push_back(cur->val);                // 中
        traversal_midOrder(cur->right, vec);    // 右
    }

    vector<int> inorderTraversal(TreeNode* root) {
        if (root == NULL) return {};
        if (root->left == NULL && root->right == NULL) return { root->val };
        vector<int> result;
        traversal_midOrder(root, result);
        return result;
    }
};
// 后序遍历递归法
class Solution3 {
public:
    void traversal_postOrder(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        traversal_postOrder(cur->left, vec);     // 左
        traversal_postOrder(cur->right, vec);    // 右
        vec.push_back(cur->val);                // 中
    }

    vector<int> postorderTraversal(TreeNode* root) {
        if (root == NULL) return {};
        if (root->left == NULL && root->right == NULL) return { root->val };
        vector<int> result;
        traversal_postOrder(root, result);
        return result;
    }
};
// 前序遍历迭代法 中左右
class Solution4 {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        if (root == NULL) return {};
        if (root->left == NULL && root->right == NULL) return { root->val };
        stack<TreeNode*> st;
        vector<int> result;
        st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            st.pop();
            result.push_back(node->val);
            if (node->right) st.push(node->right);    // 空节点不入栈,右节点
            if (node->left) st.push(node->left);    // 空节点不入栈,左节点后入栈,先出栈           
        }
        return result;
    }
};
// 中序遍历迭代法 左中右
class Solution5 {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        if (root == NULL) return {};
        if (root->left == NULL && root->right == NULL) return { root->val };
        stack<TreeNode*> st;
        vector<int> result;
        TreeNode* node = root;
        while (node != NULL || !st.empty()) {   // 栈非空或节点非空, 每次循环更新node
            if (node != NULL) {
                st.push(node);
                node = node->left;
            }
            else {
                node = st.top();
                st.pop();
                result.push_back(node->val);
                node = node->right;    // 右节点
            }    
        }
        return result;
    }
};
// 后序遍历迭代法 左右中
class Solution6 {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> result;
        if (root == NULL) return result;
        st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            st.pop();
            result.push_back(node->val);
            if (node->left) st.push(node->left);    // 相对于前序遍历,这更改一下入栈顺序 (空节点不入栈)
            if (node->right) st.push(node->right);  // 空节点不入栈
        }
        reverse(result.begin(), result.end()); // 将结果反转之后就是左右中的顺序了
        return result;
    }
};

void my_print(vector <int>& v, string msg)
{
    cout << msg << endl;
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
        cout << *it << "  ";
    }
    cout << endl;
}

int main() {
    // 构造树
    TreeNode* node3 = new TreeNode(3);
    TreeNode* node2 = new TreeNode(2, node3, NULL);
    TreeNode* root = new TreeNode(1, NULL, node2);
    Solution6 s1;
    vector<int> result = s1.postorderTraversal(root);
    my_print(result, "中序遍历结果:");
	system("pause");
	return 0;
}

end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/767729.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

家具商城小程序:连接优质家居产品的桥梁

随着人们对家居生活品质的追求&#xff0c;家具商城小程序成为提供便捷购物和个性化服务的不可或缺的工具&#xff0c;通过家具商城小程序&#xff0c;用户可以浏览并购买各类家具产品&#xff0c;如沙发、床、桌子等。同时&#xff0c;家具商城小程序还提供个性化的推荐、客户…

【实战篇】docker-compose部署go项目

一、场景&#xff1a; 二、需求 三、实操 Stage 1&#xff1a;GoLand 中 build 生成二进制文件 Stage 2&#xff1a;编写 Dockerfile Stage 3&#xff1a;编写 docker-compose.yaml Stage 4&#xff1a;文件上传到 ubuntu 服务器上 Stage 5&#xff1a;运行 docker-comp…

uni-app做h5IOS底部tabbar高度在不同的tabbar页面会忽高忽低

原因不祥&#xff0c;解决办法的话在App.vue中 <style langscss> //每个页面公共css page { height:100vh; } </style>

word 2019无法打开邮箱下载的docx文档

我通过如下设置&#xff0c;打开了文档&#xff1a; 开始——选型——信任中心——信任中心设置&#xff0c;如下图 2.把宏设置改一下&#xff0c;如下图 3.把受保护的视图设置一下&#xff0c;如下图 3.文件阻止设置为默认&#xff0c;我没有改&#xff0c;如下图 结束了…

Android平台GB28181设备接入端语音广播技术探究和填坑指南

技术背景 GB/T28181-2016官方规范和交互流程&#xff0c;我们不再赘述。 SIP服务器发起广播流程示意图如下&#xff1a; 需要注意的是&#xff1a;语音广播通知、语音广播应答命令 消息头 Content-type字段为 Content-type:Application/MANSCDPxml。 语音广播通知、语音广播…

vue写车牌号 自定义键盘

vue写车牌号自定义键盘 <template><div><div class"content-wrapper"><div class"content-top-wrapper"><van-radio-group v-model"radioCarType"><van-radio name"1">蓝牌<imgslot"icon…

COC 深圳城市开发者社区【职言职语】第1季活动来袭。。。

文章目录 活动介绍活动议程活动奖品参与方式活动时间活动费用活动地点 活动介绍 &#x1f389;&#x1f465; 欢迎加入职言职语活动&#xff01;与我们一起探索职场的智慧和灵感&#xff01; &#x1f454;&#x1f4bc; 在这个快节奏的职业世界中&#xff0c;职场话题 是我们…

【实战总结】SpringMVC架构升级SpringCloudAlibaba

升级目标 SpringMVCDubboZookeeper分布式架构改为Spring Cloud Alibaba微服务 技术框架:Spring Boot 2.7.2、Spring Cloud 2021.0.3 & Alibaba 2021.0.1.0 容器:Tomcat 9.0.65 JDK:1.8 配置中心:Nacos 2.0.4 消息队列:RocetMQ 4.9.3 配置中心:Apollo 11.0 缓存: Redis 4.0…

大华智慧园区综合管理平台存在任意文件上传漏洞

大华智慧园区综合管理平台存在任意文件上传漏洞 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作…

Ceph

Ceph简介 Ceph使用C语言开发&#xff0c;是一个开放、自我修复和自我管理的开源分布式存储系统。具有高扩展性、高性能、高可靠性的优点。Ceph目前已得到众多云计算厂商的支持并被广泛应用。RedHat及OpenStack&#xff0c;Kubernetes都可与Ceph整合以支持虚拟机镜像的后端存储…

CMake:设置语言标准(一)

CMake:设置语言标准&#xff08;一&#xff09; 导言C标准历史C11版本特性介绍类型推导之auto和decltypeC返回值类型后置对模板实例化中连续尖括号>>的改进使用using定义别名&#xff08;替代typedef&#xff09;支持函数模板的默认参数在函数模板和类模板中使用可变参数…

接下来讲一讲Vue的数据代理

首先讲一下原生js的数据代理 原生的 Object.defineProperty() let aa wewewlet person {name: "王李斌",age: 12} Object.defineProperty(person, "address", {// value: 14&#xff0c; 给字段设置值//enumerable:true, 设置动态设置的字段为可以遍历/…

Docker 镜像解密:分层存储与构建原理多角度解析

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

超声波水表的优势

超声波水表是一种新型的水表&#xff0c;它采用超声波测流技术&#xff0c;能够实现对水流的非接触式测量&#xff0c;具有许多优势。下面将从多个方面来介绍超声波水表的优势。 一、高精度 由于超声波测流技术采用的是非接触式测量&#xff0c;因此不会受到水流的摩擦、涡流等…

【C++】C++11 (3): lambda表达式和包装器

一、lambda表达式 C98中的一个例子 在C98中&#xff0c;如果想要对一个数据集合中的元素进行排序&#xff0c;可以使用std::sort方法。 #include <algorithm> #include <functional> int main() {int a[] { 4,1,8,5,3,7,0,9,2,6 };// 默认按照小于比较&#xff…

S32 Design Studio for ARM(S32DS)下载和安装

1. S32 Design Studio for ARM 介绍 S32 Design Studio for ARM&#xff08;下面简称S32DS&#xff09;&#xff0c;是 NXP 官方在 2014 年官方推出的&#xff0c;专门面向 S32K、KEA、MAC57D54H等系列微控制器的集成开发环境。 S32DS是由Eclipse和一些插件集成而来的开发平台…

自来水收费系统适合应用于哪些场景?

自来水收费系统是一种用于自来水公司或供水管理部门的软件系统&#xff0c;旨在帮助自动化自来水的收费和管理过程。该系统可以帮助自来水公司更好地管理水资源&#xff0c;提高供水质量和效率&#xff0c;同时也可以为用户提供更加便捷和安全的用水服务。下面将从多个方面来介…

centos7通过epel源安装redis

目录 一、下载epel源 二、下载并且启动 一、下载epel源 wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo 二、下载并且启动 yum install redis systemctl enable --now redis

c代码和c++代码互相调用

note 不管是c代码调用c代码&#xff0c;还是c代码调用c代码&#xff0c;本质上都是g兼容gcc的功能 c代码调用c代码 lib.h #ifndef _LIB_H_void libfun(void);#endif lib.c #include <stdio.h> #include "lib.h"void libfun(void) {printf("this is i…

Intel nuc 清除cmos密码

设备为intel nuc7&#xff0c;其他版本可以参考&#xff0c;步骤如下 1、找到主板上的bios_sec的三针跳线 2、将跳线开关取下 3、按住电源键3秒&#xff0c;电源指示灯变为橙色后松手 4、耐心等待显示器显示bios recovery倒计时画面 5、按esc取消bios recovery 6、显示器显…