二叉树后序遍历非递归算法(C/C++语言实现)

二叉树的三种遍历递归代码很容易实现。自己写下非递归算法有助于加深理解二叉树数据结构,代码是思路的实现,在纸上画个二叉树,手工实践下后序遍历的过程。如果会写先根序和中根序的非递归代码,稍微改一下,就容易得到后序非递归代码了。

不论哪种遍历,有个共同点,就是左边始终先于右边访问。大体思路和先/中根序一样,利用一个辅助栈,暂存一些后访问节点。只不过后序相对麻烦点,不像先/中根序遍历,后两者根节点先于根的右子树访问,根节点访问之后就可以“扔掉”,后序遍历需要一直保存根节点,直到其右子树访问完,最后再访问根节点。

后序需要标记每个节点是否被访问过,可以有两种方法:可以在二叉树节点结构增加一个标志域,标记当前节点是否已经被访问,见版本1; 也可不用在每个节点增加标志域,而是用set存储每个访问过的节点,见版本2。

具体代码如下:

手工画个例子,照着代码走一遍,加深理解。

/* 二叉树节点结构 */
struct BinaryTreeNode{
    int data;
    BinaryTreeNode* lchild;
    BinaryTreeNode* rchild;
    bool hasBeenAccessed; /* 其实不用这个域也可以,见下面第二个版本 */
    BinaryTreeNode(int _data = -1):
        data(_data),lchild(NULL),rchild(NULL),hasBeenAccessed(false){}
};

/* 版本一: 每个节点保存访问标志 */
void postTraverseNonRecursively( BinaryTreeNode* pRoot ) {
    if( pRoot == NULL ) {
        printf("Empty tree!\n");
        return;
    }
    
    stack stk;  /* 使用C++标准容器适配器stack */
    stk.push( pRoot );
    BinaryTreeNode *pRightChild;
    BinaryTreeNode *pCurNode = pRoot ->lchild; /* 当前处理节点 */
    while( !stk.empty() ) {
        /* 往左走,走到最左,走过的节点依次进栈 */
        while( pCurNode != NULL && pCurNode ->hasBeenAccessed == false ) { /* 注意循环的条件 */
            stk.push( pCurNode );
            pCurNode = pCurNode ->lchild;
        }
        pCurNode = stk.top();
        stk.pop();
        pRightChild = pCurNode ->rchild;
        if( pRightChild == NULL || pRightChild ->hasBeenAccessed == true ) {
            printf( "%d  ", pCurNode ->data ); /* 访问该节点 */
            pCurNode ->hasBeenAccessed = true; /* 设置访问标记 */
        } else /* if( pRightChild != NULL && pRightChild ->hasBeenAccessed == false ) */
        {
            stk.push( pCurNode );
            stk.push( pRightChild );
            pCurNode = pRightChild ->lchild; /* 重新设置当前处理节点为右子树的左孩子 */
        }
    }
}

/* 版本二: 节点不用访问标志域, 而是用set存储已经访问过的节点。大部分代码不变。 */
void postTraverseNonRecursively2( BinaryTreeNode* pRoot ) {
    set visited; /* 存放已经访问过的节点 */
    if( pRoot == NULL ) {
        printf("Empty tree!\n");
        return;
    }

    stack stk;  /* 使用C++标准容器适配器stack */
    stk.push( pRoot );
    BinaryTreeNode *pRightChild;
    BinaryTreeNode *pCurNode = pRoot ->lchild; /* 当前处理节点 */
    while( !stk.empty() ) {
        /* 往左走,走到最左,走过的节点依次进栈 */
        while( pCurNode != NULL && visited.count(pCurNode) == 0 ) { /* 注意循环的条件 */
            stk.push( pCurNode );
            pCurNode = pCurNode ->lchild;
        }
        pCurNode = stk.top();
        stk.pop();
        pRightChild = pCurNode ->rchild;
        if( pRightChild == NULL || visited.count(pRightChild) == 1 ) {
            printf( "%d  ", pCurNode ->data ); /* 访问该节点 */
            visited.insert(pCurNode); /* 设置访问标记 */
        } else /* if( pRightChild != NULL && visited.count(pRightChild) == 0 ) */
        {
            stk.push( pCurNode );
            stk.push( pRightChild );
            pCurNode = pRightChild ->lchild; /* 重新设置当前处理节点为右子树的左孩子 */
        }
    }
}

    原文作者:递归算法
    原文地址: https://blog.csdn.net/sgcls/article/details/38672951
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞