Medium!

题目描述:

给定一个二叉树,返回它的中序 遍历。

示例:

输入: [1,null,2,3]
1
\
2
/
3 输出: [1,3,2]

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

解题思路:

二叉树的中序遍历顺序为左-根-右,可以有递归和非递归来解,其中非递归解法又分为两种,一种是使用栈来解,另一种不需要使用栈。我们先来看递归方法,十分直接,对左子结点调用递归函数,根节点访问值,右子节点再调用递归函数。

C++解法一:

 // Recursion
class Solution {
public:
vector<int> inorderTraversal(TreeNode *root) {
vector<int> res;
inorder(root, res);
return res;
}
void inorder(TreeNode *root, vector<int> &res) {
if (!root) return;
if (root->left) inorder(root->left, res);
res.push_back(root->val);
if (root->right) inorder(root->right, res);
}
};

下面我们再来看非递归使用栈的解法,也是符合本题要求使用的解法之一,需要用栈来做,思路是从根节点开始,先将根节点压入栈,然后再将其所有左子结点压入栈,然后取出栈顶节点,保存节点值,再将当前指针移到其右子节点上,若存在右子节点,则在下次循环时又可将其所有左子结点压入栈中。这样就保证了访问顺序为左-根-右。

C++解法二:

 // Non-recursion
class Solution {
public:
vector<int> inorderTraversal(TreeNode *root) {
vector<int> res;
stack<TreeNode*> s;
TreeNode *p = root;
while (p || !s.empty()) {
while (p) {
s.push(p);
p = p->left;
}
p = s.top();
s.pop();
res.push_back(p->val);
p = p->right;
}
return res;
}
};

下面这种解法跟Binary Tree Preorder Traversal中的解法二几乎一样,就是把结点值加入结果res的步骤从if中移动到了else中,因为中序遍历的顺序是左-根-右。

C++解法三:

 class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> s;
TreeNode *p = root;
while (!s.empty() || p) {
if (p) {
s.push(p);
p = p->left;
} else {
TreeNode *t = s.top(); s.pop();
res.push_back(t->val);
p = t->right;
}
}
return res;
}
};

下面我们来看另一种很巧妙的解法,这种方法不需要使用栈,所以空间复杂度为常量,这种非递归不用栈的遍历方法有个专门的名字,叫Morris Traversal,在介绍这种方法之前,我们先来引入一种新型树,叫 Threaded binary tree,这个还不太好翻译,我第一眼看上去以为是叫线程二叉树,但是感觉好像又跟线程没啥关系,后来看到网上有人翻译为螺纹二叉树,就暂且叫螺纹二叉树吧。我们先来看看维基百科上关于它的英文定义:

A binary tree is threaded by making all right child pointers that would normally be null point to the inorder successor of the node (if it exists), and all left child pointers that would normally be null point to the inorder predecessor of the node.

就是说螺纹二叉树实际上是把所有原本为空的右子节点指向了中序遍历顺序之后的那个节点,把所有原本为空的左子节点都指向了中序遍历之前的那个节点,具体例子可参见https://en.wikipedia.org/wiki/Threaded_binary_tree。

那么这道题跟这个螺纹二叉树又有啥关系呢?由于我们既不能用递归,又不能用栈,那我们如何保证访问顺序是中序遍历的左-根-右呢。原来我们需要构建一个螺纹二叉树,我们需要将所有为空的右子节点指向中序遍历的下一个节点,这样我们中序遍历完左子结点后,就能顺利的回到其根节点继续遍历了。具体算法如下:

1. 初始化指针cur指向root

2. 当cur不为空时

  - 如果cur没有左子结点

      a) 打印出cur的值

    b) 将cur指针指向其右子节点

  - 反之

     将pre指针指向cur的左子树中的最右子节点 

     * 若pre不存在右子节点

          a) 将其右子节点指回cur

        b) cur指向其左子节点

     * 反之

      a) 将pre的右子节点置空

      b) 打印cur的值

      c) 将cur指针指向其右子节点

C++解法四:

 // Non-recursion and no stack
class Solution {
public:
vector<int> inorderTraversal(TreeNode *root) {
vector<int> res;
if (!root) return res;
TreeNode *cur, *pre;
cur = root;
while (cur) {
if (!cur->left) {
res.push_back(cur->val);
cur = cur->right;
} else {
pre = cur->left;
while (pre->right && pre->right != cur) pre = pre->right;
if (!pre->right) {
pre->right = cur;
cur = cur->left;
} else {
pre->right = NULL;
res.push_back(cur->val);
cur = cur->right;
}
}
}
return res;
}
};

其实Morris遍历不仅仅对中序遍历有用,对先序和后序同样有用,具体可参见http://noalgo.info/832.html和http://www.cnblogs.com/AnnieKim/archive/2013/06/15/morristraversal.html,所以对二叉树的三种常见遍历顺序(先序,中序,后序)就有三种解法(递归,非递归,Morris遍历),总共有九段代码呀,熟练掌握这九种写法才算初步掌握了树的遍历挖~~ 至于二叉树的层序遍历也有递归和非递归解法,至于有没有Morris遍历的解法还有待大神们的解答。

LeetCode(94):二叉树的中序遍历的更多相关文章

  1. LeetCode 94. 二叉树的中序遍历(Binary Tree Inorder Traversal)

    94. 二叉树的中序遍历 94. Binary Tree Inorder Traversal 题目描述 给定一个二叉树,返回它的 中序 遍历. LeetCode94. Binary Tree Inor ...

  2. Java实现 LeetCode 94 二叉树的中序遍历

    94. 二叉树的中序遍历 给定一个二叉树,返回它的中序 遍历. 示例: 输入: [1,null,2,3] 1 2 / 3 输出: [1,3,2] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? / ...

  3. Leetcode 94. 二叉树的中序遍历

    1.问题描述 给定一个二叉树,返回它的中序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,3,2] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 2.解法一 ...

  4. LeetCode 94. 二叉树的中序遍历(Binary Tree Inorder Traversal)

    题目描述 给定一个二叉树,返回它的中序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,3,2] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 解题思路 由于 ...

  5. leetcode 94二叉树的中序遍历

    递归算法C++代码: /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; ...

  6. 【leetcode 94. 二叉树的中序遍历】解题报告

    前往二叉树的:前序,中序,后序 遍历算法 方法一:递归 vector<int> res; vector<int> inorderTraversal(TreeNode* root ...

  7. LeetCode 94 ——二叉树的中序遍历

    1. 题目 2. 解答 2.1. 递归法 定义一个存放树中数据的向量 data,从根节点开始,如果节点不为空,那么 递归得到其左子树的数据向量 temp,将 temp 合并到 data 中去 将当前节 ...

  8. 【LeetCode】94. 二叉树的中序遍历

    94. 二叉树的中序遍历 知识点:二叉树:递归:Morris遍历 题目描述 给定一个二叉树的根节点 root ,返回它的 中序 遍历. 示例 输入:root = [1,null,2,3] 输出:[1, ...

  9. Leetcode题目94.二叉树的中序遍历(中等)

    题目描述: 给定一个二叉树,返回它的中序遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,3,2] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 思路解析: 1 ...

  10. leetcode刷题-94二叉树的中序遍历

    题目 给定一个二叉树,返回它的中序 遍历. 实现 # def __init__(self, x): # self.val = x # self.left = None # self.right = N ...

随机推荐

  1. Core Mvc传值Query、Form、Cookies、Session、TempData、Cache

    1.传值方法 使用Request的方法(1-3): 1)Query:获取链接?后面的值 如:http://localhost:55842/Home/About?name=kxy public IAct ...

  2. 【Math for ML】线性代数之——向量空间

    I. Groups 在介绍向量空间之前有必要介绍一下什么Group,其定义如下: 注意定义中的\(\bigotimes\)不是乘法,而是一种运算符号的统一标识,可以是乘法也可以是加法等. 此外,如果\ ...

  3. MySql联合查询

    将多条查询语句的结果合并为一个结果 *多表查询是横向连接,联合查询是纵向连接. 语法: 查询语句1 union 查询语句2 union 查询语句3 *union关键字默认去重,union all包含重 ...

  4. uio.c 分析【转】

    转自:https://blog.csdn.net/ganggexiongqi/article/details/6737647 版权声明:本文为博主原创文章,未经博主允许不得转载. https://bl ...

  5. shutil.copy()、os.walk()、os.rename()实例

    #!/usr/bin/python # -*- coding: UTF-8 -*- import os import shutil Path = "panel/" PNPath = ...

  6. 统一门户与业务系统的sso整合技术方案(单点登录)

    一.单点登录(SSO,Single Sign On)整合目前计划接入统一门户的所有业务系统均为基于JavaEE技术的B/S架构系统.由于统一门户的单点登录技术选用的是JA-SIG组织开发的Cas Se ...

  7. percona mysql5.7关闭审计功能方法

    数据库的审计日志占用大量空间,当时是为了测试审计功能开启的,现在需要关闭 # /data/mysql_data]# du -sh * 124G audit.log # 查询审计相关参数 mysql&g ...

  8. python操作三大主流数据库(14)python操作redis之新闻项目实战②新闻数据的展示及修改、删除操作

    python操作三大主流数据库(14)python操作redis之新闻项目实战②新闻数据的展示及修改.删除操作 项目目录: ├── flask_redis_news.py ├── forms.py ├ ...

  9. nginx配置文件注释说明

    #定义Nginx运行的用户和用户组 user www www; #nginx进程数,建议设置为等于CPU总核心数. worker_processes 8; #全局错误日志定义类型,[ debug | ...

  10. Light OJ 1102

    题意: 给你一个数 N , 求分成 K 个数 (可以为 0 ) 的种数: 思路: 类似 在K个抽屉放入 N 个苹果, 不为0, 就是 在 n-1 个空隙中选 m-1个: 为 0, 就可以先在 K 个抽 ...