代码随想录训练营day14|144.二叉树的前序遍历、145.二叉树的后序遍历、94.二叉树的中序遍历

对于二叉树的遍历,我们常用递归法解决。对于能用递归的方法,一定能用栈+迭代解决。

故在本文中三个遍历,均采用先递归,后迭代的顺序溢出介绍。

二叉树的遍历

leetcode题目链接:

144. 二叉树的前序遍历 - 力扣(LeetCode)

145. 二叉树的后序遍历 - 力扣(LeetCode)

94. 二叉树的中序遍历 - 力扣(LeetCode)

递归文章讲解:代码随想录 (programmercarl.com)

迭代文章讲解:代码随想录 (programmercarl.com)

递归视频讲解:每次写递归都要靠直觉? 这次带你学透二叉树的递归遍历!| LeetCode:144.前序遍历,145.后序遍历,94.中序遍历_哔哩哔哩_bilibili

前后序遍历迭代:写出二叉树的非递归遍历很难么?这次让你不再害怕非递归!|二叉树的非递归遍历 | 二叉树的遍历迭代法 | 前序与中序_哔哩哔哩_bilibili 中序遍历迭代:

写出二叉树的非递归遍历很难么?这次再带你写出中序遍历的迭代法!|二叉树的非递归遍历 | 二叉树的遍历迭代法_哔哩哔哩_bilibili


前序遍历:

递归:

class Solution {
public:
	void traversal(TreeNode* root, vector<int>& result)
	{
		if (root == nullptr)
			return;
		result.push_back(root->val);
		traversal(root->left,result);
		traversal(root->right,result);
	}
	vector<int> preorderTraversal(TreeNode* root) {
		traversal(root, result);
		return result;
	}
private:
	vector<int> result;
};

迭代:

注意:迭代入栈时要先右再左,这样出栈的时候才能先左后右。

class Solution {
public:
	vector<int> preorderTraversal(TreeNode* root) {
		if(root==nullptr)
			return {};
		TreeStack.push(root);
		TreeNode* cur;
		while (!TreeStack.empty())
		{
			cur = TreeStack.top();
			TreeStack.pop();
			result.push_back(cur->val);
			if (cur->right != nullptr)
				TreeStack.push(cur->right);
			if (cur->left != nullptr)
				TreeStack.push(cur->left);
		}
		return result;
	}
private:
	vector<int> result;
	stack<TreeNode*> TreeStack;
};

后序遍历:

递归:

class Solution {
public:
	void traversal(TreeNode* root, vector<int>& result)
	{
		if (root == nullptr)
			return;
		traversal(root->left, result);
		traversal(root->right, result);
		result.push_back(root->val);
	}
	vector<int> postorderTraversal(TreeNode* root) {
		traversal(root, result);
		return result;
	}
private:
	vector<int> result;
};

迭代:

        先序遍历是中左右,后续遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了。

class Solution {
public:
	vector<int> postorderTraversal(TreeNode* root) {
		TreeStack.push(root);
		TreeNode* cur;
		if (root == nullptr)
			return {};
		while (!TreeStack.empty())
		{
			cur = TreeStack.top();
			TreeStack.pop();
			result.push_back(cur->val);
			if (cur->left != nullptr)
				TreeStack.push(cur->left);
			if (cur->right != nullptr)
				TreeStack.push(cur->right);
		}
		reverse(result.begin(), result.end());
		return result;
	}
private:
	vector<int> result;
	stack<TreeNode*> TreeStack;
};

中序遍历: 

递归:

class Solution {
public:
	void traversal(TreeNode* root, vector<int>& result)
	{
		if (root == nullptr)
			return;
		traversal(root->left, result);
		result.push_back(root->val);
		traversal(root->right, result);
	}
	vector<int> inorderTraversal(TreeNode* root) {
		traversal(root, result);
		return result;
	}
private:
	vector<int> result;
};

迭代:

对于中序遍历,由于我们遍历到的节点和要处理的节点不是同一个节点,所以就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。

class Solution {
public:
	vector<int> inorderTraversal(TreeNode* root) {
		if (root == nullptr)
			return {};
		TreeNode* cur = root;
		while (cur!=nullptr||!TreeStack.empty())
		{
			if (cur != nullptr)
			{
				TreeStack.push(cur);
				cur = cur->left;
			}
			else
			{
				cur = TreeStack.top();
				TreeStack.pop();
				result.push_back(cur->val);
				cur = cur->right;
			}
		}
		return result;
	}
private:
	vector<int> result;
	stack<TreeNode*> TreeStack;
};

统一风格的迭代写法:

那我们就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记。

如何标记呢,就是要处理的节点放入栈之后,紧接着放入一个空指针作为标记。 这种方法也可以叫做标记法。

如图所示:

class Solution {
public:
	vector<int> inorderTraversal(TreeNode* root) {
		if (root == nullptr)
			return {};
		TreeStack.push(root);
		while (!TreeStack.empty())
		{
			TreeNode* cur = TreeStack.top();
			if (cur != nullptr)
			{
				TreeStack.pop();
				if (cur->right != nullptr)
					TreeStack.push(cur->right);
				TreeStack.push(cur);
				TreeStack.push(nullptr);
				if (cur->left != nullptr)
					TreeStack.push(cur->left);
			}
			else
			{
				TreeStack.pop();
				cur = TreeStack.top();
				TreeStack.pop();
				result.push_back(cur->val);
			}
		}
		return result;
	}
private:
	vector<int> result;
	stack<TreeNode*> TreeStack;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值