最简洁清晰的二叉树非递归遍历:(一)前中后序遍历

一、前序非递归遍历

1、算法思路

利用栈先进后出的特性,在一个有三个结点的子树中,先对根节点做出操作,再将右子树结点入栈,再将左子树结点入栈,这样利用栈遍历的顺序就是根----左-----右(因为根已经最先处理)。

思路比较简单,直接看源码即可理解。

2、源码

	void Pre_Travel(TreeNode* root)
	{
		stack<TreeNode*> stackTree;

		if (root == NULL) return;

		stackTree.push(root);

		while (stackTree.size() > 0)
		{
			TreeNode* tempNode = stackTree.top();
			stackTree.pop();

			printf("%d  ", tempNode->val);

			if (tempNode->right != NULL)
				stackTree.push(tempNode->right);

			if (tempNode->left != NULL)
				stackTree.push(tempNode->left);
		}
	}

二、中序遍历

1、算法思路

最重要的第一步就是,先找到左子树中最后一个没有左子节点的结点。
剩下内容比较简单 ,容易理解,看源码即可。

2、源码

	void Mid_Travel(TreeNode* root)
	{
		if (root == NULL)
			return;

		stack<TreeNode*> stackTree;
		TreeNode* p = root;

		while (p || stackTree.size() > 0)
		{
			//到最后一个没有左子树的结点
			while (p)
			{
				stackTree.push(p);
				p = p->left;
			}

			if (stackTree.size() > 0)
			{
				TreeNode* tempNode = stackTree.top();
				stackTree.pop();

				printf("%d  ", tempNode->val);

				//对右子树继续进行遍历其左子树
				p = tempNode->right;
			}
		}
	}

三、后序遍历

1、算法思路

三种非递归算法中,后序遍历算是相对更加复杂一点,复杂的原因在于,对于根节点的访问只有在子节点都被访问之后才能进行,这就需要使用一个缓存,来记录上次访问的结点,再将当前访问结点的左右子树和缓存比较,如果相等,说明其左右子树已经被访问过,此时可以读取当前节点,反之不行。

2、源码

void Pos_Travel(TreeNode* root)
	{
		if (root == NULL)
			return;

		stack<TreeNode*> stackTree;
		TreeNode* pre = NULL;

		stackTree.push(root);

		while (stackTree.size() > 0)
		{
			TreeNode* tempNode = stackTree.top();
			
			//如果左右子树被访问过
			if ((tempNode->left == NULL && tempNode->right == NULL) || ((pre != NULL) && (pre == tempNode->left || pre == tempNode->right)))
			{
				printf("%d  ", tempNode->val);
				pre = tempNode;
				stackTree.pop();
			}

			//左右子树没有被访问过
			else
			{
				if (tempNode->right != NULL)
					stackTree.push(tempNode->right);

				if (tempNode->left != NULL)
					stackTree.push(tempNode->left);
			}
		}
	}

四、完整Demo

#include <vector>
#include <stack>

using namespace std;
struct TreeNode
{
	int val;
	TreeNode* left;
	TreeNode* right;

	TreeNode(int v) :val(v), left(NULL), right(NULL) {};
};


class Solution
{
public:
	void Pre_Travel(TreeNode* root)
	{
		stack<TreeNode*> stackTree;

		if (root == NULL) return;

		stackTree.push(root);

		while (stackTree.size() > 0)
		{
			TreeNode* tempNode = stackTree.top();
			stackTree.pop();

			printf("%d  ", tempNode->val);

			if (tempNode->right != NULL)
				stackTree.push(tempNode->right);

			if (tempNode->left != NULL)
				stackTree.push(tempNode->left);
		}
	}

	void Mid_Travel(TreeNode* root)
	{
		if (root == NULL)
			return;

		stack<TreeNode*> stackTree;
		TreeNode* p = root;

		while (p || stackTree.size() > 0)
		{
			//到最后一个没有左子树的结点
			while (p)
			{
				stackTree.push(p);
				p = p->left;
			}

			if (stackTree.size() > 0)
			{
				TreeNode* tempNode = stackTree.top();
				stackTree.pop();

				printf("%d  ", tempNode->val);

				//对右子树继续进行遍历其左子树
				p = tempNode->right;
			}
		}
	}

	void Pos_Travel(TreeNode* root)
	{
		if (root == NULL)
			return;

		stack<TreeNode*> stackTree;
		TreeNode* pre = NULL;

		stackTree.push(root);

		while (stackTree.size() > 0)
		{
			TreeNode* tempNode = stackTree.top();
			
			//如果左右子树被访问过
			if ((tempNode->left == NULL && tempNode->right == NULL) || ((pre != NULL) && (pre == tempNode->left || pre == tempNode->right)))
			{
				printf("%d  ", tempNode->val);
				pre = tempNode;
				stackTree.pop();
			}

			//左右子树没有被访问过
			else
			{
				if (tempNode->right != NULL)
					stackTree.push(tempNode->right);

				if (tempNode->left != NULL)
					stackTree.push(tempNode->left);
			}

		}
	}
};

void main()
{
	TreeNode* root=new TreeNode(3);
	root->left = new TreeNode(2);
	root->right = new TreeNode(5);
	root->left->left = new TreeNode(4);
	root->left->right = new TreeNode(7);

	Solution solution;
	solution.Mid_Travel(root);

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值