数据结构(C++)二叉树前序中序后序遍历(非递归)

二叉树的建立与之前的相同,就不多做阐述。非递归的前序中序遍历,主要思想就是把二叉树上的每一个结点进行入栈操作,然后输出结点的值,出栈。但在其中前序和中序的顺序不一样,但大体的思路是相同的。后序遍历相比前序中序更为复杂。

都是沿着左分支访问,直到左分支为空时,再依次对栈中节点的右分支进行处理。(遵循从左至右的遍历原则,体现深度优先搜索的思想)
前序遍历:每个结点只进栈一次,在进栈前访问结点
中序遍历:每个结点进栈一次,在出栈时进行访问
后序遍历:每个结点进栈两次,在第二次出栈时访问节点

前序遍历

以根节点开始,每次都进行输出,然后不断地遍历结点的左子树,将遍历到的左子树入栈,直到结点的左子树为空,跳出此while循环后判断栈是否为空,把栈顶结点记录下来后出栈,遍历记录的节点的右子树。外层while循环进行控制,当遇到出栈后继续遍历左子树等一系列操作。

	void PreOrder(BiNode* root)
	{
		stack<BiNode*>s;
		while (root != NULL || !s.empty())
		{
			while (root != NULL)
			{
				cout << root->data;
				s.push(root);
				root = root->lchild;
			}
			if (!s.empty())
			{
				root = s.top();
				s.pop();
				root = root->rchild;
			}
		}
	}

中序遍历

从根节点开始,不断地将左子树入栈,但并不输出,知道左子树为空后,将此结点记录后出栈,再进行输出,然后遍历其右子树。外层while循环控制每次遍历到右子树后进行的一系列操作。

void InOrder(BiNode* root)
	{
		stack<BiNode*>s;
		while (root != NULL || !s.empty())
		{
			while (root != NULL)
			{
				s.push(root);
				root = root->lchild;
			}
			if (!s.empty())
			{
				root = s.top();
				s.pop();
				cout << root->data;
				root = root->rchild;
			}
		}
	}

其实上面的两个遍历思想都是靠栈实现的,实现思路还是比较简单,明白大体的思路后代码实现也没有太大的难度。

后序遍历

思想:

  • 遇到一个结点,把它推入栈中,遍历它的左子树
  • 左子树遍历结束后,还不能马上访问处于栈顶的该结点,而是要再按照它的右链接结构指示的地址去遍历该结点的右子树
  • 遍历遍右子树后才能从栈顶托出该结点并访问之

解决方案:
需要给栈中的每个元素加上一个特征位,以便当从栈顶弹出一个结点时区别是从栈顶元素左边回来的(则要继续遍历右子树),还是从右边回来的(该结点的左、右子树均已遍历)
特征:Left表示已进入该结点的左子树,将从左边回来;
特征:Right表示已进入该结点的右子树,将从右边回来

enum Tags { Left, Right };
class StackElement
{
public:
	Tags tag;
	BiNode* point;
};
void PostOrder(BiNode* root)
	{
		StackElement element;
		stack<StackElement>s;
		BiNode* point;
		if (root == NULL)
			return;
		else
			point = root;
		while (true)
		{
			while (point != NULL)
			{
				element.point = point;
				element.tag = Left;
				s.push(element);
				point = point->lchild;
			}
			element = s.top();
			s.pop();
			point = element.point;
			while (element.tag == Right)
			{
				cout << point->data;
				if (s.empty())
					return;
				else
				{
					element = s.top();
					s.pop();
					point = element.point;
				}
			}
			element.tag = Right;
			s.push(element);
			point = point->rchild;
		}
	}

后序比前序中序都要复杂一些,层序遍历反而就会简单很多,广搜思想,实现较为方便。

全部代码:

#include<iostream>
#include<stack>
using namespace std;
struct BiNode
{
	char data;
	BiNode* lchild, * rchild;
};
enum Tags { Left, Right };
class StackElement
{
public:
	Tags tag;
	BiNode* point;
};
class BiTree
{
public:
	BiTree() { root = Creat(); }
	void PreOrder() { PreOrder(root); }
	void InOrder() { InOrder(root); }
	void PostOrder() { PostOrder(root); }
private:
	BiNode* root;
	BiNode* Creat()
	{
		BiNode* root;
		char ch;
		cin >> ch;
		if (ch == '#')
			root = NULL;
		else
		{
			root = new BiNode;
			root->data = ch;
			root->lchild = Creat();
			root->rchild = Creat();
		}
		return root;
	}
	void PreOrder(BiNode* root)
	{
		stack<BiNode*>s;
		while (root != NULL || !s.empty())
		{
			while (root != NULL)
			{
				cout << root->data;
				s.push(root);
				root = root->lchild;
			}
			if (!s.empty())
			{
				root = s.top();
				s.pop();
				root = root->rchild;
			}
		}
	}
	void InOrder(BiNode* root)
	{
		stack<BiNode*>s;
		while (root != NULL || !s.empty())
		{
			while (root != NULL)
			{
				s.push(root);
				root = root->lchild;
			}
			if (!s.empty())
			{
				root = s.top();
				s.pop();
				cout << root->data;
				root = root->rchild;
			}
		}
	}
	void PostOrder(BiNode* root)
	{
		StackElement element;
		stack<StackElement>s;
		BiNode* point;
		if (root == NULL)
			return;
		else
			point = root;
		while (true)
		{
			while (point != NULL)
			{
				element.point = point;
				element.tag = Left;
				s.push(element);
				point = point->lchild;
			}
			element = s.top();
			s.pop();
			point = element.point;
			while (element.tag == Right)
			{
				cout << point->data;
				if (s.empty())
					return;
				else
				{
					element = s.top();
					s.pop();
					point = element.point;
				}
			}
			element.tag = Right;
			s.push(element);
			point = point->rchild;
		}
	}
};
int main()
{
	BiTree bt;
	bt.PreOrder();
	cout << endl;
	bt.InOrder();
	cout << endl;
	bt.PostOrder();
	cout << endl;
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值