二叉树的非递归(先序、中序、后序)遍历

二叉树的特点是每个结点至多只有两棵子树,它是一种很重要的数据结构,从树的特点我们可以利用递归很容易的实现它的创建以及遍历操作,上一篇已经用递归的方法实现了二叉树的先序、中序和后序的遍历,下面的代码是二叉树的非递归遍历的实现,三种遍历方式都给出了两种实现方法(注释掉的即为第二种实现方法),注释部分已经讲原理写出来了,由于自己语言组织能力不是很好,原理就是从网上找来的,我自己是通过这些原理来实现的遍历二叉树,希望也能给看到代码的人同样帮助。

/*
*@2012-12-14
*二叉树的非递归(先序、中序、后序)遍历
*/
#include<iostream>
using namespace std;
typedef char TElemType;		//二叉树数据元素的类型
typedef struct BitreeNode
{
	TElemType TItem;
	struct BitreeNode *lchild;
	struct BitreeNode *rchild;
}BitreeNode,*Bitree;

typedef struct	SNode
{         
	Bitree SItem;
	struct SNode *next;
}SNode , * LinkStack;
//初始化二叉树
int InitBitree(Bitree &T)
{
	T=(Bitree)malloc(sizeof(BitreeNode));
	if(!T)
		return 0;
	T->TItem='#';
	T->lchild=NULL;
	T->rchild=NULL;
	return 1;
}
//初始化栈
int InitStack(LinkStack &S)
{
	S=(LinkStack)malloc(sizeof(SNode)); //通过malloc函数分配空间
	if (!S)
		return 0;               //如果分配失败,则返回0
	S->next=NULL;
	return 1;		
}
//判断栈是否为空
int StackEmpty(LinkStack S)
{
	if (S!=NULL)                      //判断栈是否存在
	{
		if (S->next==NULL)
		{
			return 1;
		}
	}
	return 0;
}
//创建二叉树
int CreateBitree(Bitree &T)
{
	TElemType ch;
	ch=getchar();//测试字符串abc##de#g##f###
	if(ch=='#')
		T=NULL;
	else
	{
		T=(Bitree)malloc(sizeof(BitreeNode));
		if(!T)
			return 0;
		else
		{
			T->TItem=ch;
			CreateBitree(T->lchild);
			CreateBitree(T->rchild);
		}
	}
	return 1;
}
//获取栈顶元素
int GetTop(LinkStack S,Bitree &e)
{
	LinkStack q=S;
	if (S!=NULL) //判断栈是否存在
	{
		if (q->next!=NULL)//判断栈是否为空
		{
			while (q->next!=NULL)
			{
				q=q->next;
			}
			e=q->SItem;
			return 1;
		}	
	}
	return 0;             //如果不能得到数据元素,则返回0(false)
}
//压栈函数
int Push(LinkStack &S,Bitree e)
{
	LinkStack q=S;
	LinkStack m=(LinkStack)malloc(sizeof(SNode)); //通过malloc函数分配空间
	if (S!=NULL)
	{
		while (q->next!=NULL)
		{
			q=q->next;
		}
		m->SItem=e;
		m->next=NULL;
		q->next=m;
	}
	return 0;
}
//出栈函数
int Pop(LinkStack &S,Bitree &e)
{
	LinkStack q=S;
	if (S!=NULL)
	{
		if (q->next!=NULL)    //若栈不是空的
		{
			while (q->next->next!=NULL)
			{
				q=q->next;
			}
			e=q->next->SItem;
			q->next=NULL;
			return 1;
		}
	}
	return 0;
}
//遍历访问函数
int Visit(TElemType e)
{
	if(e!=NULL)
	{
		cout<<e<<" ";
		return 1;
	}else
		return 0;
}
/*先序遍历二叉树根->左->右;
1)访问结点P,并将结点P入栈;
2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);
  若不为空,则将P的左孩子置为当前的结点P;
3)直到P为NULL并且栈为空,则遍历结束。
*/
int PreOrederTraverse(Bitree &T,int(*Visit)(TElemType))
{
/*	LinkStack S;
	Bitree p=T;
	InitStack(S);
	Push(S,T);
	while (p || !StackEmpty(S))
	{
		while (p!=NULL)
		{
			Visit(p->TItem);
			Push(S,p);
			p=p->lchild;
		}
		if(!StackEmpty(S))
		{
			GetTop(S,p);
			Pop(S,p);
			p=p->rchild;
		}
	}
	*/
	LinkStack S;
	Bitree p=T;
	InitStack(S);
	Push(S,T);
	while (!StackEmpty(S))
	{
		while (GetTop(S,p) && p)
		{
			if(!Visit(p->TItem))
				return 0;
			Push(S,p->lchild);//向左走到尽头
		}
		Pop(S,p);//空指针退栈
		if(!StackEmpty(S)){//访问节点,向右一步
			Pop(S,p);
			Push(S,p->rchild);
		}
		
	}
	return 0;
}
/*
*中遍历二叉树:左->根->右
1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;
2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;
3)直到P为NULL并且栈为空则遍历结束
*/
int InOrderTraverse(Bitree &T,int(*Visit)(TElemType))
{
/*	LinkStack S;
	Bitree p=T;
	InitStack(S);
	Push(S,T);//根指针进栈
	while (p || !StackEmpty(S))
	{
		if(p)
		{
			Push(S,p);
			p=p->lchild;//根指针进栈,遍历左子树
		}
		else//根指针退栈,访问根结点,遍历右子树
		{
			Pop(S,p);
			if(!Visit(p->TItem))
					return 0;
			p=p->rchild;
		}
	}*/
	LinkStack S;
	Bitree p=T;
	InitStack(S);
	Push(S,T);//根指针进栈
	while (!StackEmpty(S))
	{
		while (GetTop(S,p) && p)
		{
			Push(S,p->lchild);//向左走到尽头
		}
		Pop(S,p);//空指针退栈
		if(!StackEmpty(S)){//访问节点,向右一步
			Pop(S,p);
			if(!Visit(p->TItem))
				return 0;
			Push(S,p->rchild);
		}
	}
	return 1;
}
/*
*后序遍历二叉树:左->右->根
1)对于任一结点P,先将其入栈。
2)如果P不存在左孩子和右孩子,或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则可以直接访问该结点。
3)若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问。
  左孩子和右孩子都在根结点前面被访问。
*/
int PostOrderTraverse(Bitree &T,int(*Visit)(TElemType))
{
/*	Bitree q=T;
	LinkStack S;
	InitStack(S);
	while (T || !StackEmpty(S))
	{
		if (T)
		{
			Push(S, T);
			T=T->lchild;
		}
		else
		{
			GetTop(S, T);
			if (T->rchild==NULL || T->rchild==q)
			{
				Visit(T->TItem);
				Pop(S, T);
				q=T;
				T=NULL;
			}
			else
			{
				T=T->rchild;
			}
		}
 }*/
	LinkStack S;
	Bitree cur;//当前结点
	Bitree pre=NULL;//前一次访问的结点
	InitStack(S);
	Push(S,T);//根指针进栈
    while(!StackEmpty(S))
    {
        GetTop(S,cur);
        if((cur->lchild==NULL&&cur->rchild==NULL)||
			(pre!=NULL&&(pre==cur->lchild||pre==cur->rchild)))
        {//如果当前结点没有孩子结点或者孩子节点都已被访问过 
			Visit(cur->TItem); 
			Pop(S,cur);
            pre=cur; 
        }
        else//将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问
        {
            if(cur->rchild!=NULL)
               Push(S,cur->rchild);
            if(cur->lchild!=NULL)    
               Push(S,cur->lchild);
        }
    } 
	return 0;
}

int main()
{
	Bitree T;
	InitBitree(T);
	CreateBitree(T);
	cout<<"先序遍历:";
	PreOrederTraverse(T,Visit);
	cout<<endl;
	cout<<"中序遍历:";
	InOrderTraverse(T,Visit);
	cout<<endl;
	cout<<"后序遍历:";
	PostOrderTraverse(T,Visit);
	cout<<endl;
	return 0;
}


你可能感兴趣的:(二叉树的非递归(先序、中序、后序)遍历)