二叉树的递归遍历以及非递归遍历(一)----先序遍历

1.二叉树的遍历方式:

先序遍历、中序遍历、后序遍历(此处不考虑层次遍历)

先序遍历:先访问根节点,再访问左子树,然后是右子树

中序遍历:先访问左子树,然后是根节点,然后是右子树

后序遍历:先访问左子树,然后右子树,最后是根节点。

 

2. 二叉树基本数据结构定义:

typedef struct TNode
{
        int val;
        struct TNode* pLeft;
        struct TNode* pRight;

        TNode(int val, TNode* pLeft, TNode* pRight)
        {
            this->val = val;
            this->pLeft = pLeft;
            this->pRight = pRight;
        }

        TNode()
        {

        }

        ~TNode()
        {
                if (pLeft)
                {
                    delete pLeft;
                    pLeft = NULL;
                }

                if (pRight)
                {
                    delete pRight;
                    pRight = NULL;
                }
        }
}TNode;

二叉树的构造:

/**************************************************************************************
                        4
             1                   5
         2       3         6          7

***************************************************************************************/
TNode*  buildTree()
{
        TNode *p = new TNode(1,
                             new TNode(2, NULL,NULL),
                             new TNode(3, NULL,NULL));
        TNode *q =  new TNode(4,
                              p,
                              new TNode(5,
                                        new TNode(6, NULL,NULL),
                                        new TNode(7, NULL,NULL)));

        return q;
};

树的逻辑结构如下:

二叉树的递归遍历以及非递归遍历(一)----先序遍历_第1张图片

                    图一(测试用树结构)

3. 先序遍历

3.1 先序遍历的递归写法:

 /**********************************************
  功能:递归先序遍历
  注:遍历顺序为根左右
  **********************************************/
  void preTraverse(TNode* pRoot)
  {
      if (!pRoot) return;
      visit(pRoot);
      preTraverse(pRoot->pLeft);
      preTraverse(pRoot->pRight);
   }

3.2 先序遍历的非递归写法:

 /**********************************************
 功能:非递归先序遍历
 住:遍历顺序为根左右
 **********************************************/
 void preNoRecTraverse(TNode* pRoot)
 {
       stack<TNode*> s;
       TNode* p = pRoot;
       s.push(p);

       while (p || !s.empty())
       {
            p = s.top();
            s.pop();

             visit(p);

             if (p->pRight)   s.push(p->pRight);
             if (p->pLeft)    s.push(p->pLeft);
         }
 }

3.3 过程模拟及结果展示:

递归调用过程:

二叉树的递归遍历以及非递归遍历(一)----先序遍历_第2张图片

                                             图二:递归调用的函数调用层次关系

 

非递归的遍历过程,其实就是模拟递归算法中的堆栈进出顺序。

在递归调用中,可以看到在每一次的递归调用中,总是首先访问根,然后访问左子树,然后访问右子树。对右子树的访问在左子树访问的后面。所以右子树的根先入栈,右子树的根后入栈。

栈的进出图如下:

二叉树的递归遍历以及非递归遍历(一)----先序遍历_第3张图片

                                                  图三:非递归调用的栈进出图

遍历结果为:(4,1,2,3,5,6,7)

 

递归算法和非递归算法的比较:

此处把正在运行的函数看成是一个栈,调用其他函数看成是进栈,调用函数运行完认为是出栈,模拟一下递归调用的栈:

二叉树的递归遍历以及非递归遍历(一)----先序遍历_第4张图片

 

共同点:两者对节点的遍历次序一致

区别:在非递归调用中,对右子树的访问在左子树后面,所以先将右子树节点压栈,再压左子树节点,这样在出栈进行遍历的时候起到先遍历左子树,再遍历右子树的效果。
在递归调用中,对左右子树调用的先后区别在于是先调用左子树的遍历函数,再调用右子树的遍历函数,起到的效果是一致的。

你可能感兴趣的:(递归,非递归,二叉树遍历,先序遍历)