二叉树遍历

二叉树遍历

递归遍历

前序

void preOrder(BTree root){
    if(root == NULL)
        return ;
    visit(root);
    preOrder(root->left);
    preOrder(root->right);
}

后序

void postOrder(BTree root){
    if(root == NULL){
        return ;
    }
    postOrder(root->left);
    postOrder(root->right);
    visit(root);
}

中序

void inOrder(BTree root){
    if(root == NULL)
        return ;
    inOrder(root->left);
    visit(root);
    inOrder(root->right);
}

非递归遍历

前序

借助栈来实现,注意左右孩子的入栈顺序

先右孩子,再左孩子,这样出栈的时候就是先左再右

void preOrder(BTree root){
    BTree stack[MaxSize];
    int top = -1;
    BTree p = NULL;
    
    if(root)	//根节点不为空 将其入栈
        stack[++top] = root;
    
    while(top != -1){
    	p = stack[top--];	//弹出栈顶节点并访问
        visit(p);
        
        if(p->right)	//先右孩子
	    stack[++top] = p->right;            
        
        if(p->left)		//再左孩子
            stack[++top] = p->left;
    }
}

后序

版本一

在非递归先序遍历的基础上实现

先序:根左右

后序:左右根

逆后序:根右左

可以得知,逆后序和先序遍历序列仅仅是左右顺序不同

而在先序遍历算法中,左右的顺序取决于将左右孩子入栈的顺序,因此调换先序遍历算法中左右孩子入栈顺序,即先左孩子入栈,再右孩子入栈即可得逆后序遍历序列,再将逆后序遍历序列反转即可得后序。

void postOrder(BTree root){
    BTree s1[MaxSize];	//栈1用来得逆后序
    int top1 = -1;
    
    BTree s2[MaxSize];	//栈2用来反转逆后序
    int top2 = -1;
  	
    BTree p = NULL;
    
    if(root)
        s1[++top1] = root;
    while(top1 != -1){
        p = s1[top1--];
        s2[++top2] = p;
        if(p->left){
            s1[++top1] = p->left;
        }
        
        if(p->right){
            s1[++top1] = p->right;
        }
    }//遍历完成s2中存放即为后序遍历序列
    
    while(top2 != -1){
        visit(s2[top2--]);
    }
    
}

版本二

借助栈和尾指针模拟后序遍历流程,先左再根再右

  • 从根节点开始,沿左孩子依次入栈,直到左孩子为空

  • 取栈顶节点p

  • 根据p右孩子的情况进行处理

    • p没有右孩子

      弹出并访问p

    • p有右孩子

      • 右孩子已被访问过

        弹出并访问p

      • 右孩子未被访问过

        转去右孩子执行

void postOrder(BTree root){
    BTree stack[MaxSize];
    int top = -1;
    BTree p = root;		//当前指针p 初始为根节点
    BTree r = NULL;		//尾指针r 初始为空
    
    while(p || top != -1){
        if(p){
            stack[++top] = p;
            p = p->left;
        }
        else{
            p = stack[top];	//读栈顶节点p
            if(p->right && r->right != r){	//判断是否要转去右孩子执行
                p = p->right;
            }
            else{
                visit(p);        //此时栈中记录的即为从根结点到p的路径
                top--;		//弹出栈顶节点并访问
                r = p;		//r记录上一次访问过的节点
                p = NULL;	//每次访问完p都要置空
            }
        }
    }
}

后序遍历版本二算法可以应用在求从根节点到树中某个节点的路径

当访问到某个节点时,当前栈中存放的节点即为从根节点到该节点的路径

中序

生疏,重点理解记忆

void inOrder(BTree root){
    BTree stack[MaxSize];
    int top = -1;
    BTree p = root;
    
    while(p || top != -1){
        if(p){	//这段逻辑和后序相同,一直往左走
            stack[++top] = p;
            p = p->left;
        }
        else{	//左边走到头不需要再判断右孩子,直接访问然后转去右子树即可
            visit(stack[top]);
            p = stack[top]->right;
            top--;
        }
    }
}

层序

void levelOrder(BTree root){
    BTree que[MaxSize];
    int front = 0, rear = 0;
    BTree p = NULL;
    
    if(root){
        que[rear++] = root;
    }
    
    while(front != rear){
	p = que[front++];
        visit(p);
        if(p->left){
            que[rear++] = p->left;
        }
        if(p->right){
            que[rear++] = p->right;
        }
    }
}

在此框架的基础上,相关的应用有:求二叉树的层数、求每一层节点数、求每一层节点关键字平均值......

以上应用需要在遍历的过程中区分二叉树的层次

思路:增设一个指向当前层最后一个节点的指针q,当遍历到q时就进行相关分层处理。

如何维护指针q?

初始q=root,每遍历一个节点p时,判断并将p的左右节点入队之后,检查p是否等于q,若p=q,则当前队列尾节点即为下一层最后一个节点,更新q=que[rear-1],即当访问到当前层最后一个节点时,将q指向下一层最后一个节点。

void levelOrder(BTree root){
    BTree que[MaxSize];
    int front = 0, rear = 0;
    BTree p = NULL, q = root; //q指向当前层最后一个节点,初始为root
    
    if(root){
        que[rear++] = root;
    }
    
    int level = 0;	//当前层数
    int cnt = 0;	//当前层内节点数
    
    while(front != rear){
        p = que[front++];
        visit(p);
        if(p->left){
            que[rear++] = p->left;
        }
        if(p->right){
            que[rear++] = p->right;
        }
        
        //分层操作
        if(p == q){
            q = que[rear - 1];	//更新q,指向下一层最后一个节点,即此时的队尾节点
            //其他需要的操作...
            level++;
            cnt = 0;
        }
    }
}
posted @ 2023-01-04 16:02  dctwan  阅读(18)  评论(0编辑  收藏  举报