非遞歸實現二叉樹的三種遍歷操作,C++描述


二叉樹遍歷圖解示意圖可以參考《大話數據結構》P175,看了這個過程能更好的理解算法,作者博客地址:http://cj723.cnblogs.com/

  輸入過程就是 ab##c##        輸入過程就是 ABC###DE##F##

圖一:
前序遍歷:abc
中序遍歷:bac
后序遍歷:bca
圖二:
前序遍歷:ABCDEF
中序遍歷:CBAEDF
后序遍歷:CBEFDA
#include<iostream>
#include<stack>
using namespace std;
typedef struct BinaryTree
{
        char data;
        struct BinaryTree* lchild;
        struct BinaryTree* rchild;
}binaryTreeNode,*pBinaryTree;
int createBinaryTree(pBinaryTree& root);

//非遞歸實現前序遍歷,利用棧來模擬遞歸過程
void preorderTraversalNonRecursion(pBinaryTree root); 

//非遞歸實現中序遍歷,利用棧來模擬遞歸過程
void inorderTraversalNonRecursion(pBinaryTree root);

//非遞歸實現后序遍歷,利用棧來模擬遞歸過程
void postorderTraversalNonRecursion(pBinaryTree root);

int createBinaryTree(pBinaryTree& root)
{
        char data;
        if(cin>>data)
        {
                if('#'==data)  //輸入#表示該結點為空
                {
                        root = NULL; 
                        return -1;  //只要當輸入是#才會返回-1,表示空樹
                }               
                //建立根結點
                binaryTreeNode* node = new binaryTreeNode();
                node->data = data;
                root = node;
                //遞歸去建立左子樹
                createBinaryTree(root->lchild);
                //遞歸去建立右子樹
                createBinaryTree(root->rchild);
        }
        return 0;   //最終遞歸返回的是0;
}

void preorderTraversalNonRecursion(pBinaryTree root)
{ //訪問節點順序是:根結點,左子樹,右子樹;針對左右子樹,又是按照根左右的順序訪問,所有這個過程中要記錄根結點
        if(nullptr==root)
                return;
        stack<binaryTreeNode*> rootNode;  //遍歷過程中記錄根結點
        while(!rootNode.empty()||
                nullptr!=root)
        {
                while(nullptr!=root)
                {
                        cout<<root->data<<" ";  //輸出根結點
                        //遍歷左子樹
                        rootNode.push(root);  //記錄左子樹的根結點,前序遍歷回溯訪問右子樹的時候要用到
                        root = root->lchild;
                } / /一直遍歷到最左邊的最后一個結點,肯定左子樹為空了,出while循環,這時候就要回溯訪問右子樹了
                if(!rootNode.empty())
                {
                        root = rootNode.top();  //棧中取出最近入棧的根結點
                        root = root->rchild;  //根結點指向右子樹
                        rootNode.pop();  / /最近壓棧的根結點彈棧
                        //右子樹也是一棵二叉樹,又回到第二個while循環,前序遍歷,根左右的方法訪問右子樹
                }
                else
                        root = NULL;
        }
}
void inorderTraversalNonRecursion(pBinaryTree root)
{ //左子樹,根結點,右子樹
        if(nullptr==root)
                return ;
        stack<binaryTreeNode*> rootNode;
        while(nullptr!=root||
                !rootNode.empty())
        {
                while(nullptr!=root)
                {
                        rootNode.push(root);  //棧中保存根結點,先去訪問左子樹
                        root = root->lchild;
                } //左子樹遍歷完畢
                cout<<rootNode.top()->data<<" ";  //訪問根結點
                root = rootNode.top()->rchild;  //訪問右子樹
                rootNode.pop();  //出棧最近保存的結點
        }
}
typedef struct Traversal
{
        binaryTreeNode* rootAddr;  //二叉樹結點地址
        bool accessToken;  //訪問標記
}traversalInfo,*pTraversal;
void postorderTraversalNonRecursion(pBinaryTree root)
{ //后序遍歷,左子樹,右子樹,根結點
        //遍歷完左子樹后要回溯到根結點去遍歷右子樹,所以需要一個標記來記錄根結點,如果是第二次遍歷到就直接輸出值
        if(nullptr==root)
                return ;
        stack<traversalInfo> rootNodeIndo;
        while(nullptr!=root)  //二叉樹根結點最后才會訪問
        {
                //遍歷左子樹
                traversalInfo tmp;
                tmp.rootAddr = root;
                tmp.accessToken = false;  //第一次訪問,第二次訪問修改為true,輸出信息
                rootNodeIndo.push(tmp);  //遍歷右子樹沿途的根結點入棧
                root = root->lchild;
        } //開始回溯遍歷右子樹
        while(!rootNodeIndo.empty())
        {
                root = rootNodeIndo.top().rootAddr;  //取出最近訪問的根結點
                //遍歷右子樹
                while(nullptr!=root->rchild&&
                        !rootNodeIndo.top().accessToken)  //右子樹不空,並且根結點只存在第一次訪問
                {
                        rootNodeIndo.top().accessToken = true;  //根結點第二次訪問,修改為true,下次回溯訪問到就要輸出
                        //右子樹根結點進棧
                        root = root->rchild;
                        traversalInfo tmp;
                        tmp.rootAddr = root;
                        tmp.accessToken = false;
                        rootNodeIndo.push(tmp);

                        //右子樹的左子樹不空,接着遍歷左子樹
                        while(nullptr!=root->lchild)
                        {
                                root = root->lchild;
                                traversalInfo tmp;
                                tmp.rootAddr = root;
                                tmp.accessToken = false;
                                rootNodeIndo.push(tmp);
                        } //右子樹的左子樹遍歷完畢,回溯遍歷右子樹的右子樹。
                }
                //輸出結點信息
                //執行下面語句只有兩種情況,1、對應二叉樹最左邊結點沒有右子樹,包括右子樹的最左邊結點
                //2、回溯再次訪問到根結點,即第3個while循環的第二個條件!rootNodeIndo.top().accessToken不滿足
                cout<<rootNodeIndo.top().rootAddr->data<<" ";
                rootNodeIndo.pop();  //出棧
        }
}




int main()
{
        pBinaryTree root = nullptr;
        int ret = createBinaryTree(root);
        if(0==ret)
        {
                cout<<"preorder traversal non-recursion:"<<endl;
                preorderTraversalNonRecursion(root);
                cout<<endl<<endl;;
                cout<<"inorder traversal non-recursion:"<<endl;
                inorderTraversalNonRecursion(root);
                cout<<endl<<endl;;
                cout<<"postorder traversal non-recursion:"<<endl;
                postorderTraversalNonRecursion(root);
                cout<<endl;
        }

        cout<<endl;
        system("pause");
}
   


//后序遍歷算法優化
typedef struct Traversal
{
        binaryTreeNode* rootAddr;  
        bool accessToken; 
}traversalInfo,*pTraversal;


void stackPush(stack<traversalInfo>& rootNodeInfo,binaryTreeNode* &rootAddr,bool&& flag)
{
        traversalInfo tmp;
        tmp.rootAddr = rootAddr;
        tmp.accessToken = flag; 
        rootNodeInfo.push(tmp);
}

void postorderTraversalNonRecursion(pBinaryTree root)
{
        if(nullptr==root)
                return ;
        stack<traversalInfo> rootNodeInfo;
        while(nullptr!=root) 
        {
                stackPush(rootNodeInfo,root,false);
                root = root->lchild;
        }
        while(!rootNodeInfo.empty())
        {
                root = rootNodeInfo.top().rootAddr; 
                while(nullptr!=root->rchild&&
                        !rootNodeInfo.top().accessToken) 
                {
                        rootNodeInfo.top().accessToken = true; 
                        root = root->rchild;
                        stackPush(rootNodeInfo,root,false);
                  
                        while(nullptr!=root->lchild)
                        {
                                root = root->lchild;
                                stackPush(rootNodeInfo,root,false);
                        }
                }
                cout<<rootNodeInfo.top().rootAddr->data<<" ";
                rootNodeInfo.pop();  
        }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM