二叉树遍历算法包含: 前序, 中序, 后序, 层次遍历 共四种算法。
先序遍历 DLR: 先访问根节点,然后访问左子树, 最后访问右子树
中序遍历LDR: 先访问左子树,然后根节点,最后访问右子树
后序遍历LRD: 先访问左子树,然后访问右子树,最后根节点
层次遍历: 从每层开始,至左向右逐层访问
先序、中序,后序都可以使用递归方式进行访问,非递归方式使用栈辅助, 层次遍历使用队列作为辅助结构
1. 先序非递归遍历算法:
每次递归深入的时候,就是将左右孩子节点压栈的过程,在压栈之前,访问该节点;
每个节点只有在访问完右子树,或者右子树为空时,出栈,为了标志每个节点的右孩子节点是否压栈,可以使用一个标志位flag,将节点的右孩子节点压入栈中,需要改变flag,这样每次访问栈顶元素时,如果判断右子树已访问,直接出栈;
详细算法如下:
最开始根节点入栈
while(栈非空){
1. 获取栈顶元素cur;
2. 判断该节点的flag, 如果flag为true,说明该节点右子树已经访问,出栈, 否则 访问该节点cur;
3. 如果cur有左孩子节点,压入栈中,进入step 1;
否则,如果有右孩子节点(只有右子树),压入栈中,同时修改cur的标志位flag为true;如果cur为叶子节点,直接出栈,进入step1
}
void preOrder(BitNode *t){
if(!t) return;
Stack<BitNode*> s;
s.push(t);
BitNode *cur=NULL;
while( !s.empty() ){
cur= s.top();
if(cur.flag){
//右子树已经访问,出栈
s.pop();
}else{
visit(cur); //访问该节点
if(cur->lchild){
s.push(cur->lchild);//访问左子树
}else{
if(cur->rchild){//访问右子树
s.push(cur->rchild);
cur->flag= true;
}else{
//叶子节点
s.pop();
}
}
}
}
}
2. 中序遍历非递归算法:
与先序遍历类似,只是访问完左子树后访问根节点,访问完根节点,出栈,最后访问完右子树,为了标志每个节点的左子树是否访问,使用标志位flag
详细算法如下:
最开始根节点入栈
while(栈非空){
1. 获取栈顶元素cur;
2. 如果cur节点标志位为flag为false, 且该节点有左子树,将左子树压入栈中,同时置该节点标志位flag为true;否则访问该节点,并出栈,如果该节点有右子树,将右孩子压入栈中
}
void inOrder(BitNode *t){
if(!t) return;
Stack<BitNode*> s;
s.push(t);
BitNode* cur=NULL;
while( !s.empty() ){
cur = s.top();
if(cur->flag){
visit(cur);
s.pop();
if(cur->rchild){
s.push(cur->rchild);
}
}
}//while
}
}
3. 后序遍历二叉树非递归算法:
先访问左右子树,最后访问根节点,同样的,如果该节点的左右子树都已访问,直接出栈,否则更新节点的访问左右子树状态,如果状态为右子树已经访问,直接出栈
详细算法如下:
最开始根节点入栈
while(栈非空){
1. 获取栈顶元素cur;
2. 如果cur节点标志位为flag为2, 右子树已经访问完,访问该节点出栈, 否则,
如果flag==1, 表明该节点左子树已经访问,开始访问右子树,如果该节点无右子树,访问该节点后直接出栈 否则,将右孩子压入栈中,同时置该节点标志位flag为2
如果flag==0,表明该节点左右子树均未访问, 先访问左子树,如果该节点有左子树,将左子树压入栈中,同时置该节点标志位flag为1,表明左子树已经访问完, 否则判断如果该节点有右子树,将右孩子压入栈中,同时置该节点标志位flag为2,否则该节点为叶子节点,访问该节点后直接出栈
}
void postOrder(BitNode *t){
if(!t) return;
Stack<BitNode*> s;
s.push(t);
BitNode* cur=NULL;
while( !s.empty() ){
cur = s.top();
if(cur->flag==2){
visit(cur);
s.pop();
}else if(cur-> flag==0 ){
if(cur->lchild){
s.push(cur->lchild);
cur->flag =1;
}else{
if(cur->rchild){
s.push(cur->rchild);
cur->flag=2;
}else{
//叶子节点
visit(cur);
s.pop();
}
}
}
}//while
}
4.层次遍历算法:
使用队列FIFO的特性,至左向右依次将根节点的孩子节点压入队列中