非递归二叉树先序遍历、中序遍历及后序遍历

数据结构定义

struct Node {
	char val;
	pNode lchild, rchild;
};

二叉树形态:

       A
     /   \
    B     C
   / \   / \
  D   E F   G
       / \
      H   I

前序遍历:

先判断节点的指针是否为空,不为空就先访问该结点,然后直接进栈,接着遍历左子树;为空则要从栈中弹出一个节点来,这个时候弹出的结点就是其父亲,然后访问其父亲的右子树,直到当前节点为空且栈为空时,算法结束.

void preVisitStack(pNode root)
{
	stack<pNode> s;
	pNode p = root;
	while (p != NULL || !s.empty()) {
		if (p != NULL) {
			printf("%c ", p->val);
			s.push(p);
			p = p->lchild;
		}
		else {
			p = s.top();
			s.pop();
			p = p->rchild;
		}
	}
	cout << endl;
}

中序遍历:

和先序遍历一样,但在访问节点的顺序不一样,访问节点的时机是从栈中弹出元素时访问,如果从栈中弹出元素,就意味着当前节点父亲的左子树已经遍历完成,这时候访问父亲,就是中序遍历.

void midVisitStack(pNode root)
{
	stack<pNode> s;
	pNode p = root;
	while (p != NULL || !s.empty()) {
		if (p != NULL) {
			s.push(p);
			p = p->lchild;
		}
		else {
			p = s.top();
			printf("%c ", p->val);
			s.pop();
			p = p->rchild;
		}
	}
	cout << endl;
}

后序遍历:

后续遍历,首先访问左子树,把父亲节点保存于栈中,问题是当元素从栈中弹出的时候,我们无法判断这个时候是该访问其右子树还是访问父亲节点,于是我们就需要一个标记,当访问左子树时我们把父亲节点的标记设为1,表示下一步如果弹出该节点,就访问其右子树;弹出一个节点时,我们要判断该节点的标记,如果是1,则访问其右子树,并把该节点的标记设置成2,表示下一步就访问该节点,然后把该节点继续入栈,如果是2,那么表示访问该节点,访问并且丢弃该节点.

void backVisitStack(pNode root)
{
	stack<pNode> s;
	pNode p, q;
	p = root;
	q = NULL;
	while (p != NULL || !s.empty())
	{
		while (p != NULL)
		{
			s.push(p);
			p = p->lchild;
		}
		if (!s.empty())
		{
			p = s.top();
			if (p->rchild == NULL || p->rchild == q)
			{
				printf("%c ", p->val);
				q = p;
				s.pop();
				p = NULL;   //重要  避免死循环
			}
			else
			{
				p = p->rchild;
			}
		}
	}
	cout << endl;
}

测试代码:

#include <iostream>
#include <stack>

using namespace std;

typedef struct Node *pNode;

struct Node {
	char val;
	pNode lchild, rchild;
};

void createBiTree(pNode &T)
{
	char c;
	cin >> c;
	if ('#' == c)
		T = NULL;
	else
	{
		T = new Node;
		T->val = c;
		createBiTree(T->lchild);
		createBiTree(T->rchild);
	}
}

void preVisitStack(pNode root)
{
	stack<pNode> s;
	pNode p = root;
	while (p != NULL || !s.empty()) {
		if (p != NULL) {
			printf("%c ", p->val);
			s.push(p);
			p = p->lchild;
		}
		else {
			p = s.top();
			s.pop();
			p = p->rchild;
		}
	}
	cout << endl;
}

void midVisitStack(pNode root)
{
	stack<pNode> s;
	pNode p = root;
	while (p != NULL || !s.empty()) {
		if (p != NULL) {
			s.push(p);
			p = p->lchild;
		}
		else {
			p = s.top();
			printf("%c ", p->val);
			s.pop();
			p = p->rchild;
		}
	}
	cout << endl;
}

void backVisitStack(pNode root)
{
	stack<pNode> s;
	pNode p, q;
	p = root;
	q = NULL;
	while (p != NULL || !s.empty())
	{
		while (p != NULL)
		{
			s.push(p);
			p = p->lchild;
		}
		if (!s.empty())
		{
			p = s.top();
			if (p->rchild == NULL || p->rchild == q)
			{
				printf("%c ", p->val);
				q = p;
				s.pop();
				p = NULL;   //重要  避免死循环
			}
			else
			{
				p = p->rchild;
			}
		}
	}
	cout << endl;
}

int main()
{
	Node* root;
	createBiTree(root);
	printf("先序遍历:");
	preVisitStack(root);
	printf("中序遍历:");
	midVisitStack(root);
	printf("后序遍历:");
	backVisitStack(root);
	system("pause");
}

测试输入:ABD##E##CFH##I##G##

测试结果:
前序遍历:  A B D E C F H I G 
中序遍历:  D B E A H F I C G 
后序遍历:  D E B H I F G C A 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值