二叉树先序中序后序深度思考及非递归算法程序实现

1.先序遍历(根左右),中序遍历(左根右)和后序遍历(左右根)都可以用递归实现,类似于DFS,左子树都在右子树之前遍历,不同的是根的遍历顺序。层序遍历则类似于BFS。
2.中序序列与先序序列、后序序列、层序序列中的任一个结合都能重构二叉树,但是没有中序,两外的任意两个或三个组合都不能重构二叉树,因为只有靠中序才能区分出左右子树,而其他三种都只是提供根节点的。
3.二叉树的先序中序后序遍历。遍历过程中经过节点的路线都一样,只是访问各节点的时机不同。先序是在第一次将节点入栈前访问,中序则是在节点出栈时访问。
后序遍历非递归(比较重要):在出栈一个节点后,要先判断这个结点的左右孩子节点是否都出栈,若都已出栈,才能让这个节点出栈。从下面的算法中可以看到,要想访问该节点,必须将该结点的所有祖先节点都压入栈中后,才能访问该节点。
也就是说访问一个节点p时,栈中节点恰好是p结点的所有祖先,从栈底到栈顶再加上p节点,正好是从根节点到p结点的一条路径。很多算法都会利用到上述特性:如求根节点到某节点的路径,求两个节点的最近公共祖先、输出根结点到所有叶子结点的路径等。
4.二叉树的先序中序非递归算法
将二叉树根节点的所有左节点一一进栈,然后出栈一个结点*p,*p没有左孩子节点或者左孩子节点已经访问过了,访问该节点。然后将该结点的右孩子节点入栈,再重复上述操作,直到栈空为止。

void inorder2(node* root){
	stack<node*> s;//入栈的是结点的地址
	node* p=root;
	//在遍历的过程中,出栈入栈可能导致栈空,但此时遍历并未结束所以这里采用双重判断 
	while(p || !s.empty()  ){//当树不空或者栈不空时循环 
		while(p){
//printf(“%d ”,p->data);  访问操作在这里,就是先序遍历非递归。
			s.push(p);//将根节点及所有的左孩子节点入栈,第一次遇到节点
			p=p->lchild ;
		}
		if(!s.empty()){//栈不空时出栈一个节点 
			p=s.top() ;
s.pop() ;//出栈一个节点,该节点没有左孩子节点或者左孩子节点均已经访问过了
			//这里可以访问,或者做其他操作,是中序遍历非递归
			printf("%d ",p->data ); 
			//
			p=p->rchild ;//将该出栈结点的右孩子入栈  
		} 	   
	} 	
}
二叉树的后序遍历非递归算法:
//当用堆栈存储节点时,必须分清返回根节点时,是从左子树返回的还是右子树返回的,所以设置一个辅助指针r,r指向最近访问过的节点。  
void postorder2(node* root){
	stack<node*> s;//入栈的是结点的地址 
	node* p=root;
	node* r=NULL; //辅助指针r,指向最近访问过的节点 
	while(p || !s.empty()){
		while(p){
			s.push(p);
			s=s->lchild;
		}
		if(!s.empty()){
			p=s.top();//取栈顶元素地址赋给p 
			s.pop();//弹出栈顶节点
			if(p->rchild==r || p->rchild ==NULL ){//右孩子已经访问或者右孩子不存在,访问节点
			 printf("%d ",p->data ); 
			 r=p;//r指向被访问节点
			 p=NULL;//节点置空,该节点的左右孩子节点均已经被访问	
			}else{//否则,右孩子节点并未入栈,就不能访问 
				s.push(p);//否则,将弹出该的节点重新压入栈 
				p=p->rchild ;//继续遍历右子树 
			} 		 
		}	
	}	
}

5.将层序遍历中的队列改为堆栈的话会怎样?
如果将其改为堆栈,并且入栈顺序改为先入右子节点再入左子节点,那么其顺序与先序遍历一样。
对于二叉树的操作,很多都关于遍历,要分别遍历左节点,右节点,在遍历左节点时,右节点怎么办呢,则需要数据结构来存储,栈 或者队列都行。而且先访问右节点还是左节点,顺序不同,要实现的功能也就不同。
6.树和图的区别
1.线性表可以是空表,树可以是空树,但图不可以是空图,图中至少有一个顶点,可以没有边。
2.树是图的子集,可以算是一种特殊的图,树存在一对多的关系,图一对多和多对多都可以。
3.树有一个根节点,但是图没有。树除根节点外每个节点只有一个前驱,而图没有这种关系。树没有环,图可以有环。树n个顶点一定有n-1条边,但是图顶点和边之间没有确定关系。图有不连通的情况,树一定连通
4.树有明显的层次性,图呈现的是网络性,更复杂的关系。
7.树的遍历和图的遍历区别
遍历就是把节点按照一定规则构成线性序列,不同规则构成不同顺序的序列而已。
1.树的遍历不需要设置vis数组来标记是否访问过。因为不管是先序(根左右)中序(左根右)后序(左右根),树节点之间有明确的父亲孩子关系,都一定只会遍历一次。而图各节点之间都只有相邻关系,所以图的遍历都需要vis数组来标记节点是否访问过。
2.树的遍历一般以根节点开始,图的遍历可以任选节点。图有不连通的情况,树没有。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值