【二叉树遍历算法】——前/中/后序递归与非递归的实现

昨天面试了美团,面试官要求写出二叉树的中序遍历,要求实现递归与非递归方式。在写非递归的时候,一个while循环中忘记控制空指针,╮(╯▽╰)╭当时脑子一片空白不在状态。回来后告诉自己,这类问题以后绝不会发生!下述6种实现方法希望大家都能理解,并快速能手写代码出来。(理解,懂得思路才是王道,因为面试的时候人的情绪相对来说是比较紧张,需要掌握得更熟悉)

先(前)序递归遍历

void preorderTraverse(BiTree T){
	if(T){
		visit(T);
		preorderTraverse(T->lChild);
		preorderTraverse(T->rChild);
	}
}

中序递归遍历

void inOrderTraverse(BiTree T){
	if(T){
		inOrderTreverse(T->lChild);
		visit(T);
		inOrderTreverse(T->rChild);
	}
}

后序递归遍历

void lastorderTraverse(BiTree T){
	if(T){
		preorderTraverse(T->lChild);
		preorderTraverse(T->rChild);
		visit(T);
	}
}


先(前)序非递归遍历

void preorderTraverse(BiTree T){
	InitStack(S);
	Push(S,T);
	while(!StackEmpty(S)){
		while(GetTop(S,p) && p){
			//先打印再添加左子树
			visit(p);
			Push(S,p->lChild);
		}
		//弹出空指针
		Pop(S,p);
		//向右走一步
		if(!StackEmpty(S)){
			Pop(S,p);
			Push(S,p->rChild);
		}		
	}
}


中序非递归遍历

void inOrderTraverse(BiTree 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);
			visit(p);
			Push(S,p->rChild);
		}	
	}
}

后序非递归遍历

typedef struct{ 
	Node *p;      //二叉树结点
	int isVisited;  //1表示所指的有结点被访问过
}SNode

非递归后序
void lastorderTraverse(BiTree T){
	InitStack(S);	
	p = T;
	//一直往左边走
	while(p){ 
		Push(S,p,0);  p = p ->lchild;  //表示把当前根节点push进栈,同时isVisited值为0
	}
	while(!StackEmpty(S)){
		GetTop(S,sNode);
		
		//如果右子树已经访问过或者没有右子树
		if(!sNOde->p->rchild || sNode.isVisited == 1){
			Pop(S,p);
			visit(p);
		}else{
			//此时应该从右子树开始一直往左下方走到尽头
			sNode.isVisited = 1;
			p = sNode->rChild;
			while(p){
				Push(S,p,0);
				p = p->lChild;
			}			
		}		
	}
}

下面是我的理解和记住实现的几个技巧:

  • 递归实现中,先(前)/中/后序的visit函数的调用在两句递归调用语句的前/中/后位置。
  • 非递归实现中,先(前)和中序都是通过先把根压进栈,然后一直向左走走到尽头,弹出空指针后向右走一步,循环操作,不同在于:先(前)序遍历打印的时候是在添加左子树之前(因为根要先打印嘛),而中序是在添加右子树之前(因为根要比右子树先打印)。
  • 非递归实现中,打印的条件为当前没有右子树或者右子树已经访问过;需要借助一个结构体来记录右子树是否被访问过;同样需要先把根压栈再向左走到尽头;假设有一棵树(ABC),A为根,B为左子树,C为右子树,那么利用打印条件和压栈顺序,A其实不可能优先于BC打印的,而怎么控制B先于C打印呢?就是在每次不满足打印条件的时候,就拿到其右子树后一直往左下方走,把结点都push进栈就可以。



你可能感兴趣的:(算法积累,数据结构,二叉树,遍历,递归,非递归)