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

树结点的声明

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,即它的右结点。

原文地址:https://www.cnblogs.com/happygirl-zjj/p/4574620.html