[转]数据结构 二叉树的遍历

/**********************************************************************
二叉树的基本操作
(1)二叉树的数据结构
(2)二叉树的构造
(3)二叉树遍历 :先序,中序,后序
************************************************************************/
#include <cstdio>
#include <cstdlib>
const int MAX=20;
//二叉树的结构 利用双链表实现
typedef struct Node
{
	char ch;				 // 数据域
	struct Node *plchild;    //左子树指针
	struct Node *prchild;	//右子树指针
}BiTreeNode;

//构造二叉树 
//1.按照先序遍历法构造 利用递归构造
// ABD#G##EH##I##CF#J###
void CreateBiTree_PreOrder(BiTreeNode * &T) //注意这里传入的是指针的引用
{	
	char ch;
	scanf("%c",&ch);
	if('#'==ch)
		T=NULL;
	else {
		T=new BiTreeNode;
		if(NULL==T)
			exit(-1);
		T->ch=ch;
		CreateBiTree_PreOrder(T->plchild); // 构造左子树
		CreateBiTree_PreOrder(T->prchild); // 构造右子树
	}
}
//2.按照带括号的字符串创建二叉树结构
/*思路:a(b(c,d),e(f(,g),h(i)))
	'(': 表明已创建的节点为双亲节点,入栈。将要创建左孩子节点,用flag=1标记
	',': 表明将要创建右孩子节点。用flag=2标记
	')': 表明左右孩子节点创建和链接完毕,父节点出栈。
	default: 创建节点,并且赋值,判断链接情况
 */
void CreateBiTree_ByString(BiTreeNode* &T, char str[])
{
	BiTreeNode* Stack[MAX];		// 栈用于存储父节点
	int top=0,flag=0;
	BiTreeNode* p=NULL;			//用于临时指针
	while(*str)
	{
		switch(*str)
		{
			case '(':
					Stack[top++]=p;
					flag=1;		//表示即将要创建的是 左孩子节点
					break;
			case ',':
					flag=2;  //表明将要创建	右孩子节点
					break;
			case ')':
					--top;	//将父节点出栈
					break;
			default:
				{	
					p=new BiTreeNode;
					if(NULL==p)
						return  ;
					if(T==NULL)
						T=p;
					p->ch=*str;
					p->plchild=NULL;
					p->prchild=NULL;
					switch(flag) //此时 flag要初始化 不然非法访问
					{
						case 1:
							Stack[top-1]->plchild=p; //将父节点与左孩子节点链接
							break;
						case 2:
							Stack[top-1]->prchild=p; //将父节点与右孩子节点链接
							break;
					}
					break;
				}
		}
		++str;
	}
}
// 递归先序遍历
void PreOrderTraverse_Recur(BiTreeNode *T)
{	
	if(T) 
	{
		printf("%2c",T->ch);
		PreOrderTraverse_Recur(T->plchild);
		PreOrderTraverse_Recur(T->prchild);
	}
}
// 非递归先序遍历
/* 思路: 先访问父节点,打印。然后压入栈中,然后访问左孩子节点,访问打印压栈。
		将左孩子一个个压入栈中,直到NULL.然后在访问右孩子节点。同理按前
 */
void PreOrderTraverse_NoRecur(BiTreeNode *T)
{
	BiTreeNode* Stack[MAX]; //利用数组构造栈 先进后出
	int top=0;
	BiTreeNode *p=T;
	while( p || top >0)
	{
		while(p)
		{
			printf("%2c",p->ch);	//先访问
			Stack[top++]=p;		//将 父节点压栈
			p=p->plchild;		//访问左孩子节点
		}
		if(top>0)	//top 代表栈中有多个节点
		{ //开始访问 右孩子节点
			p=Stack[--top];		//如果某个父节点的左孩子节点为NULL 那么出栈该父节点。
			p=p->prchild;		//然后又跳入到 访问该右孩子的左子树
		}
	}
}
// 递归中序遍历
void InOrderTraverse_Recur(BiTreeNode *T)
{
	if(T)  //如果节点不为NULL 
	{	
		InOrderTraverse_Recur(T->plchild); //先放问 左孩子树
		printf("%2c",T->ch);		   //然后在 访问根节点
		InOrderTraverse_Recur(T->prchild); // 然后在访问 右孩子树
	}
}
// 非递归中序遍历 
/* 思路:相比于先序而言(一直将父节点压栈,父节点出栈的时候就是要访问该节点的右孩子树)
		 所以中序遍历,一直压入左孩子节点,直到NULL.在出栈的时候打印父节点值。
 */
void InorderTraverse_NoRecur(BiTreeNode *T)
{
	BiTreeNode* Stack[MAX];
	int top=0;
	BiTreeNode *p=T;
	while( p || top>0 )
	{
		while(p)
		{
			Stack[top++]=p;  //直接将父节点入栈
			p=p->plchild;	// 然后访问左子树
		}
		if(top>0)
		{
			p=Stack[--top];		 //将父节点处栈
			printf("%2c",p->ch); //打印父节点值
			p=p->prchild;		 //访问右孩子子树
		}
	}
}
// 递归后序遍历
void AfterOrderTraverse_Recur(BiTreeNode *T)
{
	if(T)
	{
		AfterOrderTraverse_Recur(T->plchild);
		AfterOrderTraverse_Recur(T->prchild);
		printf("%2c",T->ch);	
	}
}
// 非递归后序遍历
/*思路:依旧是将父节点依次压栈。直到左节点为NULL,此时不出栈父节点,而是直接访问右孩子节点
		同时设定q用于检测是否已经访问过右孩子节点。
 */
void AfterOrderTraverse_NoRecur(BiTreeNode *T)
{
	BiTreeNode* Stack[MAX];
	int top=0;
	BiTreeNode *p=T,*q=NULL; // q用于判断右节点是否访问过
	while(p || top>0)
	{
		while(p) //直到没有左孩子节点
		{
			Stack[top++]=p;
			p=p->plchild; 
		}
		if(top>0)
		{
			p=Stack[top-1]; //不出栈 直接访问右子树
			if(p->prchild==NULL || p->prchild == q) //没有右节点或者右节点已经访问过
			{
				printf("%2c",p->ch);
				q=p;
				p=NULL;
				top--;
			}
			else //有右节点 且没被访问过
				p=p->prchild;
		}
	}
	
}
//销毁二叉树
void DestoryBiTree(BiTreeNode* &T)
{
	if(T)
	{
		if(T->plchild)
			DestoryBiTree(T->plchild);
		if(T->prchild)
			DestoryBiTree(T->prchild);
		delete T;
		T=NULL;
	}
}
int main()
{//ABD#G##EH##I##CF#J###
	BiTreeNode *T=NULL;
	CreateBiTree_PreOrder(T);
	puts("递归先序遍历:");
	PreOrderTraverse_Recur(T);
	puts("");
	puts("非递归先序遍历:");
	PreOrderTraverse_NoRecur(T);
	puts("");
	puts("递归中序遍历:");
	InOrderTraverse_Recur(T);
	puts("");
	puts("非递归中序遍历:");
	InorderTraverse_NoRecur(T);
	puts("");
	puts("递归后序遍历:");
	AfterOrderTraverse_Recur(T);
	puts("");
	puts("非递归后序遍历:");
	AfterOrderTraverse_NoRecur(T);
	puts("");
	DestoryBiTree(T);	//销毁二叉树
	puts("
--按照带括号的字符串输入------------");
	BiTreeNode *T2=NULL;
	char str[]="a(b(c,d),e(f(,g),h(i)))";
	CreateBiTree_ByString(T2,str);
	puts("递归先序遍历:");
	PreOrderTraverse_Recur(T2);
	puts("");
	puts("非递归先序遍历:");
	PreOrderTraverse_NoRecur(T2);
	puts("");
	puts("递归中序遍历:");
	InOrderTraverse_Recur(T2);
	puts("");
	puts("非递归中序遍历:");
	InorderTraverse_NoRecur(T2);
	puts("");
	puts("递归后序遍历:");
	AfterOrderTraverse_Recur(T2);
	puts("");
	puts("非递归后序遍历:");
	AfterOrderTraverse_NoRecur(T2);
	puts("");
	//DestoryBiTree(T2);	//销毁二叉树
}

  

原文地址:https://www.cnblogs.com/ransw/p/4171285.html