二叉树遍历 | 递归 & 非递归

中序遍历

一直遍历左子树到空,然后转移到右子树

void inorder(TreeNode *root,vector<int> &path){
    stack<TreeNode*> s;
    TreeNode* p=root;
    while(p||!s.empty()){  //节点不为空时,或者栈不为空的情况下继续执行循环体
        //一直遍历左子树直到底
        while(p!=NULL){
            s.push(p);
            p=p->left;
        }
        //p为空,说明已经到了左子树的最下面,这时需要出栈
        if(!s.empty()){
            p=s.top();
            path.push_back(p->val);
            s.pop();
            //进入右子树,开始新一轮的左子树遍历(递归的自我实现)
            p=p->right;
        }
    }
}

先序遍历

先序遍历和中序遍历差不多,也是需要借助根节点访问右子树,只不过和中序遍历的区别在于在根节点被压栈时就输出它的值,而不是在出栈的时候再访问

void preOrder(TreeNode* root,vector<int> &path){
    if(root==NULL) return;
    stack<TreeNode*> s;
    TreeNode* p=root;
    while(!s.empty()||p!=NULL){
        while(p){
            path.push_back(p->val);
            s.push(p);
            p=p->left;
        }
        if(!s.empty()){
            TreeNode* temp=s.top();
            s.pop();
            p=temp->right;
        }
    }
}

后序遍历

需要判断上次访问的是位于左子树还是右子树。若位于左子树,则要跳过根节点,先进入右子树,再访问根节点;若是位于右子树,则直接访问根节点。

需要保存当前访问节点和上次访问节点

后序遍历访问的一直都是从栈中弹出的元素

  1. 使用栈来实现,并设置两个指针,分别指向当前访问的节点和上次访问的节点
  2. 初始化时将当前访问的节点指向最左下的节点,上次访问的节点为NULL
  3. 取栈顶元素为当前访问节点,如果此节点没有右孩子或者是右孩子为上次访问节点,那么输出此节点信息,并将此节点赋值给上次访问节点,继续从栈中取元素
  4. 如果右孩子不是上面说的那种情况的话,将当前访问节点(也就是原来的栈顶元素)再次压入栈中,然后访问右子树,将右子树的左节点左节点持续压入栈中,继续循环第3步
void postOrder(TreeNode* root,vector<int> &path){
    if(root==NULL) return;
    stack<TreeNode*> s;
    //当前访问节点,上次访问节点
    TreeNode *pCur,*pLastVisit;
    pCur=root;
    pListVisit=NULL;
    //从左子树的最下边开始访问
    while(pCur){
        s.push(pCur);
        pCur=pCur->left;
    }
    while(!s.empty()){
        //走到这里时,已经遍历到二叉树的最低端
        pCur=s.top();
        s.pop();
        //如果没有右子树或者右子树已经被访问,那么访问这个根节点
        if(pCur->right==NULL||pCur->right==pLastVisit){
            path.push_back(pCur->val);
            //修改为最近被访问的节点
            //只有输出结果的时候才会修改上次访问节点
            pLastVisit=pCur;
        }
        else{
            //将根节点再次入栈
            s.push(pCur);
            //访问右子树,进入右子树
            pCur=pCur->right;
            while(pCur){
                s.push(pCur);
                pCur=pCur->left;
            }
        }
    }
}

层序遍历

层序遍历用非递归的方法更容易实现些,使用队列保存节点,然后逐层遍历即可

用递归实现的方法并不常用,首先要知道树的深度,逐层输出(这里的递归的作用似乎就只是到达了对应的层)

void level(TreeNode* root,int i,vector<int>& path){
    if(root==NULL||i==0) return;
    if(i==1){
        path.push_back(root->val);
    }
    level(root->left,i-1,path);
    level(root->right,i-1,path);
}

int getDepth(TreeNode *root,int depth){
    if(root==NULL)
        return depth;
    else{
        int l=getDepth(root->left,depth+1);
        int r=getDepth(root->right,depth+1);
        return max(l,r);
    }
}

void levelOrder(TreeNode* root,vector<int>& path){
    if(root==NULL) return;
    int dep=getDepth(root);
    for(int i=1;i<=dep;i++){
        level(root,i,path);
    }
}

 

测试代码

int main(){
    TreeNode* one=new TreeNode();
    one->val=1;
    TreeNode* two=new TreeNode();
    two->val=2;
    TreeNode* three=new TreeNode();
    three->val=3;
    TreeNode* four=new TreeNode();
    four->val=4;
    one->right=two;
    one->left=three;
    three->left=four;
    
    vector<int> path;
//    levelOrder(one,path);
//    inorder(one,path);
//    preOrder(one,path);
    postOrder(one,path);
    for(int i=0;i<path.size();i++){
        cout<<path[i]<<" ";
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值