二叉樹的各種操作_源代碼

先使用先序的方法建立一棵二叉樹,然後分別使用遞歸與非遞歸的方法實現前序、中序、後序遍歷二叉樹,並使用了兩種方法來進行層次遍歷二叉樹,一種方法就是使用STL中的queue,另外一種方法就是定義了一個數組隊列,分別使用了front和rear兩個數組的下標來表示入隊與出隊,還有兩個操作就是求二叉樹的深度、結點數。。。
  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

#

就可以構造如下圖所示的二叉樹了。。

後序遍歷非遞歸的另外一種寫法:

  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. }  
輸入二叉樹中的兩個節點,輸出這兩個結點在數中最低的共同父節點。
思路:遍歷二叉樹,找到一條從根節點開始到目的節點的路徑,然後在兩條路徑上查找共同的父節點。
  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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章