二叉树的非递归后序遍历算法

转载网址:http://www.cnblogs.com/ybwang/archive/2011/10/04/lastOrderTraverse.html

前序、中序、后序的非递归遍历中,要数后序最为麻烦,如果只在栈中保留指向结点的指针,那是不够的,必须有一些额外的信息存放在栈中。

方法有很多,这里只举一种,先定义栈结点的数据结构
typedef struct{Node * p; int rvisited;}SNode //Node 是二叉树的结点结构,rvisited==1代表p所指向的结点的右结点已被访问过。


lastOrderTraverse(BiTree bt){
  //首先,从根节点开始,往左下方走,一直走到头,将路径上的每一个结点入栈。
  p = bt;
  while(bt){
    push(bt, 0); //push到栈中两个信息,一是结点指针,一是其右结点是否被访问过
    bt = bt.lchild;
  }


  //然后进入循环体
  while(!Stack.empty()){ //只要栈非空
    sn = Stack.getTop(); // sn是栈顶结点


    //注意,任意一个结点N,只要他有左孩子,则在N入栈之后,N的左孩子必然也跟着入栈了(这个体现在算法的后半部分),所以当我们拿到栈顶元素的时候,可以确信这个元素要么没有左孩子,要么其左孩子已经被访问过,所以此时我们就不关心它的左孩子了,我们只关心其右孩子。


    //若其右孩子已经被访问过,或是该元素没有右孩子,则由后序遍历的定义,此时可以visit这个结点了。
    if(!sn.p.rchild || sn.rvisited){
      p = pop();
      visit(p);
    }
    else //若它的右孩子存在且rvisited为0,说明以前还没有动过它的右孩子,于是就去处理一下其右孩子。
    { 
      //此时我们要从其右孩子结点开始一直往左下方走,直至走到尽头,将这条路径上的所有结点都入栈。


      //当然,入栈之前要先将该结点的rvisited设成1,因为其右孩子的入栈意味着它的右孩子必将先于它被访问(这很好理解,因为我们总是从栈顶取出元素来进行visit)。由此可知,下一次该元素再处于栈顶时,其右孩子必然已被visit过了,所以此处可以将rvisited设置为1。
      sn.rvisited = 1;


      //往左下方走到尽头,将路径上所有元素入栈
      p = sn.p.rchild;
      while(p != 0){
        push(p, 0);
        p = p.lchild;
      }
    }//这一轮循环已结束,刚刚入栈的那些结点我们不必管它了,下一轮循环会将这些结点照顾的很好。
  }

}


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

[cpp]  view plain copy
  1. //转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/6583988  
  2. #include<iostream>    
  3. #include<queue>    
  4. #include<stack>    
  5. using namespace std;    
  6.     
  7. //二叉树结点的描述    
  8. typedef struct BiTNode  
  9. {    
  10.     char data;    
  11.     struct BiTNode *lchild, *rchild;      //左右孩子    
  12. }BiTNode,*BiTree;    
  13.     
  14. //按先序遍历创建二叉树    
  15. //BiTree *CreateBiTree()     //返回结点指针类型    
  16. //void CreateBiTree(BiTree &root)      //引用类型的参数    
  17. void CreateBiTree(BiTNode **root)    //二级指针作为函数参数    
  18. {    
  19.     char ch; //要插入的数据    
  20.     scanf("\n%c", &ch);  
  21.     //cin>>ch;    
  22.     if(ch=='#')  
  23.         *root = NULL;  
  24.     else  
  25.     {  
  26.         *root = (BiTNode *)malloc(sizeof(BiTNode));  
  27.         (*root)->data = ch;  
  28.         printf("请输入%c的左孩子:",ch);  
  29.         CreateBiTree(&((*root)->lchild));  
  30.         printf("请输入%c的右孩子:",ch);  
  31.         CreateBiTree(&((*root)->rchild));  
  32.     }  
  33. }  
  34.     
  35. //前序遍历的算法程序    
  36. void PreOrder(BiTNode *root)  
  37. {    
  38.     if(root==NULL)    
  39.         return ;    
  40.     printf("%c ", root->data); //输出数据    
  41.     PreOrder(root->lchild); //递归调用,前序遍历左子树    
  42.     PreOrder(root->rchild); //递归调用,前序遍历右子树    
  43. }    
  44.     
  45. //中序遍历的算法程序    
  46. void InOrder(BiTNode *root)    
  47. {    
  48.     if(root==NULL)  
  49.         return ;  
  50.     InOrder(root->lchild); //递归调用,前序遍历左子树    
  51.     printf("%c ", root->data); //输出数据    
  52.     InOrder(root->rchild); //递归调用,前序遍历右子树    
  53. }    
  54.     
  55. //后序遍历的算法程序    
  56. void PostOrder(BiTNode *root)  
  57. {  
  58.     if(root==NULL)  
  59.         return ;  
  60.     PostOrder(root->lchild);      //递归调用,前序遍历左子树    
  61.     PostOrder(root->rchild);      //递归调用,前序遍历右子树    
  62.     printf("%c ", root->data);    //输出数据      
  63. }    
  64.     
  65. /*  
  66. 二叉树的非递归前序遍历,前序遍历思想:先让根进栈,只要栈不为空,就可以做弹出操作,  
  67. 每次弹出一个结点,记得把它的左右结点都进栈,记得右子树先进栈,这样可以保证右子树在栈中总处于左子树的下面。  
  68. */    
  69. void PreOrder_Nonrecursive(BiTree T)     //先序遍历的非递归      
  70. {    
  71.     if(!T)      
  72.         return ;      
  73.       
  74.     stack<BiTree> s;    
  75.     s.push(T);    
  76.     
  77.     while(!s.empty())    
  78.     {    
  79.         BiTree temp = s.top();    
  80.         cout<<temp->data<<" ";    
  81.         s.pop();    
  82.         if(temp->rchild)    
  83.             s.push(temp->rchild);    
  84.         if(temp->lchild)    
  85.             s.push(temp->lchild);    
  86.     }    
  87. }    
  88.   
  89. void PreOrder_Nonrecursive1(BiTree T)     //先序遍历的非递归   
  90. {  
  91.     if(!T)    
  92.         return ;  
  93.     stack<BiTree> s;  
  94.     BiTree curr = T;  
  95.     while(curr != NULL || !s.empty())  
  96.     {  
  97.         while(curr != NULL)  
  98.         {  
  99.             cout<<curr->data<<"  ";  
  100.             s.push(curr);  
  101.             curr = curr->lchild;  
  102.         }  
  103.         if(!s.empty())  
  104.         {  
  105.             curr = s.top();  
  106.             s.pop();  
  107.             curr = curr->rchild;  
  108.         }  
  109.     }  
  110. }  
  111.   
  112. void PreOrder_Nonrecursive2(BiTree T)     //先序遍历的非递归    
  113. {    
  114.     if(!T)  
  115.         return ;    
  116.     
  117.     stack<BiTree> s;    
  118.     while(T)          // 左子树上的节点全部压入到栈中    
  119.     {    
  120.         s.push(T);    
  121.         cout<<T->data<<"  ";    
  122.         T = T->lchild;    
  123.     }    
  124.         
  125.     while(!s.empty())    
  126.     {            
  127.         BiTree temp = s.top()->rchild;  // 栈顶元素的右子树    
  128.         s.pop();                        // 弹出栈顶元素    
  129.         while(temp)          // 栈顶元素存在右子树,则对右子树同样遍历到最下方    
  130.         {    
  131.             cout<<temp->data<<"  ";    
  132.             s.push(temp);    
  133.             temp = temp->lchild;    
  134.         }    
  135.     }    
  136. }    
  137.   
  138. void InOrderTraverse1(BiTree T)   // 中序遍历的非递归    
  139. {    
  140.     if(!T)    
  141.         return ;    
  142.     BiTree curr = T;    // 指向当前要检查的节点    
  143.     stack<BiTree> s;  
  144.     while(curr != NULL || !s.empty())  
  145.     {  
  146.         while(curr != NULL)  
  147.         {  
  148.             s.push(curr);  
  149.             curr = curr->lchild;  
  150.         }//while  
  151.         if(!s.empty())  
  152.         {  
  153.             curr = s.top();  
  154.             s.pop();  
  155.             cout<<curr->data<<"  ";  
  156.             curr = curr->rchild;  
  157.         }  
  158.     }  
  159. }  
  160.   
  161. void InOrderTraverse(BiTree T)   // 中序遍历的非递归    
  162. {    
  163.     if(!T)    
  164.         return ;    
  165.     stack<BiTree> s;    
  166.     BiTree curr = T->lchild;    // 指向当前要检查的节点    
  167.     s.push(T);    
  168.     while(curr != NULL || !s.empty())    
  169.     {    
  170.         while(curr != NULL)    // 一直向左走    
  171.         {    
  172.             s.push(curr);    
  173.             curr = curr->lchild;    
  174.         }    
  175.         curr = s.top();    
  176.         s.pop();    
  177.         cout<<curr->data<<"  ";    
  178.         curr = curr->rchild;    
  179.     }    
  180. }    
  181.   
  182. void PostOrder_Nonrecursive1(BiTree T)  // 后序遍历的非递归      
  183. {      
  184.     stack<BiTree> S;      
  185.     BiTree curr = T ;           // 指向当前要检查的节点    
  186.     BiTree previsited = NULL;    // 指向前一个被访问的节点    
  187.     while(curr != NULL || !S.empty())  // 栈空时结束      
  188.     {      
  189.         while(curr != NULL)            // 一直向左走直到为空    
  190.         {      
  191.             S.push(curr);      
  192.             curr = curr->lchild;      
  193.         }      
  194.         curr = S.top();    
  195.         // 当前节点的右孩子如果为空或者已经被访问,则访问当前节点    
  196.         if(curr->rchild == NULL || curr->rchild == previsited)      
  197.         {      
  198.             cout<<curr->data<<"  ";      
  199.             previsited = curr;      
  200.             S.pop();      
  201.             curr = NULL;      
  202.         }      
  203.         else    
  204.             curr = curr->rchild;      // 否则访问右孩子    
  205.     }      
  206. }     
  207.     
  208. void PostOrder_Nonrecursive(BiTree T)  // 后序遍历的非递归     双栈法    
  209. {      
  210.     stack<BiTree> s1 , s2;      
  211.     BiTree curr ;           // 指向当前要检查的节点    
  212.     s1.push(T);    
  213.     while(!s1.empty())  // 栈空时结束      
  214.     {    
  215.         curr = s1.top();    
  216.         s1.pop();    
  217.         s2.push(curr);    
  218.         if(curr->lchild)    
  219.             s1.push(curr->lchild);    
  220.         if(curr->rchild)    
  221.             s1.push(curr->rchild);    
  222.     }    
  223.     while(!s2.empty())    
  224.     {    
  225.         printf("%c ", s2.top()->data);    
  226.         s2.pop();    
  227.     }    
  228. }    
  229.     
  230.     
  231. int visit(BiTree T)    
  232. {    
  233.     if(T)    
  234.     {    
  235.         printf("%c ",T->data);    
  236.         return 1;    
  237.     }    
  238.     else    
  239.         return 0;    
  240. }    
  241.     
  242. void LeverTraverse(BiTree T)   //方法一、非递归层次遍历二叉树     
  243. {    
  244.     queue <BiTree> Q;    
  245.     BiTree p;    
  246.     p = T;    
  247.     if(visit(p)==1)    
  248.         Q.push(p);    
  249.     while(!Q.empty())    
  250.     {    
  251.         p = Q.front();    
  252.         Q.pop();    
  253.         if(visit(p->lchild) == 1)     
  254.             Q.push(p->lchild);    
  255.         if(visit(p->rchild) == 1)    
  256.             Q.push(p->rchild);    
  257.     }    
  258. }    
  259. void LevelOrder(BiTree BT)     //方法二、非递归层次遍历二叉树     
  260. {    
  261.     BiTNode *queue[10];//定义队列有十个空间    
  262.     if (BT==NULL)    
  263.         return;    
  264.     int front,rear;    
  265.     front=rear=0;    
  266.     queue[rear++]=BT;    
  267.     while(front!=rear)//如果队尾指针不等于对头指针时    
  268.     {    
  269.         cout<<queue[front]->data<<"  ";  //输出遍历结果    
  270.         if(queue[front]->lchild!=NULL)  //将队首结点的左孩子指针入队列    
  271.         {    
  272.             queue[rear]=queue[front]->lchild;    
  273.             rear++;    //队尾指针后移一位    
  274.         }    
  275.         if(queue[front]->rchild!=NULL)    
  276.         {    
  277.             queue[rear]=queue[front]->rchild;    //将队首结点的右孩子指针入队列    
  278.             rear++;   //队尾指针后移一位    
  279.         }    
  280.         front++;    //对头指针后移一位    
  281.     }    
  282. }    
  283.     
  284. int depth(BiTNode *T)   //树的深度    
  285. {    
  286.     if(!T)    
  287.         return 0;    
  288.     int d1,d2;    
  289.     d1=depth(T->lchild);    
  290.     d2=depth(T->rchild);    
  291.     return (d1>d2?d1:d2)+1;    
  292.     //return (depth(T->lchild)>depth(T->rchild)?depth(T->lchild):depth(T->rchild))+1;    
  293. }    
  294. int CountNode(BiTNode *T)    
  295. {    
  296.     if(T == NULL)    
  297.         return 0;    
  298.     return 1+CountNode(T->lchild)+CountNode(T->rchild);    
  299. }    
  300.     
  301. int main(void)    
  302. {    
  303.     BiTNode *root=NULL; //定义一个根结点    
  304.     int flag=1,k;    
  305.     printf("                     本程序实现二叉树的基本操作。\n");    
  306.     printf("可以进行建立二叉树,递归先序、中序、后序遍历,非递归先序、中序遍历及非递归层序遍历等操作。\n");    
  307.     
  308.     while(flag)    
  309.     {    
  310.         printf("\n");    
  311.         printf("|--------------------------------------------------------------|\n");    
  312.         printf("|                    二叉树的基本操作如下:                     |\n");    
  313.         printf("|                        0.创建二叉树                          |\n");    
  314.         printf("|                        1.递归先序遍历                        |\n");    
  315.         printf("|                        2.递归中序遍历                        |\n");    
  316.         printf("|                        3.递归后序遍历                        |\n");    
  317.         printf("|                        4.非递归先序遍历                      |\n");    
  318.         printf("|                        5.非递归中序遍历                      |\n");    
  319.         printf("|                        6.非递归后序遍历                      |\n");    
  320.         printf("|                        7.非递归层序遍历                      |\n");    
  321.         printf("|                        8.二叉树的深度                        |\n");    
  322.         printf("|                        9.二叉树的结点个数                    |\n");    
  323.         printf("|                        10.退出程序                            |\n");    
  324.         printf("|--------------------------------------------------------------|\n");    
  325.         printf("                        请选择功能:");    
  326.         scanf("%d",&k);    
  327.         switch(k)    
  328.         {    
  329.         case 0:    
  330.             printf("请建立二叉树并输入二叉树的根节点:");    
  331.             CreateBiTree(&root);    
  332.             break;    
  333.         case 1:    
  334.             if(root)    
  335.             {    
  336.                 printf("递归先序遍历二叉树的结果为:");    
  337.                 PreOrder(root);    
  338.                 printf("\n");    
  339.             }    
  340.             else    
  341.                 printf("          二叉树为空!\n");    
  342.             break;    
  343.         case 2:    
  344.             if(root)    
  345.             {    
  346.                 printf("递归中序遍历二叉树的结果为:");    
  347.                 InOrder(root);    
  348.                 printf("\n");    
  349.             }    
  350.             else    
  351.                 printf("          二叉树为空!\n");    
  352.             break;    
  353.         case 3:    
  354.             if(root)    
  355.             {    
  356.                 printf("递归后序遍历二叉树的结果为:");    
  357.                 PostOrder(root);    
  358.                 printf("\n");    
  359.             }    
  360.             else    
  361.                 printf("          二叉树为空!\n");    
  362.             break;    
  363.         case 4:    
  364.             if(root)    
  365.             {    
  366.                 printf("非递归先序遍历二叉树:");    
  367.                 PreOrder_Nonrecursive1(root);    
  368.                 printf("\n");    
  369.             }    
  370.             else    
  371.                 printf("          二叉树为空!\n");    
  372.             break;    
  373.         case 5:    
  374.             if(root)    
  375.             {    
  376.                 printf("非递归中序遍历二叉树:");    
  377.                 InOrderTraverse1(root);    
  378.                 printf("\n");    
  379.             }    
  380.             else    
  381.                 printf("          二叉树为空!\n");    
  382.             break;    
  383.         case 6:    
  384.             if(root)    
  385.             {    
  386.                 printf("非递归后序遍历二叉树:");    
  387.                 PostOrder_Nonrecursive(root);    
  388.                 printf("\n");    
  389.             }    
  390.             else    
  391.                 printf("          二叉树为空!\n");    
  392.             break;    
  393.         case 7:    
  394.             if(root)    
  395.             {    
  396.                 printf("非递归层序遍历二叉树:");    
  397.                 //LeverTraverse(root);    
  398.                 LevelOrder(root);    
  399.                 printf("\n");    
  400.             }    
  401.             else    
  402.                 printf("          二叉树为空!\n");    
  403.             break;    
  404.         case 8:    
  405.             if(root)    
  406.                 printf("这棵二叉树的深度为:%d\n",depth(root));    
  407.             else    
  408.                 printf("          二叉树为空!\n");    
  409.             break;    
  410.         case 9:    
  411.             if(root)    
  412.                 printf("这棵二叉树的结点个数为:%d\n",CountNode(root));    
  413.             else    
  414.                 printf("          二叉树为空!\n");    
  415.             break;    
  416.         default:    
  417.             flag=0;    
  418.             printf("程序运行结束,按任意键退出!\n");    
  419.         }    
  420.     }    
  421.     system("pause");    
  422.     return 0;    
  423. }  


运行效果图如下:

分别输入:

1

2

4

#

#

5

#

#

3

6

#

#

7

#

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

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

[cpp]  view plain copy
  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. }  
输入二叉树中的两个节点,输出这两个结点在树中最低的共同父节点。
思路:遍历二叉树,找到一条从根节点开始到目的节点的路径,然后在两条路径上查找共同的父节点。
[cpp]  view plain copy
  1. // 得到一条从根节点开始到目的节点的路径  
  2. bool GetNodePath(TreeNode *pRoot , TreeNode *pNode , vector<TreeNode *> &path)  
  3. {  
  4.     if(pRoot == NULL)  
  5.         return false;  
  6.     if(pRoot == pNode)  
  7.         return true;  
  8.     else if(GetNodePath(pRoot->lchild , pNode , path) )  
  9.     {  
  10.         path.push_back(pRoot->lchild);  
  11.         return true;  
  12.     }  
  13.     else if(GetNodePath(pRoot->rchild , pNode , path) )  
  14.     {  
  15.         path.push_back(pRoot->rchild);  
  16.         return true;  
  17.     }  
  18.     return false;  
  19. }  
  20. TreeNode *GetLastCommonNode(const vector<TreeNode *> &path1 , const vector<TreeNode *> &path2)  
  21. {  
  22.     vector<TreeNode *>::const_iterator iter1 = path1.begin();  
  23.     vector<TreeNode *>::const_iterator iter2 = path2.begin();  
  24.     TreeNode *pLast;  
  25.     while(iter1 != path1.end() && iter2 != path2.end() )  
  26.     {  
  27.         if(*iter1 == *iter2)  
  28.             pLast = *iter1;  
  29.         else  
  30.             break;  
  31.         iter1++;  
  32.         iter2++;  
  33.     }  
  34.     return pLast;  
  35. }  
  36. TreeNode *GetLastCommonParent(TreeNode *pRoot , TreeNode *pNode1 , TreeNode *pNode2)  
  37. {  
  38.     if(pRoot == NULL || pNode1 == NULL || pNode2 == NULL)  
  39.         return  NULL;  
  40.     vector<TreeNode *> path1;  
  41.     GetNodePath(pRoot , pNode1 , path1);  
  42.   
  43.     vector<TreeNode *> path2;  
  44.     GetNodePath(pRoot , pNode2 , path2);  
  45.     return GetLastCommonNode(path1 , path2);  
  46. }  

转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/6583988


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值