• 二叉树的三种递归与非递归遍历算法


    树结点的声明

    struct BinaryNode
    {
        char element;
        BinaryNode* left;
        BinaryNode* right;
        BinaryNode()
        {
            element = ' ';
            left = right = NULL;
        }
    };

    创建一棵二叉树

     1 BinaryNode * creatBinaryTree (string&s)
     2 {
     3     if (s.empty())
     4         return NULL;
     5     size_t n = s.size();
     6     BinaryNode* p = new BinaryNode[n];
     7     for (int i = 0; i < n; ++i)
     8     {
     9         p[i].element = s[i];
    10         if ( (2*i+1) < n )
    11             p[i].left = &p[2*i+1];
    12         if ( (2*i+2) < n )
    13             p[i].right = &p[2*i+2];
    14     }
    15     return p;
    16 }

    输出二叉树

     1 enum mode{preR,preNr, inR, inNr, postR, postNr};
     2 
     3 void displayBinaryTree(BinaryNode*t, enum mode& m)
     4 {
     5     switch(m)
     6     {
     7     case preR:
     8         preOrderTraverse_Recursive(t);
     9         break;
    10     case preNr:
    11         preOrderTraverse_nonRecursive(t);
    12         break;
    13     case inR:
    14         inOrderTraverse_Recursive(t);
    15         break;
    16     case inNr:
    17         inOrderTraverse_nonRecursive(t);
    18         break;
    19     case postR:
    20         postOrderTraverse_Recursive(t);
    21         break;
    22     case postNr:
    23         postOrderTraverse_nonRecursive(t);
    24         break;
    25     default:
    26         ;
    27     }
    28 }

    一.先序遍历

    1.递归算法

    1 void preOrderTraverse_Recursive( BinaryNode *t)
    2 {
    3     if (t)
    4     {
    5         cout << t->element << endl;
    6         preOrderTraverse_Recursive(t->left);
    7         preOrderTraverse_Recursive(t->right);
    8     }
    9 }

    2.非递归算法
    思路::在先序遍历中,由于根节点首先被访问,而且由根结点可以同时得到左右孩子结点的信息,因此在访问过程中,可以在访问根节点的同时将根节点从栈中删除,并且将根节点的左右孩子按照右孩子,左孩子的顺序入栈。

     1 void preTraverse_nonRecursive( BinaryNode *t)
     2 {
     3         stack<BinaryNode*>s;
     4         BinaryNode* p = t;
     5         s.push(p);     
     6         while (!s.empty())
     7         {
     8             p = s.top();
     9             s.pop();
    10             if (p)
    11             {
    12                 cout<<p->element<<endl;
    13                 s.push(p->right);
    14                 s.push(p->left);
    15             }
    16         }
    17 }

    二.中序遍历

    1.递归算法

    void inOrderTraverse_Recursive( BinaryNode *t)
    {
        if (t)
        {
            inOrderTraverse_Recursive(t->left);
            cout << t->element << endl;
            inOrderTraverse_Recursive(t->right);
        }
    }

    2.非递归算法
    思路1和思路2的主要区别是思路1会将空指针压入栈中,而思路2则不会,因此思路1需要将空指针弹出栈

     1 //思路1
     2 void inOrderTraverse_nonRecursive( BinaryNode *t)
     3 {
     4     stack<BinaryNode*>s;
     5     BinaryNode* p = t ;
     6     s.push(p);
     7     while ( !s.empty() )
     8     {//p表示栈顶元素
     9         p = s.top();
    10         while ( p  )
    11         {//向左走到尽头,最后压入的一定是空指针
    12             p = p->left;
    13             s.push(p);
    14         }
    15         s.pop();//空指针出栈
    16         if (!s.empty())
    17         {
    18             p = s.top();
    19             s.pop();
    20             cout << p->element << endl;
    21             s.push( p->right );
    22         }
    23     }
    24 }
     1 void inOrderTraverse_nonRecursive( BinaryNode *t)
     2 {//思路2
     3     stack<BinaryNode*>s;
     4     BinaryNode* p = t ;
     5     while ( p || !s.empty() )
     6     {//p指向的是下一个需要被访问的结点
     7         if ( p )
     8         {
     9             s.push(p);
    10             p = p->left;
    11         }
    12         else
    13         {//p为null,栈非空
    14             p = s.top();
    15             s.pop();//根指针退栈,遍历右子树
    16             cout << p->element << endl;
    17             p = p->right;
    18         }
    19     }
    20 }

    三.后序遍历

    1.递归算法

    void postOrderTraverse_Recursive( BinaryNode *t)
    {
        if (t)
        {
            postOrderTraverse_Recursive(t->left);
            postOrderTraverse_Recursive(t->right);
            cout << t->element << endl;
        }
    }

    2.非递归算法
    思路:按照根节点,右孩子结点,左孩子结点的顺序依次入栈。如果一个结点没有左右孩子结点,则该结点可被访问,同时该结点出栈。如果一个结点有左右孩子结点,但是其孩子结点已经被访问,则该结点也可以被访问。因此需要设置一个变量preNode存放上次被访问的结点。

     1 void postOrderTraverse_nonRecursive( BinaryNode *t)
     2 {
     3         stack<BinaryNode*>s;
     4         BinaryNode* p = t ;
     5         BinaryNode* preNode = t;
     6         if (p)
     7             s.push(p);
     8         while (!s.empty())
     9         {
    10             p = s.top();
    11             if ( (p->left == NULL && p->right==NULL) 
    12                 || (preNode == p->left || preNode == p->right) )
    13             {
    14                 cout << p->element << endl;
    15                 s.pop();
    16                 preNode = p;
    17             }
    18             else
    19             {
    20                 if (p->right)
    21                     s.push(p->right);
    22                 if (p->left)
    23                     s.push(p->left);
    24             }
    25         }
    26 }
     

    后序遍历时栈的出栈入栈情况如图所示:结点d因为左右孩子都为空,因此可以访问,访问完成后出栈,结点b的左右孩子因为都被访问过也可以被访问,此时b的前一个访问结点是结点e,它的右结点。
    上图为反映了后序遍历时数据出栈入栈的情况。结点d因为左右孩子都为空,因此可以访问,访问完成后出栈,结点b的左右孩子因为都被访问过,因此也可以被访问,此时b的前一个访问结点是结点e,即它的右结点。

  • 相关阅读:
    UWP开发-获取设备唯一ID
    html5加js实现本地文件读取和写入并获取本地文件路径
    C/C++杂记:运行时类型识别(RTTI)与动态类型转换原理
    C/C++杂记:深入虚表结构
    C/C++杂记:虚函数的实现的基本原理
    C/C++杂记:深入理解数据成员指针、函数成员指针
    C/C++杂记:NULL与0的区别、nullptr的来历
    细说:Unicode, UTF-8, UTF-16, UTF-32, UCS-2, UCS-4
    汉字编码:GB2312, GBK, GB18030, Big5
    ANSI是什么编码?
  • 原文地址:https://www.cnblogs.com/happygirl-zjj/p/4574620.html
Copyright © 2020-2023  润新知