zoukankan      html  css  js  c++  java
  • 【转】二叉树的非递归遍历

    原文地址:http://blog.csdn.net/hackbuteer1/article/details/6583988

            先使用先序的方法建立一棵二叉树,然后分别使用递归与非递归的方法实现前序、中序、后序遍历二叉树,并使用了两种方法来进行层次遍历二叉树,一种方法就是使用STL中的queue,另外一种方法就是定义了一个数组队列,分别使用了front和rear两个数组的下标来表示入队与出队,还有两个操作就是求二叉树的深度、结点数。。。

    //转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/6583988
    #include<iostream>  
    #include<queue>  
    #include<stack>  
    using namespace std;  
      
    //二叉树结点的描述  
    typedef struct BiTNode
    {  
        char data;  
        struct BiTNode *lchild, *rchild;      //左右孩子  
    }BiTNode,*BiTree;  
      
    //按先序遍历创建二叉树  
    //BiTree *CreateBiTree()     //返回结点指针类型  
    //void CreateBiTree(BiTree &root)      //引用类型的参数  
    void CreateBiTree(BiTNode **root)    //二级指针作为函数参数  
    {  
        char ch; //要插入的数据  
        scanf("
    %c", &ch);
        //cin>>ch;  
        if(ch=='#')
            *root = NULL;
        else
        {
            *root = (BiTNode *)malloc(sizeof(BiTNode));
            (*root)->data = ch;
            printf("请输入%c的左孩子:",ch);
            CreateBiTree(&((*root)->lchild));
            printf("请输入%c的右孩子:",ch);
            CreateBiTree(&((*root)->rchild));
        }
    }
      
    //前序遍历的算法程序  
    void PreOrder(BiTNode *root)
    {  
        if(root==NULL)  
            return ;  
        printf("%c ", root->data); //输出数据  
        PreOrder(root->lchild); //递归调用,前序遍历左子树  
        PreOrder(root->rchild); //递归调用,前序遍历右子树  
    }  
      
    //中序遍历的算法程序  
    void InOrder(BiTNode *root)  
    {  
        if(root==NULL)
            return ;
        InOrder(root->lchild); //递归调用,前序遍历左子树  
        printf("%c ", root->data); //输出数据  
        InOrder(root->rchild); //递归调用,前序遍历右子树  
    }  
      
    //后序遍历的算法程序  
    void PostOrder(BiTNode *root)
    {
        if(root==NULL)
            return ;
        PostOrder(root->lchild);      //递归调用,前序遍历左子树  
        PostOrder(root->rchild);      //递归调用,前序遍历右子树  
        printf("%c ", root->data);    //输出数据    
    }  
      
    /* 
    二叉树的非递归前序遍历,前序遍历思想:先让根进栈,只要栈不为空,就可以做弹出操作, 
    每次弹出一个结点,记得把它的左右结点都进栈,记得右子树先进栈,这样可以保证右子树在栈中总处于左子树的下面。 
    */  
    void PreOrder_Nonrecursive(BiTree T)     //先序遍历的非递归    
    {  
        if(!T)    
            return ;    
        
        stack<BiTree> s;  
        s.push(T);  
      
        while(!s.empty())  
        {  
            BiTree temp = s.top();  
            cout<<temp->data<<" ";  
            s.pop();  
            if(temp->rchild)  
                s.push(temp->rchild);  
            if(temp->lchild)  
                s.push(temp->lchild);  
        }  
    }  
    
    void PreOrder_Nonrecursive1(BiTree T)     //先序遍历的非递归 
    {
        if(!T)  
            return ;
        stack<BiTree> s;
        BiTree curr = T;
        while(curr != NULL || !s.empty())
        {
            while(curr != NULL)
            {
                cout<<curr->data<<"  ";
                s.push(curr);
                curr = curr->lchild;
            }
            if(!s.empty())
            {
                curr = s.top();
                s.pop();
                curr = curr->rchild;
            }
        }
    }
    
    void PreOrder_Nonrecursive2(BiTree T)     //先序遍历的非递归  
    {  
        if(!T)
            return ;  
      
        stack<BiTree> s;  
        while(T)          // 左子树上的节点全部压入到栈中  
        {  
            s.push(T);  
            cout<<T->data<<"  ";  
            T = T->lchild;  
        }  
          
        while(!s.empty())  
        {          
            BiTree temp = s.top()->rchild;  // 栈顶元素的右子树  
            s.pop();                        // 弹出栈顶元素  
            while(temp)          // 栈顶元素存在右子树,则对右子树同样遍历到最下方  
            {  
                cout<<temp->data<<"  ";  
                s.push(temp);  
                temp = temp->lchild;  
            }  
        }  
    }  
    
    void InOrderTraverse1(BiTree T)   // 中序遍历的非递归  
    {  
        if(!T)  
            return ;  
        BiTree curr = T;    // 指向当前要检查的节点  
        stack<BiTree> s;
        while(curr != NULL || !s.empty())
        {
            while(curr != NULL)
            {
                s.push(curr);
                curr = curr->lchild;
            }//while
            if(!s.empty())
            {
                curr = s.top();
                s.pop();
                cout<<curr->data<<"  ";
                curr = curr->rchild;
            }
        }
    }
    
    void InOrderTraverse(BiTree T)   // 中序遍历的非递归  
    {  
        if(!T)  
            return ;  
        stack<BiTree> s;  
        BiTree curr = T->lchild;    // 指向当前要检查的节点  
        s.push(T);  
        while(curr != NULL || !s.empty())  
        {  
            while(curr != NULL)    // 一直向左走  
            {  
                s.push(curr);  
                curr = curr->lchild;  
            }  
            curr = s.top();  
            s.pop();  
            cout<<curr->data<<"  ";  
            curr = curr->rchild;  
        }  
    }  
    
    void PostOrder_Nonrecursive1(BiTree T)  // 后序遍历的非递归    
    {    
        stack<BiTree> S;    
        BiTree curr = T ;           // 指向当前要检查的节点  
        BiTree previsited = NULL;    // 指向前一个被访问的节点  
        while(curr != NULL || !S.empty())  // 栈空时结束    
        {    
            while(curr != NULL)            // 一直向左走直到为空  
            {    
                S.push(curr);    
                curr = curr->lchild;    
            }    
            curr = S.top();  
            // 当前节点的右孩子如果为空或者已经被访问,则访问当前节点  
            if(curr->rchild == NULL || curr->rchild == previsited)    
            {    
                cout<<curr->data<<"  ";    
                previsited = curr;    
                S.pop();    
                curr = NULL;    
            }    
            else  
                curr = curr->rchild;      // 否则访问右孩子  
        }    
    }   
      
    void PostOrder_Nonrecursive(BiTree T)  // 后序遍历的非递归     双栈法  
    {    
        stack<BiTree> s1 , s2;    
        BiTree curr ;           // 指向当前要检查的节点  
        s1.push(T);  
        while(!s1.empty())  // 栈空时结束    
        {  
            curr = s1.top();  
            s1.pop();  
            s2.push(curr);  
            if(curr->lchild)  
                s1.push(curr->lchild);  
            if(curr->rchild)  
                s1.push(curr->rchild);  
        }  
        while(!s2.empty())  
        {  
            printf("%c ", s2.top()->data);  
            s2.pop();  
        }  
    }  
      
      
    int visit(BiTree T)  
    {  
        if(T)  
        {  
            printf("%c ",T->data);  
            return 1;  
        }  
        else  
            return 0;  
    }  
      
    void LeverTraverse(BiTree T)   //方法一、非递归层次遍历二叉树   
    {  
        queue <BiTree> Q;  
        BiTree p;  
        p = T;  
        if(visit(p)==1)  
            Q.push(p);  
        while(!Q.empty())  
        {  
            p = Q.front();  
            Q.pop();  
            if(visit(p->lchild) == 1)   
                Q.push(p->lchild);  
            if(visit(p->rchild) == 1)  
                Q.push(p->rchild);  
        }  
    }  
    void LevelOrder(BiTree BT)     //方法二、非递归层次遍历二叉树   
    {  
        BiTNode *queue[10];//定义队列有十个空间  
        if (BT==NULL)  
            return;  
        int front,rear;  
        front=rear=0;  
        queue[rear++]=BT;  
        while(front!=rear)//如果队尾指针不等于对头指针时  
        {  
            cout<<queue[front]->data<<"  ";  //输出遍历结果  
            if(queue[front]->lchild!=NULL)  //将队首结点的左孩子指针入队列  
            {  
                queue[rear]=queue[front]->lchild;  
                rear++;    //队尾指针后移一位  
            }  
            if(queue[front]->rchild!=NULL)  
            {  
                queue[rear]=queue[front]->rchild;    //将队首结点的右孩子指针入队列  
                rear++;   //队尾指针后移一位  
            }  
            front++;    //对头指针后移一位  
        }  
    }  
      
    int depth(BiTNode *T)   //树的深度  
    {  
        if(!T)  
            return 0;  
        int d1,d2;  
        d1=depth(T->lchild);  
        d2=depth(T->rchild);  
        return (d1>d2?d1:d2)+1;  
        //return (depth(T->lchild)>depth(T->rchild)?depth(T->lchild):depth(T->rchild))+1;  
    }  
    int CountNode(BiTNode *T)  
    {  
        if(T == NULL)  
            return 0;  
        return 1+CountNode(T->lchild)+CountNode(T->rchild);  
    }  
      
    int main(void)  
    {  
        BiTNode *root=NULL; //定义一个根结点  
        int flag=1,k;  
        printf("                     本程序实现二叉树的基本操作。
    ");  
        printf("可以进行建立二叉树,递归先序、中序、后序遍历,非递归先序、中序遍历及非递归层序遍历等操作。
    ");  
      
        while(flag)  
        {  
            printf("
    ");  
            printf("|--------------------------------------------------------------|
    ");  
            printf("|                    二叉树的基本操作如下:                     |
    ");  
            printf("|                        0.创建二叉树                          |
    ");  
            printf("|                        1.递归先序遍历                        |
    ");  
            printf("|                        2.递归中序遍历                        |
    ");  
            printf("|                        3.递归后序遍历                        |
    ");  
            printf("|                        4.非递归先序遍历                      |
    ");  
            printf("|                        5.非递归中序遍历                      |
    ");  
            printf("|                        6.非递归后序遍历                      |
    ");  
            printf("|                        7.非递归层序遍历                      |
    ");  
            printf("|                        8.二叉树的深度                        |
    ");  
            printf("|                        9.二叉树的结点个数                    |
    ");  
            printf("|                        10.退出程序                            |
    ");  
            printf("|--------------------------------------------------------------|
    ");  
            printf("                        请选择功能:");  
            scanf("%d",&k);  
            switch(k)  
            {  
            case 0:  
                printf("请建立二叉树并输入二叉树的根节点:");  
                CreateBiTree(&root);  
                break;  
            case 1:  
                if(root)  
                {  
                    printf("递归先序遍历二叉树的结果为:");  
                    PreOrder(root);  
                    printf("
    ");  
                }  
                else  
                    printf("          二叉树为空!
    ");  
                break;  
            case 2:  
                if(root)  
                {  
                    printf("递归中序遍历二叉树的结果为:");  
                    InOrder(root);  
                    printf("
    ");  
                }  
                else  
                    printf("          二叉树为空!
    ");  
                break;  
            case 3:  
                if(root)  
                {  
                    printf("递归后序遍历二叉树的结果为:");  
                    PostOrder(root);  
                    printf("
    ");  
                }  
                else  
                    printf("          二叉树为空!
    ");  
                break;  
            case 4:  
                if(root)  
                {  
                    printf("非递归先序遍历二叉树:");  
                    PreOrder_Nonrecursive1(root);  
                    printf("
    ");  
                }  
                else  
                    printf("          二叉树为空!
    ");  
                break;  
            case 5:  
                if(root)  
                {  
                    printf("非递归中序遍历二叉树:");  
                    InOrderTraverse1(root);  
                    printf("
    ");  
                }  
                else  
                    printf("          二叉树为空!
    ");  
                break;  
            case 6:  
                if(root)  
                {  
                    printf("非递归后序遍历二叉树:");  
                    PostOrder_Nonrecursive(root);  
                    printf("
    ");  
                }  
                else  
                    printf("          二叉树为空!
    ");  
                break;  
            case 7:  
                if(root)  
                {  
                    printf("非递归层序遍历二叉树:");  
                    //LeverTraverse(root);  
                    LevelOrder(root);  
                    printf("
    ");  
                }  
                else  
                    printf("          二叉树为空!
    ");  
                break;  
            case 8:  
                if(root)  
                    printf("这棵二叉树的深度为:%d
    ",depth(root));  
                else  
                    printf("          二叉树为空!
    ");  
                break;  
            case 9:  
                if(root)  
                    printf("这棵二叉树的结点个数为:%d
    ",CountNode(root));  
                else  
                    printf("          二叉树为空!
    ");  
                break;  
            default:  
                flag=0;  
                printf("程序运行结束,按任意键退出!
    ");  
            }  
        }  
        system("pause");  
        return 0;  
    }

    运行效果图如下:

    分别输入:

    1

    2

    4

    #

    #

    5

    #

    #

    3

    6

    #

    #

    7

    #

    就可以构造如下图所示的二叉树了。。

    后序遍历非递归的另外一种写法:

     1 /*
     2 后序遍历由于遍历父节点是在遍历子节点之后,而且左节点和右节点遍历后的行为不一样,
     3 所以需要用变量来记录前一次访问的节点,根据前一次节点和现在的节点的关系来确定具体执行什么操作
     4 */
     5 void Postorder(BiTree T)
     6 {
     7     if(T == NULL)
     8         return ;
     9     stack<BiTree> s;
    10     BiTree prev = NULL , curr = NULL;
    11     s.push(T);
    12     while(!s.empty())
    13     {
    14         curr = s.top();
    15         if(prev == NULL  || prev->lchild == curr || prev->rchild == curr)
    16         {
    17             if(curr->lchild != NULL)
    18                 s.push(curr->lchild);
    19             else if(curr->rchild != NULL)
    20                 s.push(curr->rchild);
    21         }
    22         else if(curr->lchild == prev)
    23         {
    24             if(curr->rchild != NULL)
    25                 s.push(curr->rchild);
    26         }
    27         else
    28         {
    29             cout<<curr->data;
    30             s.pop();
    31         }
    32         prev = curr;
    33     }
    34 }

    输入二叉树中的两个节点,输出这两个结点在树中最低的共同父节点。
    思路:遍历二叉树,找到一条从根节点开始到目的节点的路径,然后在两条路径上查找共同的父节点。

    // 得到一条从根节点开始到目的节点的路径
    bool GetNodePath(TreeNode *pRoot , TreeNode *pNode , vector<TreeNode *> &path)
    {
        if(pRoot == NULL)
            return false;
        if(pRoot == pNode)
            return true;
        else if(GetNodePath(pRoot->lchild , pNode , path) )
        {
            path.push_back(pRoot->lchild);
            return true;
        }
        else if(GetNodePath(pRoot->rchild , pNode , path) )
        {
            path.push_back(pRoot->rchild);
            return true;
        }
        return false;
    }
    TreeNode *GetLastCommonNode(const vector<TreeNode *> &path1 , const vector<TreeNode *> &path2)
    {
        vector<TreeNode *>::const_iterator iter1 = path1.begin();
        vector<TreeNode *>::const_iterator iter2 = path2.begin();
        TreeNode *pLast;
        while(iter1 != path1.end() && iter2 != path2.end() )
        {
            if(*iter1 == *iter2)
                pLast = *iter1;
            else
                break;
            iter1++;
            iter2++;
        }
        return pLast;
    }
    TreeNode *GetLastCommonParent(TreeNode *pRoot , TreeNode *pNode1 , TreeNode *pNode2)
    {
        if(pRoot == NULL || pNode1 == NULL || pNode2 == NULL)
            return  NULL;
        vector<TreeNode *> path1;
        GetNodePath(pRoot , pNode1 , path1);
    
        vector<TreeNode *> path2;
        GetNodePath(pRoot , pNode2 , path2);
        return GetLastCommonNode(path1 , path2);
    }
  • 相关阅读:
    解决 搭建Jekins过程中 启动Tomcat的java.net.UnknownHostException异常
    射手和农场主
    java 和 JS(javaScript)中的反斜杠正则转义
    分享修改密码的SharePoint Web part: ITaCS Change Password web part
    分享微软官方Demo用的SharePoint 2010, Exchange 2010, Lync 2010虚拟机
    Office 365 的公共网站的一些限制及解决的办法
    SharePoint 2013 关闭 customErrors
    安装 KB2844286 导致SharePoint 2010 XSLT web part 显示出现错误
    安装Office Web Apps Server 2013 – KB2592525安装失败
    如何将hyper-v虚拟机转换成vmware的虚拟机- 转换SharePoint 2010 Information Worker Demonstration and Evaluation Virtual Machine (SP1)
  • 原文地址:https://www.cnblogs.com/zhangbaochong/p/5250301.html
Copyright © 2011-2022 走看看