您的位置:首页 > 其它

二叉树新建、前序、中序、后序遍历非递归写法

2015-07-01 22:10 387 查看
/************************************************************************/
/* 包括内容:
	1、二叉树的建立
	2、二叉树的遍历(先序、中序和后序的递归、非递归遍历)
	3、二叉树的层次遍历
	4、二叉树的深度
	5、二叉树的重建
	*/
/************************************************************************/

#include <iostream>
#include <stack>

using namespace std;
struct TreeNode 
{
	int  val;
	TreeNode *lchild,*rchild;
	TreeNode(int x):val(x),lchild(NULL),rchild(NULL){};
};
//递归方式,为了建成树后的访问,使用引用
void treeCreate(TreeNode * &T)
{
	char ch;
	cin>>ch;
	// # 表示此节点为空
	if (ch=='#')
	{
		T=NULL;
	}
	else{
		int i=ch-'0';
		T=new TreeNode(i);
		treeCreate(T->lchild);//利用lchild和rchild将树连接起来
		treeCreate(T->rchild);
	}
}

// 非递归方式,则要用到栈,但问题是什么时候进栈,什么时候出战???
//所以如果是用()方式输入,这样当遇到左括号的时候入栈,右括号出战,逗号表示是右子树
void treeCreateNoneR(TreeNode * &T)
{
	char ch;
	int lev=0;//记录左右子树存在情况	
	stack<TreeNode *> sta;
	T=NULL;//将T先置为空,指向新产生的根指针,整棵树才能建立起来
	TreeNode *t;
	while (cin>>ch)
	{
		if(ch=='#') continue;
		else if (ch=='(')
		{
		sta.push(t);
		lev=1;//存在左子树
		continue;

		}
		else if (ch==')')
		{
			sta.pop();
			continue;
		}
		else if (ch==',')//存在右子树
		{
			lev=2;
			continue;
		}
		 
		int i=ch-'0';
		t=new TreeNode(i);
		if (T==NULL)//这里将树的根联系起来
		{
			T=t;
		}
		else {
			if(lev==1&&!sta.empty())
			{
				TreeNode *p=sta.top();
				p->lchild=t;

			}
			else if(!sta.empty())
			{
				TreeNode *p=sta.top();
				p->rchild=t;

			}
			}
		}

}

//先序遍历递归
void PreorderTraverse(TreeNode *root)
{
	TreeNode *t=root;
	if (t)
	{
		cout<<t->val;
		PreorderTraverse(t->lchild);
		PreorderTraverse(t->rchild);
	}
}
//非递归先序遍历,先访问根,再依次访问左右子树
void  PreorderTraverseNoneR(TreeNode *root)
{
	TreeNode *t=root;
	stack<TreeNode *>sta;
	sta.push(t);
	while (!sta.empty())//栈非空的情况下循环
	{
		t=sta.top();//每次访问的是栈顶元素
		cout<<t->val;
		if (t->lchild && t->rchild)//左右子树均存在,那么右子树先入栈,左子树先入栈先访问
		{
			sta.pop();
			sta.push(t->rchild);
			sta.push(t->lchild);			

		}
		else if(t->lchild)//只有左子树,则左子树入栈
		{
			sta.pop();
		   sta.push(t->lchild);

		}
		else if (t->rchild)
		{
			sta.pop();
			sta.push(t->rchild);
			 
		}
		else sta.pop();//叶子节点,则父节点也要出栈
		
	}

} a

//中序遍历
 void InorderTraverse(TreeNode* root)
 {
	 TreeNode *t=root;
	 if (t)
	 {
		 InorderTraverse(t->lchild);//先遍历左子树
		 cout<<t->val;//访问根节点
		 InorderTraverse(t->rchild);//再遍历右子树
	 } 

 }
//非递归仍然借用栈来做,但是注意最先输出的是最最左子树节点
void InorderTraverseNoR(TreeNode *root)
{
	TreeNode *t=root;
	stack<TreeNode*>sta;
	sta.push(t);
	while(!sta.empty())
	{
		t=sta.top();
		//根节点的左子树被访问后,top又为根节点的时候,会再次被访问,如何解决?
		//栈需要pop,但是可能又pop多了,所以干脆让NULL也入栈
		while (t && !sta.empty() )
		{
			 
				t=t->lchild;
				sta.push(t);			 
	
		}
		sta.pop();
		 
		if (!sta.empty())//进行访问
		{
			t=sta.top();
			sta.pop();
			cout<<t->val;
			 
			sta.push(t->rchild);//右子树入栈
		}

		
	}
}

//后序非递归遍历,先左子树,后右子树,再根节点。
void PostOrderTraverse(TreeNode *root)
{
	TreeNode *t=root;
	if (t)
	{
		PostOrderTraverse(t->lchild);
		PostOrderTraverse(t->rchild);
		cout<<t->val;
	}
}

/************************************************************************/
/* 后序遍历的难点在于:需要判断上次访问的节点是位于左子树,还是右子树。*/
/*若是位于左子树,则需跳过根节点,先进入右子树,再回头访问根节点;
若是位于右子树,则直接访问根节点。 */                                                                    
/************************************************************************/
void PostOrderTraverseNoR(TreeNode *root)
{
	TreeNode *t=root;
	TreeNode *lastVisit=NULL;
	stack<TreeNode*> sta;
	sta.push(t);
	//移到左子树
    while (t)
    {
		sta.push(t);
		t=t->lchild;
    }//循环结束,t已经为空,且已经便利到左子树底端
	while (!sta.empty())
	{
		t=sta.top();
		sta.pop();
		//根节点可以被访问的前提是没有右子树,或者右子树已经被访问
		if(t->rchild==NULL || t->rchild==lastVisit)
		{
		  cout<<t->val;
		  //修改最近被访问的节点
		  lastVisit=t;
		}
		else{
			//根节点再次入栈
			sta.push(t);
			//进入右子树,且可肯定右子树一定不为空
			t=t->rchild;
			while (t)
			{
				sta.push(t);
				t=t->lchild;
			}

		}

	}

	 

}

int main()
{
	char ch;
	TreeNode *root;
	root=new TreeNode(-1);

	//treeCreate(root);
	treeCreateNoneR(root);
	PreorderTraverse(root);
	PreorderTraverseNoneR(root);
	cout<<endl<<"In Order"<<"  ";
	InorderTraverse(root);
	cout<<endl<<"In order none Re"<<"  ";
	InorderTraverseNoR(root);
	cout<<"next "<<endl;
	cout<<endl<<"Post order none Re"<<"  ";
	PostOrderTraverse(root);
	PostOrderTraverseNoR(root);

}

最后一部分借鉴:
http://www.2cto.com/kf/201407/314705.html,多谢~
附上结果截图
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: