zoukankan      html  css  js  c++  java
  • 二叉树遍历算法总结

                                                                                二叉树遍历算法总结

        

       本文依据《数据结构与算法》(C语言版)(第三版) 整理。

       A.  二叉树的遍历

          1.前序遍历二叉树:

            (1)若二叉树为空,则为空操作,返回空。


            (2)訪问根结点。
            (3)前序遍历左子树。


            (4)前序遍历右子树。


          a.二叉树前序遍历的递归算法:

       void PreOrderTraverse(BiTree BT)
       {
         if(BT)
         {
            printf("%c",BT->data);              //訪问根结点
            PreOrderTraverse(BT->lchild);       //前序遍历左子树
            PreOrderTraverse(BT->rchild);       //前序遍历右子树
         }
       }

        b.使用栈存储每一个结点右子树的二叉树前序遍历的非递归算法:

          (1)当树为空时,将指针p指向根结点,p为当前结点指针。


          (2)先訪问当前结点p。并将p压入栈S中。


          (3)令p指向其左孩子。
          (4)反复运行步骤(2)、(3)。直到p为空为止。
          (5)从栈S中弹出栈顶元素。将p指向此元素的右孩子。
          (6)反复运行步骤(2)~(5),直到p为空而且栈S也为空。
          (7)遍历结束。


          使用栈的前序遍历的非递归算法:

          void PreOrderNoRec(BiTree BT)
          {
            stack S;
            BiTree p=BT->root;
            while((NULL!=p)||!StackEmpty(S))
            {
              if(NULL!=p)
              {
                printf("%c",p->data);
                Push(S,p);
                p=p->lchild;
              }
              else
              {
                p=Top(S);
                Pop(S);
                p=p->rchild;
              }
            }
          }

        c.使用二叉链表存储的二叉树前序遍历非递归算法:

        void PreOrder(pBinTreeNode pbnode)
        {
          pBinTreeNode stack[100];
          pBinTreeNode p;
          int top;
          top=0;
          p=pbnode;
          do
          {
            while(p!=NULL)
            {
              printf("%d
    ",p->data);      //訪问结点p
              top=top+1;
              stack[top]=p;
              p=p->llink;                  //继续搜索结点p的左子树
            }
            if(top!=0)
            {
              p=stack[top];
              top=top-1;
              p=p->rlink;                  //继续搜索结点p的右子树
            }
          }while((top!=0)||(p!=NULL));
        }
    

        2.中序遍历二叉树:

          (1)若二叉树为空。则为空操作,返回空。


          (2)中序遍历左子树。
          (3)訪问根结点。
          (4)中序遍历右子树。

          a.二叉树中序遍历的递归算法:

        void InOrderTraverse(BiTree BT)
        {
          if(BT)
          {
             InOrderTraverse(BT->lchild);        //中序遍历左子树
             printf("%c",BT->data);              //訪问根结点
             InOrderTraverse(BT->rchild);        //中序遍历右子树
          }
        }

          b.使用栈存储的二叉树中序遍历的非递归算法:

           (1)当树为空时,将指针p指向根结点,p为当前结点指针。
           (2)将p压入栈S中。并令p指向其左孩子。
           (3)反复运行步骤(2)。直到p为空。
           (4)从栈S中弹出栈顶元素,将p指向此元素。


           (5)訪问当前结点p。并将p指向其右孩子。
           (6)反复运行步骤(2)~(5),直到p为空而且栈S也为空。
           (7)遍历结束。
            使用栈的中序遍历的非递归算法:

         void IneOrderNoRec(BiTree BT)
         {
           stack S;
           BiTree p=BT->root;
           while((NULL!=p)||!StackEmpty(S))
           {
             if(NULL!=p)
             {
               Push(S,p);
               p=p->lchild;
             }
             else
             {
               p=Top(S);
               Pop(S);
               printf("%c",p->data);
               p=p->rchild;
             }
           }
         }

           c.使用二叉链表存储的二叉树中序遍历非递归算法:

        void InOrder(pBinTreeNode pbnode)
        {
             pBinTreeNode stack[100];
             pBinTreeNode p;
             int top;
             top=0;
             p=pbnode;
             do
             {
               while(p!=NULL)
               {
                 top=top+1;
                 stack[top]=p;                //结点p进栈
                 p=p->llink;                  //继续搜索结点p的左子树
               }
               if(top!=0)
               {
                 p=stack[top];                //结点p出栈
                 top=top-1;
                 printf("%d
    ",p->data);      //訪问结点p
                 p=p->rlink;                  //继续搜索结点p的右子树
               }
             }while((top!=0)||(p!=NULL));
        }
          

        3.后序遍历二叉树:

          (1)若二叉树为空。则为空操作,返回空。


          (2)后序遍历左子树。
          (3)后序遍历右子树。
          (4)訪问根结点。

          a.二叉树后序遍历的递归算法:

         void PostOrderTraverse(BiTree BT)
         {
           if(BT)
           {
              PostOrderTraverse(BT->lchild);        //后序遍历左子树
              PostOrderTraverse(BT->rchild);        //后序遍历右子树
              printf("%c",BT->data);                //訪问根结点
           }
         }

          b.使用栈存储的二叉树后序遍历的非递归算法:

          算法思想:首先扫描根结点的全部左结点并入栈,然后出栈一个结点,扫描该结点的右结点并入栈,再扫描该右结点的全部左结点并入栈,当一个结点的左、右子树均被訪问后再訪问该结点。由于在递归算法中。左子树和右子树都进行了返回,因此为了区分这两种情况。还须要设置一个标识栈tag,当tag的栈顶元素为0时表示从左子树返回。为1表示从右子树返回。
           (1)当树为空时,将指针p指向根结点,p为当前结点指针。
           (2)将p压入栈S中,0压入栈tag中,并令p指向其左孩子。
           (3)反复运行步骤(2),直到p为空。
           (4)假设tag栈中的栈顶元素为1,跳至步骤(6)。


           (5)假设tag栈中的栈顶元素为0,跳至步骤(7)。


           (6)将栈S的栈顶元素弹出,并訪问此结点。跳至步骤(8)。
           (7)将p指向栈S的栈顶元素的右孩子。
           (8)反复运行步骤(2)~(7),直到p为空而且栈S也为空。


           (9)遍历结束。


            使用栈的后序遍历非递归算法:

           void PostOrderNoRec(BiTree BT)
           {
             stack S;
             stack tag;
             BiTree p=BT->root;
             while((NULL!=p)||!StackEmpty(S))
             {
               while(NULL!=p)
               {
                 Push(S,p);
                 Push(tag,0);
                 p=p->lchild;
               }
               if(!StackEmpty(S))
               {
                 if(Pop(tag)==1)
                 {
                   p=Top(S);
                   Pop(S);
                   printf("%c",p->data);
                   Pop(tag);    //栈tag要与栈S同步
                 }
                 else
                 {
                   p=Top(S);
                   if(!StackEmpty(S))
                   {
                     p=p->rchild;
                     Pop(tag);
                     Push(tag,1);
                   }
                 }
               }
             }
           }

         c.使用二叉链表存储的二叉树后序遍历非递归算法:

         void PosOrder(pBinTreeNode pbnode)
         {
              pBinTreeNode stack[100];       //结点的指针栈
              int count[100];                //记录结点进栈次数的数组
              pBinTreeNode p;
              int top;
              top=0;
              p=pbnode;
              do
              {
                while(p!=NULL)
                {
                  top=top+1;
                  stack[top]=p;                //结点p首次进栈
                  count[top]=0;
                  p=p->llink;                  //继续搜索结点p的左子树
                }
                p=stack[top];                  //结点p出栈
                top=top-1;
                if(count[top+1]==0)
                {
                  top=top+1;
                  stack[top]=p;                //结点p首次进栈
                  count[top]=1;
                  p=p->rlink;                  //继续搜索结点p的右子树
                }
                else
                {
                  printf("%d
    ",p->data);      //訪问结点p
                  p=NULL;
                }
              }while((top>0));
         }

         B 线索化二叉树:

           线索化二叉树的结点结构图:
                                                
           线索化二叉树的结点类型说明:
          typedef struct node
          {
            DataType data;
            struct node *lchild, *rchild;       //左、右孩子指针
            int ltag, rtag;                     //左、右线索
          }TBinTNode;         //结点类型
          typedef TBinTNode *TBinTree;
           在线索化二叉树中。一个结点是叶子结点的充分必要条件是其左、右标志均为1.
         中序线索化二叉树及其相应的线索链表例如以下图:
                           

          (1)中序线索化二叉树的算法:

           void InOrderThreading(TBinTree p)
          {
            if(p)
            {
              InOrderThreading(p->lchild);   //左子树线索化
              if(p->lchild)
                p->ltag=0;
              else
                p->ltag=1;
              if(p->rchild)
                p->rtag=0;
              else
                p->rtag=1;
              if(*(pre))      //若*p的前驱*pre存在
              {
                if(pre->rtag==1)
                  pre->rchild=p;
                if(p->ltag==1)
                  p->lchild=pre;
              }
              pre=p;                         //另pre是下一訪问结点的中序前驱
              InOrderThreading(p->rchild);   //右子树线索化
            }
          }
           

        (2)在中序线索化二叉树下,结点p的后继结点有下面两种情况:

          ①结点p的右子树为空。那么p的右孩子指针域为右线索,直接指向结点p的后继结点。
          ②结点p的右子树不为空。那么依据中序遍历算法。p的后继必是其右子树中第1个遍历到的结点。
          
         中序线索化二叉树求后继结点的算法:
        TBinTNode *InOrderSuc(BiThrTree p)
        {
           TBinTNode *q;
           if(p->rtag==1)   //第①情况
             return p->rchild;
           else            //第②情况
           {
             q=p->rchild;
             while(q->ltag==0)
               q=q->lchild;
             return q;
           }
        }
          中序线索化二叉树求前驱结点的算法:
        TBinTNode *InOrderPre(BiThrTree p)
        {
           TBinTNode *q;
           if(p->ltag==1)
             return p->lchild;
           else
           {
             q=p->lchild;         //从*p的左孩子開始查找
             while(q->rtag==0)
               q=q->rchild;
             return q;
           }
        }

         (3)遍历中序线索化二叉树的算法

        void TraversInOrderThrTree(BiThrTree p)
        {
          if(p)
          {
            while(p->ltag==0)
              p=p->lchild;
            while(p)
            {
              printf("%c",p->data);
              p=InOrderSuc(p);
            }
          }
        }
  • 相关阅读:
    Win7+Ubuntu11.10(EasyBCD硬盘安装)
    hdu 3661 Assignments
    hdu 1128 Self Numbers
    CF 152 B. Chilly Willy
    hdu 1754 I Hate It
    A survey of wireless network simulation and/or emulation software for use in higher education
    How to Fix Packet Loss: Causes, Simple Solutions & Top Tools
    getchar函数
    C++“左值”和“右值”
    stdio.h中的stdio
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8452087.html
Copyright © 2011-2022 走看看