遍历二叉树的各种操作(递归与非递归遍历)

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

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

运行效果图如下:

分别输入:

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. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值