二叉树的遍历(先序/中序/后序,递归/迭代)与搜索

遍历一个数据结构,也即逐一地处理(可读可写)其中所有元素。

  • 二叉树的遍历:一棵二叉树可以看作一个状态空间:根节点(入口)对应状态空间的初始状态,父子结点连接对应状态的邻接关系。以这种观点,一次二叉树的遍历就是一次覆盖整个状态空间的搜索

1. 深度优先与广度优先

按深度优先的方式遍历一棵二叉树,需要做三件事(可能需要处理其中的数据):

  • 遍历左子树(L);
  • 遍历根节点(D);
  • 遍历右子树(R);

全排列的话,A33=6,但这里一般假定先处理左子树,后处理右子树,这样,根据根节点遍历的先后顺序,仅可得到三种遍历方式(先中后说的都是根节点的遍历相对顺序)。

由于二叉树的子树也是二叉树,将一种具体的遍历顺序(先中后)方式继续运用到子树的遍历中,就形成了一种二叉树的统一方法。

宽度优先(层次遍历)是按路径长度(自己到自己,路径长度为 0)由近到远地访问节点。对二叉树做这种遍历,也就是按二叉树的层次逐层访问树中各结点。与状态空间搜索的情况一样,这种遍历不能写成一个递归的过程

在宽度优先遍历中规定了逐层访问,并未规定同一层结点的访问顺序。但从算法的角度,必须规定一个顺序,常见的是在每一层里都从左到右逐个访问(从右到左,也是需要使用一个队列,只不过进队的顺序是从右子节点,左子节点)。实现这一算法需要一个队列作为缓存。

2. 二叉树的遍历:递归实现

  • 先序:

    template<typename T, typename VST>
    void travPreorder_R(BinNode<T>* x, VST& visit){
    if (!x) return;
    visit(x->data);
    if (HasLChild(x))
    travPreorder_R(x->lChid, visit);
    if (HasRChild(x))
    travPreorder_R(x->rChild, visit);
    }
  • 中序:

    template<typename T, typename VST>
    void travInorder_R(BinNode<T>* x, VST& visit){
        if (!x) return;
        if (HasLChild(x))
            travPreorder_R(x->lChid, visit);
        visit(x->data);
        if (HasRChild(x))
            travPreorder_R(x->rChild, visit);
    }
    
  • 后序:

    template<typename T, typename VST>
    void travInorder_R(BinNode<T>* x, VST& visit){
        if (!x) return;
        if (HasLChild(x))
            travPreorder_R(x->lChid, visit);
        if (HasRChild(x))
            travPreorder_R(x->rChild, visit);
        visit(x->data);
    }

3. 二叉树的遍历 —— 迭代实现

  • 先序,思路,先一路向左(同时把右子树保存在栈里),再把栈中的右子树出栈,

    // 辅助函数
    template <typename T, typename VST>
    void visitAlongLeftBranch(BinNode<T>* x, VST& visit, Stack<BinNode<T>*> S){
            while (x){
                visit(x->data);
                S.push(x->rChild);
                x = x->lChild;
            }
    }
    
    template <typename T, typename VST>
    void travPreorder_I1(BinNode<T>* x, VST& visit){
        Stack<BinNode<T>*> S;
        while (true){
            visitAlongLeftBranch(x, visit, S);
            if (S.empty())
                break;
            x = S.pop();
        }
    }
  • 后序,思考的起点依然是,首先访问的结点是哪一个?(HLVFL,Highest Leaf Visual From Left)

    template <typename T>
    void gotoHLVFL(Stack<BinNode<T>*> S){
        while (BinNode<T>* x = S.top()){     // 循环退出时,一定是 x 为 NULL 了,也即 S.top() 栈顶元素为空
    
            if (HasLChild(x)){
                if (HasRChild(x)){
                    S.push(x->rChild);
                }
                S.push(x->lChild);
            } else {
                S.push(x->rChild);
            }
        }
        S.pop();         // 弹出栈顶的空元素;
    }
    
    template <typename T, typename VST>
    void travPostorder_I(BinNode<T>* x, VST& visit){
        Stack<BinNode<T>*> S;
        if (x) S.push(x);
        while (!S.empty()){
            if (S.top() != x.parent){
                gotoHLVFL(S);
            }
            x = S.pop();
            visit(x->data);
        }
    }
原文地址:https://www.cnblogs.com/mtcnn/p/9424165.html