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

本文详细介绍了二叉树的建立方法,包括递归和非递归方式,并阐述了二叉树的先序、中序和后序遍历,以及层次遍历和深度计算。同时,还涉及了二叉树的重建过程。
/************************************************************************/
/* 包括内容:
	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,多谢~


附上结果截图


实验内容:1、输入二叉树的先列字符,建立二叉链表。注意:输入时,必须加入虚结点以示空指针的位置;假设虚结点输入时用空格字符表示。 2、按先、中后序遍历二叉树 3、求二叉树结点总数,观察输出结果。 4、求二叉树叶子数,观察输出结果。 5、求二叉树的深度(或称高度),观察输出结果。 6、交换二叉树的左右子树 7、在主函数中设计一个简单的菜单,分别调试上述算法。 8、(★)二叉树采用链接存储结构,其根结点指针为T,设计一个算法对这棵二叉树的每个结点赋值:(注意要修改DataType类型) a)叶结点的值为3 b)只有左孩子或右孩子的结点则其值分别等于左孩子或右孩子的值 c)左、右孩子均有的结点,则其值等于左、右孩子结点的值之和 示例代码:#include <stdio.h> #include <stdlib.h> #include "Datahead.h" /*二叉树的链式存储表示*/ typedef char TElemType; /*由用户定义的实际数据类型*/ typedef struct BiTNode { TElemType data; struct BiTNode *lchild, *rchild; /*左右孩子指针*/ } BiTNode, *BiTree; /*结点类型*/ int a; void main() { void CreateBiTree(BiTree *T); /*构造二叉链表*/ Status PrintChar(TElemType e); /*Visit 函数*/ Status PreOrderTraverse(BiTree T,Status(*Visit)(TElemType e)); /*前序遍历二叉树*/ Status InOrderTraverse(BiTree T,Status(*Visit)(TElemType e)); /*中遍历二叉树*/ void Postorder(BiTree T); /*后序遍历二叉树*/ int nodes(BiTree T); /*计算总结点数*/ int leafs(BiTree T); /*计算总叶子数*/ void swap(BiTree T); /*交换左右子树*/ BiTree T; printf("input preorder nodes:(xu jie dian yong kong ge biao shi :\n"); CreateBiTree(&T); if (PreOrderTraverse(T,PrintChar)) printf(":PreOrderTraverse OK \n"); printf("zong de jie dian shu :%d\n",nodes(T)); printf("ye zi jie dian shu :%d\n",leafs(T)); swap(T); printf("jiao huan zuo you zi shu yi hou :\n"); if (PreOrderTraverse(T,PrintChar)) printf(":PreOrderTraverse OK again\n"); getch(); } /*构造二叉链表*/ void CreateBiTree(BiTree *T) /* P131 算法6.4*/ { char ch; scanf("%c",&ch); if(ch==' ') *T=NULL; else { if(!(*T=(BiTNode*)malloc(sizeof(BiTNode))))exit(0); (*T)->data=ch; CreateBiTree(&((*T)->lchild)); CreateBiTree(&((*T)->rchild)); } } Status PrintChar(TElemType e){ /*Visit 函数*/ printf("%c",e); return OK; } /*前序遍历二叉树*/ Status PreOrderTraverse(BiTree T,Status (*Visit)(TElemType e)){ /* P129 算法6.1*/ if(T){ if(Visit(T->data)) if(PreOrderTraverse(T->lchild,Visit)) if(PreOrderTraverse(T->rchild,Visit)) return OK; return ERROR; }else return OK; } /*中遍历二叉树的简单写法 */ void Inorder(BiTree T) { if(T){ Inorder(T->lchild); printf("%c",T->data); Inorder(T->rchild); } } /*后序遍历二叉树*/ void Postorder(BiTree T) { if(T){ /*请补充代码*/ } } /*计算总结点数*/ int nodes(BiTree T) { if(T) return(nodes(T->lchild)+nodes(T->rchild)+1); else return(0); } /*计算总叶子数*/ int leafs(BiTree T) { if(T==NULL)return(0); else{ if(T->lchild==NULL&&T->rchild==NULL)return(1); else return(leafs(T->lchild)+leafs(T->rchild)); } } /*交换左右子树*/ void swap(BiTree T) { BiTree p; if(T){ p=T->lchild; T->lchild=T->rchild; T->rchild=p; swap(T->lchild); swap(T->rchild); } } /*计算二叉树的深度或者称为高度*/ int depth(BiTree T){ int hl,hr,max; if(T){ if (T->lchild==NULL && T->rchild==NULL) return 1; else { hl=depth(T->lchild); hr=depth(T->rchild); max=(hl>hr)?hl:hr; return max+1; } } else return 0; } /*结点赋值 叶结点的值为3 只有左孩子或右孩子的结点则其值分别等于左孩子或右孩子的值 左、右孩子均有的结点,则其值等于左、右孩子结点的值之和 */ int ChangeValue(BiTree T){ if(T){ if (T->lchild==NULL && T->rchild==NULL) T->data=3; /*请补充代码*/ return T->data; } } 根据实验内容,在示例代码上补充代码,最后输出完整代码
06-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值