zoukankan      html  css  js  c++  java
  • 数据结构-二叉树的遍历

    二叉树的定义:

    又称二分树,它是有限的节点集合,这个集合或者是空,或者是由一个根节点和两棵互不相交的称为左子树和右子树的二叉树组成。

    他和度为2的树是不同的,差别在于

    1、度为2的树中至少有一个节点的度为2,而二叉树没有这种要求

    2、度为2的数不区分左右子树而二叉树严格区分左右子树。

    遍历方案

    二叉树的前序遍历

    从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:

    ⑴访问结点本身(N),

    ⑵遍历该结点的左子树(L),

    ⑶遍历该结点的右子树(R)。

    以上三种操作有六种执行次序:

    NLR、LNR、LRN、NRL、RNL、RLN。

    注意:

    前三种次序与后三种次序对称,故只讨论先左后右的前三种次序。

    常规的三种递归遍历方法

    1、先序遍历:

    访问根节点,先序遍历左子树,先序遍历右子树

    2、中序遍历:

    中序遍历左子树,访问根节点,中序遍历右子树

    3、后序遍历

    后序遍历左子树,访问根节点,后序遍历右子树。

    关于层次遍历法从上到下从左到右遍历所有节点。

    一般而言,先序遍历不会有什么问题,最主要的是中序遍历。

    如下例:

    image

    三种遍历结果(可以利用文章提供的算法验证正确性)如下

    先序遍历 ABCDEFGHIJKMN

    中序遍历  DFEGCHBAMKNJI

    后序遍历  FGEDHCBMNKJIA

    上面二叉树中序遍历的错误写法:

    FEGDCHBAMKNJI

    错误写法的关键在于错误的选择了E(F,G)二叉树作为遍历的起点,实际上我们应该选择D(,tree)作为遍历的起点。[其中tree指的E(F,G)]

    中序遍历遍历二叉树的过程是:中序遍历左子树,访问根节点,中序遍历右子树。这表明二叉树的遍历是个递归过程,拿中序遍历的递归算法来说

    void InOrder(BTNode *b)           //中序遍历的递归算法
    {
        if (b!=NULL)  
        {    
           InOrder(b->lchild);        //递归访问左子树
            printf("%c ",b->data);    //访问根节点
            InOrder(b->rchild);        //递归访问右子树
        }
    }

    中序遍历中选取的遍历起点应该是由整棵二叉树根节点一直往左持续延伸最后形成的叶子节点 。

    此外 二叉树的中序遍历可以使用投影法来快速解决比如

    image

    二叉树遍历的算法源码:

    //文件名:exp7-2.cpp
    #include <stdio.h>
    #include <malloc.h>
    #define MaxSize 100
    typedef char ElemType;
    typedef struct node
    {
        ElemType data;                //数据元素
        struct node *lchild;        //指向左孩子
        struct node *rchild;        //指向右孩子
    } BTNode;
    #define MaxSize 100
    typedef char ElemType;
     void CreateBTNode(BTNode *&b,char *str);
     void DispBTNode(BTNode *b);
     void DestroyBTNode(BTNode *&b);
    void PreOrder(BTNode *b)          //先序遍历的递归算法
    {
        if (b!=NULL)  
        {    
            printf("%c ",b->data);    //访问根节点
            PreOrder(b->lchild);    //递归访问左子树
            PreOrder(b->rchild);    //递归访问右子树
        }
    }
    void PreOrder1(BTNode *b)
    {
        BTNode *St[MaxSize],*p;
        int top=-1;
        if (b!=NULL) 
        {
            top++;                        //根节点入栈
            St[top]=b;
            while (top>-1)                //栈不为空时循环
            {
                p=St[top];                //退栈并访问该节点
                top--;
                printf("%c ",p->data);
                if (p->rchild!=NULL)    //右孩子入栈
                {
                   top++;
                   St[top]=p->rchild;
                }
                if (p->lchild!=NULL)    //左孩子入栈
                {
                   top++;
                   St[top]=p->lchild;
                }
            }
            printf("
    ");
        }
    }
    void InOrder(BTNode *b)           //中序遍历的递归算法
    {
        if (b!=NULL)  
        {    
            InOrder(b->lchild);        //递归访问左子树
            printf("%c ",b->data);    //访问根节点
            InOrder(b->rchild);        //递归访问右子树
        }
    }
    void InOrder1(BTNode *b)
    {
        BTNode *St[MaxSize],*p;
        int top=-1;
        if (b!=NULL)
        {
            p=b;
            while (top>-1 || p!=NULL)
            {
                while (p!=NULL)
                {
                    top++;
                    St[top]=p;
                    p=p->lchild;
                }
                if (top>-1)
                {
                    p=St[top];
                    top--;
                    printf("%c ",p->data);
                    p=p->rchild;
                }
            }
            printf("
    ");
        }
    }
    void PostOrder(BTNode *b)         //后序遍历的递归算法
    {
        if (b!=NULL)  
        {    
            PostOrder(b->lchild);    //递归访问左子树
            PostOrder(b->rchild);    //递归访问右子树
            printf("%c ",b->data);    //访问根节点
        }
    }
    void PostOrder1(BTNode *b)
    {
        BTNode *St[MaxSize];
        BTNode *p;
        int flag,top=-1;                        //栈指针置初值
        if (b!=NULL)
        {
            do
            {
                while (b!=NULL)                    //将t的所有左节点入栈
                {
                    top++;
                    St[top]=b;
                    b=b->lchild;
                }
                p=NULL;                            //p指向当前节点的前一个已访问的节点
                flag=1;    
                while (top!=-1 && flag)
                {
                    b=St[top];                    //取出当前的栈顶元素
                    if (b->rchild==p)            //右子树不存在或已被访问,访问之
                    {
                        printf("%c ",b->data);    //访问*b节点
                        top--;
                        p=b;                    //p指向则被访问的节点
                    }
                    else
                    {
                        b=b->rchild;            //t指向右子树
                        flag=0;    
                    }
                }
            } while (top!=-1);
            printf("
    ");
        } 
    }
    void TravLevel(BTNode *b)
    {
        BTNode *Qu[MaxSize];                //定义循环队列
        int front,rear;                        //定义队首和队尾指针
        front=rear=0;                        //置队列为空队列
        if (b!=NULL) 
            printf("%c ",b->data);
        rear++;                                //节点指针进入队列
        Qu[rear]=b;
        while (rear!=front)                    //队列不为空
        {
            front=(front+1)%MaxSize;
            b=Qu[front];                    //队头出队列
            if (b->lchild!=NULL)            //输出左孩子,并入队列
            {
                printf("%c ",b->lchild->data);
                rear=(rear+1)%MaxSize;
                Qu[rear]=b->lchild;
            }
            if (b->rchild!=NULL)            //输出右孩子,并入队列
            {
                printf("%c ",b->rchild->data);
                rear=(rear+1)%MaxSize;
                Qu[rear]=b->rchild;
            }
        } 
        printf("
    ");
    }
    
    void CreateBTNode(BTNode *&b,char *str)        //由str串创建二叉链
    {
        BTNode *St[MaxSize],*p=NULL;
        int top=-1,k,j=0;  
        char ch;
        b=NULL;                //建立的二叉树初始时为空
        ch=str[j];
        while (ch!='')    //str未扫描完时循环
        {
                  switch(ch) 
            {
            case '(':top++;St[top]=p;k=1; break;        //为左节点
            case ')':top--;break;
            case ',':k=2; break;                          //为右节点
            default:p=(BTNode *)malloc(sizeof(BTNode));
                p->data=ch;p->lchild=p->rchild=NULL;
                         if (b==NULL)                    //p指向二叉树的根节点
                            b=p;
                        else                              //已建立二叉树根节点
                        {    
                            switch(k) 
                            {
                            case 1:St[top]->lchild=p;break;
                            case 2:St[top]->rchild=p;break;
                            }
                        }
            }
            j++;
            ch=str[j];
        }
    }
    BTNode *FindNode(BTNode *b,ElemType x)    //返回data域为x的节点指针
    {
        BTNode *p;
        if (b==NULL)
             return NULL;
        else if (b->data==x)
             return b;
        else
        {    
            p=FindNode(b->lchild,x);
            if (p!=NULL) 
                return p;
            else 
                return FindNode(b->rchild,x);
        }
    }
    BTNode *LchildNode(BTNode *p)    //返回*p节点的左孩子节点指针
    {
        return p->lchild;
    }
    BTNode *RchildNode(BTNode *p)    //返回*p节点的右孩子节点指针
    {
        return p->rchild;
    }
    int BTNodeDepth(BTNode *b)    //求二叉树b的深度
    {
           int lchilddep,rchilddep;
           if (b==NULL) 
            return(0);                             //空树的高度为0
           else  
        {    
            lchilddep=BTNodeDepth(b->lchild);    //求左子树的高度为lchilddep
              rchilddep=BTNodeDepth(b->rchild);    //求右子树的高度为rchilddep
            return (lchilddep>rchilddep)? (lchilddep+1):(rchilddep+1);
           }
    }
    void DispBTNode(BTNode *b)    //以括号表示法输出二叉树
    {
        if (b!=NULL)
        {
            printf("%c",b->data);
            if (b->lchild!=NULL || b->rchild!=NULL)
            {
                printf("(");
                DispBTNode(b->lchild);
                if (b->rchild!=NULL) printf(",");
                DispBTNode(b->rchild);
                printf(")");
            }
        }
    }
    int BTWidth(BTNode *b)  //求二叉树b的宽度
    {
        struct 
        {
            int lno;        //节点的层次编号
            BTNode *p;        //节点指针
        } Qu[MaxSize];        //定义顺序非循环队列
        int front,rear;                            //定义队首和队尾指针
        int lnum,max,i,n;
        front=rear=0;                            //置队列为空队
        if (b!=NULL) 
        {
            rear++;    
            Qu[rear].p=b;                        //根节点指针入队
            Qu[rear].lno=1;                        //根节点的层次编号为1
            while (rear!=front)                    //队列不为空
            {
                front++;
                b=Qu[front].p;                    //队头出队
                lnum=Qu[front].lno;
                if (b->lchild!=NULL)            //左孩子入队
                {
                    rear++;
                    Qu[rear].p=b->lchild;
                    Qu[rear].lno=lnum+1;
                }
                if (b->rchild!=NULL)            //右孩子入队
                {
                    rear++;
                    Qu[rear].p=b->rchild;
                    Qu[rear].lno=lnum+1;
                }
            }
            max=0;lnum=1;i=1;
            while (i<=rear)
            {
                n=0;
                while (i<=rear && Qu[i].lno==lnum) 
                {
                    n++;i++;
                }
                lnum=Qu[i].lno;
                if (n>max) max=n;
            }
            return max;
        }
        else
            return 0;
    }
    int Nodes(BTNode *b)    //求二叉树b的节点个数
    {
        int num1,num2;
        if (b==NULL) 
            return 0;
        else if (b->lchild==NULL && b->rchild==NULL) 
            return 1;
        else
        {
            num1=Nodes(b->lchild);
            num2=Nodes(b->rchild);
            return (num1+num2+1);
        }
    }
    int LeafNodes(BTNode *b)    //求二叉树b的叶子节点个数
    {
        int num1,num2;
        if (b==NULL) 
            return 0;
        else if (b->lchild==NULL && b->rchild==NULL) 
            return 1;
        else
        {
            num1=LeafNodes(b->lchild);
            num2=LeafNodes(b->rchild);
            return (num1+num2);
        }
    }
    void DestroyBTNode(BTNode *&b)
    {
        if (b!=NULL)
        {
            DestroyBTNode(b->lchild);
            DestroyBTNode(b->rchild);
            free(b);
        }
    }
    
    
    void main()
    {
        /*
        BTNode *b;
        CreateBTNode(b,"A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))"); 
        printf("二叉树b:");DispBTNode(b);printf("
    ");
        printf("层次遍历序列:");
        TravLevel(b);
        printf("先序遍历序列:
    ");
        printf("    递归算法:");PreOrder(b);printf("
    ");
        printf("  非递归算法:");PreOrder1(b);
        printf("中序遍历序列:
    ");
        printf("    递归算法:");InOrder(b);printf("
    ");
        printf("  非递归算法:");InOrder1(b);
        printf("后序遍历序列:
    ");
        printf("    递归算法:");PostOrder(b);printf("
    ");
        printf("  非递归算法:");PostOrder1(b);
        DestroyBTNode(b);
        */
        BTNode *b;
        CreateBTNode(b,"A(B(C(D(,E(F,G)),H)),I(J(K(M,N))))"); 
        //"a(b(d(,g)),c(e,f(h)))"
        //"A(B(D(E(F(,H),G(I)))),C(,J(K(M,N),L(O(,P)))))"
        //A(C(,D),E(H,F(G,O)))
        //A(B(C(D(,E(F,G)),H)),I(J(K(M,N))))
        printf("二叉树b:");DispBTNode(b);printf("
    ");
        printf("层次遍历序列:");
        TravLevel(b);
        printf("先序遍历序列:
    ");
        printf("    递归算法:");PreOrder(b);printf("
    ");
        printf("  非递归算法:");PreOrder1(b);
        printf("中序遍历序列:
    ");
        printf("    递归算法:");InOrder(b);printf("
    ");
        printf("  非递归算法:");InOrder1(b);
        printf("后序遍历序列:
    ");
        printf("    递归算法:");PostOrder(b);printf("
    ");
        printf("  非递归算法:");PostOrder1(b);
        DestroyBTNode(b);
    }
    作者:leemoaly
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    hdu2066最短路径spfa算法对每个点分别判断0ms过
    关于oj上c++与g++的区别以及一些常见的问题
    hdu1213依旧并查集。求集合的个数
    hdu2112最短路径
    hdu1232最水并查集模版题
    hdu1325最大联通分量+树中点与边数值关系
    hdu2544最短路径spfa模版题
    hdu1856依旧并查集
    hdu1879最小生成树+并查集
    sencha touch 视图(view) show与hide事件探讨
  • 原文地址:https://www.cnblogs.com/kavs/p/4968699.html
Copyright © 2011-2022 走看看