中序遍历

 中序遍历是十分重要的遍历算法。针对BST而言,中序遍历给定了一个次序,将二叉树变成了一种线性结构,而且正好是升序排列(在BST中,语义规范不存在关键值相同的节点)。
  • 仿照先序遍历的递归版
template<typename T,typename VST>void travIn_R(BinNodePosi(T) x,VST& visit){
    if(!x) return;
    travIn_R(x-lc,visit);
    visit(x->data);
    travIn_R(x-rc,visit);
}
将递归版算法改写为迭代版,右子树遍历属于尾递归,但是左子树却严格不是。
考察中序遍历二叉树的左侧通路,不难发现一个规律,遇到的左侧节点总不是最先访问的,而是会检查有没有右子树,如果有转向右子树,直到当前节点没有右兄弟,才访问该节点。则依照此思路,从根节点沿左侧通路一趟下行,沿右子树逐一遍历。这样,原问题就分解若干个右子树遍历的问题。
template<typename T,typename VST>void travIn_R(BinNodePosi(T) x,VST& visit){
    Stack<BinNodePosi(T)> S;
    while(true){
        goAlongLeftBranch(x,S);
        if(S.empty()) break;
        x = S.pop(); visit(x-data);
        x = x->rc;
    }
}
template<typename T,typename vst>void  goAlongLeftBranch(BinNodePosi(T) *x,Stack<BinNodePosi(T)&> S){
    while(x){S.push(x);x=x->lc}
}

同理,可以借助辅助栈,重写上述算法。

template<typename T,typename VST>void travIn_R2(BinNodePosi(T) x,VST& visit){
    Stack<BinNodePosi(T)> S;
    while(true){
        if(x) S.push(x);
        x = x->lc;
        else if(!S.empty()){
            x = S.pop();
            visit(x->data);
            x = x->rc;
        }
        else break;
    }
}
  • 直接后继
中序遍历与其他遍历策略一样,将二叉树定义了一个次序的关系,则可以通过succ()接口来查找某个节点的直接后继
template<typename T>BinNodePosi(T) BinNode<T>::succ(){
    BinNodePosi(T) x = this;
    if(rc){
        x = rc;
        if(HasLChild(*x)) x = x-lc;
    }
    else{
        while(IsRChild(*x)){
            x = x->parent;
        }
        x = x->parent; 
    }
    return x;
}
再有了直接后继之后,可以不再使用辅助栈来实现中序遍历。
template<typename T,typename VST>void travIn_R3(BinNodePosi(T) x,VST& visit){
    bool backtrack = false;
    while(true){
        if(HasLChild(*x) && !backtrack){//如果有左孩子,而且没有回溯,深入左子树。
            x = x-lc;
        }
        else{//刚刚发生回溯或无左子树。访问
            visit(x->data);
            if(HasRChild(*x)){//如果有右子树,按照一开始给定的策略,遍历右子树。
                x = x->rc;
                backtrack = false;
            }
        }
        else{//如果右子树为空,遇到了最左侧的叶节点,回溯。
            if(!x=x->succ()) break;
            backtrack = true;//开启回溯标识。
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值