最簡潔清晰的二叉樹非遞歸遍歷:(一)前中後序遍歷

一、前序非遞歸遍歷

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);

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章