leetcode94_二叉树的中序遍历

23 篇文章 0 订阅
12 篇文章 0 订阅

一.  这题最直接的思路就是递归.

#include <iostream>
#include <vector>
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

class Solution {
public:
	//一定要设置全局变量的res.
	//不然res不会改变.
	vector<int> res;
	vector<int> inorderTraversal(TreeNode* root) {
		if (root == NULL)
			return res;
		res = inorderTraversal(root->left);
		res.push_back(root->val);
		res = inorderTraversal(root->right);
		return res;
	}
};

 

二. 但是这道题的重点是使用迭代算法.

三.  参考一下官方题解.

作者:LeetCode
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/er-cha-shu-de-zhong-xu-bian-li-by-leetcode/

方法一:递归

1.  第一种解决方法是使用递归。这是经典的方法,直截了当。我们可以定义一个辅助函数来实现递归。

//方法一:递归
class Solution {
public:
	//数组切记传入它的指针,否则不会跟着改变.
	void helper(TreeNode* root, vector<int>& res) {
		if (root == NULL)
			return;
		helper(root->left, res);
		res.push_back(root->val);
		helper(root->right, res);
	}
	vector<int> inorderTraversal(TreeNode* root) {
		vector<int> res;
		helper(root, res);
		return res;
	}
};

复杂度分析(可以参考算法递归树那一节)

1.  时间复杂度:O(n)。递归函数 T(n)=2⋅T(n/2)+1。(每个节点最多遍历两次,一次递, 一次归, 所以O(n)).
2.  空间复杂度:最坏情况下需要空间O(n)(退化成链表的时候),平均情况为O(logn)(递归树深度)。

 

方法二:基于栈的遍历

1.  本方法的策略与上方法很相似,区别是使用了栈

//方法二:基于栈的遍历
class Solution {
public:
	vector<int> inorderTraversal(TreeNode* root) {
		vector<int> res;
		//栈里存的是树的节点.
		stack<TreeNode*> st;
		while (root != NULL || !st.empty()) {
			//一直循环,观察有无左子树.
			while (root != NULL) {
				st.push(root);
				root = root->left;
			}
			root = st.top();
			res.push_back(root->val);
			st.pop();
			root = root->right;
		}
		return res;
	}
};

复杂度分析

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

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

 

四. 参考另一位大神的新颖方法.

作者:hzhu212
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/yan-se-biao-ji-fa-yi-chong-tong-yong-qie-jian-ming/

1.   颜色标记法-一种通用且简明的树遍历方法

2.   官方题解中介绍了三种方法来完成树的中序遍历,包括:递归   借助栈的迭代方法   莫里斯遍历

3.   在树的深度优先遍历中(包括前序、中序、后序遍历),递归方法最为直观易懂,但考虑到效率,我们通常不推荐使用递归

4.   栈迭代方法虽然提高了效率,但其嵌套循环却非常烧脑,不易理解,容易造成“一看就懂,一写就废”的窘况。而且对于不同的遍历顺序(前序、中序、后序),循环结构差异很大,更增加了记忆负担。

5.  因此,我在这里介绍一种“颜色标记法”(瞎起的名字……),兼具栈迭代方法的高效,又像递归方法一样简洁易懂,更重要的是,这种方法对于前序、中序、后序遍历,能够写出完全一致的代码

6.  其核心思想如下:

使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
如果遇到的节点为灰色,则将节点的值输出。

7.  这个方法很好,递归与非递归的记忆方法相同,只是顺序相反(只需要移动三句话的顺序)。如中序遍历:递归是左根右,非递归是右根左;先序遍历:左右根=》根右左。后序类似.

//大神的颜色标记法.
class Solution {
	vector<int>ans;
public:
	vector<int> inorderTraversal(TreeNode* root) {
		int white = 0;
		int gray = 1;
		//pair与make_pair仔细学学.
		stack<pair<int, TreeNode*>>s;
		s.push(make_pair(white, root));
		while (!s.empty()) {
			int color = s.top().first;
			TreeNode* t = s.top().second;
			s.pop();
			if (t == NULL) continue;
			if (color == white) {
				s.push(make_pair(white, t->right));
				s.push(make_pair(gray, t));
				s.push(make_pair(white, t->left));
			}
			else ans.push_back(t->val);
		}
		return ans;
	}
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值