zoukankan      html  css  js  c++  java
  • 二叉树的遍历

    二叉树是每个节点最多有两个子树的树结构,遍历方法有深度优先(包括:先序、中序、后序遍历)和宽度优先(层序遍历),层序遍历通过队列可以实现。

    这里主要介绍深度优先遍历的方法以及其中栈的应用,帮助理解二叉树的结构、递归和非递归中栈的应用。

    中序遍历:左子树---> 根结点 ---> 右子树(先访问左子树,再访问根节点,后访问右子树,而对于每个子树来说,又按照同样的访问顺序进行遍历)

    先序遍历:根结点 ---> 左子树 ---> 右子树

    后序遍历:左子树 ---> 右子树 ---> 根结点

    根据三种遍历的特性,递归的算法很容易就能写出来

    //先序
    void PreOrder(node *root)
    {
        if (root==NULL) return;
        else {
            printf("%d", root->data);
            PreOrder(root->lch);
            PreOrder(root->rch); 
        }
    }
    //中序
    void InOrder(node *root)
    {
        if (root==NULL) return;
        else {
            InOrder(root->lch);
            printf("%d", root->data);
            InOrder(root->rch); 
        }
    }
    //后序
    void PostOrder(node *root)
    {
        if (root==NULL) return;
        else {
            PostOrder(root->lch);
            PostOrder(root->rch);
            printf("%d", root->data); 
        }
    }

    二叉树遍历的核心问题:二维结构的线性化

      >从结点访问其左,右儿子节点

      >访问左儿子后,右儿子节点怎么办?

        #需要一个存储结构保存暂时不访问的结点

        #存储结构:堆栈,队列

    递归的根本的实现方法就是堆栈,我们想有没有可能直接用堆栈实现非递归算法?

    树中各节点的访问路径

     

    以中序遍历为例,一开始碰到A的时候,由于是中序不能直接打印A,必须遍历完左边的子树后,才能打印A,那遍历完后又怎么知道回到这边来呢?这时候采用的方法实际上就是堆栈

    对于栈中的某一元素而言,需要判定其是否满足出栈条件:当回溯至栈中某一点时,要判断是否还需要其的记忆作用

    void  Traversal(BiTree BT)
    { Stack S
    = CreateStack(MaxSize);//创建栈,用于存储节点 BTNode *T = BT; while(T||!isEmpty(S)){ while(T){ //在此访问节点为先序遍历 Push(S, T); T = T->lchild; } if(!isEmpty(S)){ T = pop(S); //在此访问节点为中序遍历 T = T->rchild; } } }

    以上是先序遍历和中序遍历的模板,如果在压栈的时候访问节点,这时是第一次遇到该节点,则为先序遍历。如果在弹栈的时候访问节点,此时之前已经将节点入栈,所以这是第二次遇到该节点,则是中序遍历。

    老师在课上讲的关于访问树的路径是每个节点都要被访问三次,第一次、第二次、第三次遇到节点的时候访问则为先序、中序、后序遍历。

    第一次、第二次、第三次遇到该节点分别是:

    第一次:该节点被作为其父节点的某子树的根节点访问。

    第二次:从该节点的左子树返回该节点

    第三次:从该节点的右子树返回该节点

    如果是后序遍历,则需要在第三次遇到该节点的时候访问该节点。那么就是需要在从该节点的右子树返回时访问该节点。所以实现后序遍历最重要的就是识别当节点从栈中弹出时,刚刚是访问了其左孩子节点,还是访问了右孩子节点。

    如果每次访问节点的时候,都用一个节点指向这个节点,那么下一次要访问节点的时候,就可以知道上一次访问的是它的左孩子节点还是右孩子节点。

    所以当要访问一个节点的时候,我们首先判断上一次访问的是不是它的右孩子节点,如果不是并且该节点有右孩子节点的话,那么就先访问它的右子树。如果是的话,那么表示该节点的左子树和右子树都已经访问完毕。

    void postOrderTraversal(BiTree BT)
    {
        BiTree T = BT, pre = NULL;
        Stack S = CreateStack(MaxSize);
        while(T||!isEmpty(S)) {
            while(T) {
                Push(S, T);
                T = T->lchild;
            }
            if(!isEmpty(S)){
                T = getTop(S);
                //右子树还没有被访问
                if(T->rchild && T->rchild!=pre)
                    T = T->rchild;
                //无右子树或右子树已被访问
                else{                              
                    T = pop(S);//节点出栈并访问
                    visit(T);
                    pre = T;
                    T = NULL;//将T设为空,以访问其父节点。
                }
            }
        }
    }

    参考自:

    https://www.icourse163.org/learn/ZJU-93001?tid=1003997005#/learn/content?type=detail&id=1007588486&cid=1009151983(main)

    https://blog.csdn.net/sky_kkk/article/details/78543358?utm_source=blogxgwz7

    https://blog.csdn.net/sdulibh/article/details/50573036

    https://blog.csdn.net/zhangxiangdavaid/article/details/37115355

  • 相关阅读:
    无法将类型“XXX”隐式转换为“XXX[]”(Cannot implicitly convert type 'XXX' to 'XXX[]')
    VS2010验证时出错。HRESULT = '8000000A'
    Linux Command Tips
    RealVNC 使用手册
    PL/SQL Developer自动补全SQL技巧
    Install dnsutils(dig, nslookup, host) On iPhone
    asp.net压缩图片
    Discuz论坛密码加密方式详解
    三种SQL分页法效率分析
    Mysql数据库服务器配置文件/etc/my.cnf的详细配置
  • 原文地址:https://www.cnblogs.com/wizarderror/p/10816635.html
Copyright © 2011-2022 走看看