二叉樹遍歷(前中後層序/非遞歸)

一:前中後序遞歸實現
  1. /* 
  2. 前中後序的遞歸實現理解起來最爲簡單,要點在於visit(node)的位置。 
  3. */  
  4. /* 
  5. 前中後序遞歸實現 
  6. */  
  7. //前序遍歷  
  8. void BT_PreOrder(BitTree node)  
  9. {  
  10.     if(!node) return;  
  11.   
  12.     visit(node);  
  13.     BT_PreOrder(node->left);  
  14.     BT_PreOrder(node->right);  
  15. }  
  16.   
  17. //中序遍歷  
  18. void BT_InOrder(BitTree node)  
  19. {  
  20.     if(!node) return;  
  21.   
  22.     BT_PreOrder(node->left);  
  23.     visit(node);  
  24.     BT_PreOrder(node->right);  
  25. }  
  26.   
  27. //中序遍歷  
  28. void BT_PostOrder(BitTree node)  
  29. {  
  30.     if(!node) return;  
  31.   
  32.     BT_PreOrder(node->left);  
  33.     BT_PreOrder(node->right);  
  34.     visit(node);  
  35. }  



二:層序遞歸實現
  1. /* 
  2. 層序遍歷 
  3. 這種方式用隊列來實現,也是最容易理解的方式,思路如下: 
  4. 按照層序遍歷的定義,訪問完當前節點之後,則當前節點的左子節點具備了倒數第二優先級,當前節點的右子節點具備了倒數第一優先級,利用隊列先進先出的特性(可以確定最低的優先級),可以實現。 
  5. */  
  6. void BT_LevelOrder(BitTree node)  
  7. {  
  8.     if(!node) return;  
  9.   
  10.     queue<BitTree> q;  
  11.     q.push(node);  
  12.   
  13.     BitTree pvNode;  
  14.     while(!q.empty())  
  15.     {  
  16.         pvNode = q.pop();  
  17.         visit(pvNode);  
  18.   
  19.         if(!pvNode->left) q.push(pvNode->left);  
  20.         if(!pvNode->right) q.push(pvNode->right);  
  21.     }  
  22. }  




三:前序非遞歸實現
  1. /* 
  2. 前序遍歷非遞歸實現1 
  3. 這種方式用棧來實現,也是最容易理解的方式,思路如下: 
  4. 按照前序遍歷的定義,訪問完當前節點之後,則當前節點的左子節點具備了第一優先級,當前節點的右子節點具備了第二優先級, 
  5. 利用棧後進先出的特性(可以確定最高的優先級),可以實現。 
  6. */  
  7. void BT_PreOrderNoRec(BitTree node)  
  8. {  
  9.     if(!node) return;  
  10.   
  11.     stack<BitTree> s;  
  12.     BitTree pvNode;  
  13.     s.push(node);  
  14.     while(!s.empty())  
  15.     {  
  16.         pvNode = s.pop();  
  17.         visit(pvNode);  
  18.   
  19.         if(!pvNode->right) s.push(pvNode->right);  
  20.         if(!pvNode->left)  s.push(pvNode->left);  
  21.     }  
  22. }  
  23.   
  24. /* 
  25. 前序遍歷非遞歸實現2 
  26. 在網上看到的一種寫法,個人覺得不如第一種實現起來更易懂 
  27. */  
  28. void BT_PreOrderNoRec2(BitTree node)  
  29. {  
  30.     if(!node) return;  
  31.   
  32.     stack<BitTree> s;  
  33.     while(!node && !s.empty())  
  34.     {  
  35.         /*如果當前節點不爲空,則直接訪問,然後將節點存儲到棧中(僅僅用來將來尋找右子節點),然後當前節點變爲左字節點*/  
  36.         if(node)  
  37.         {  
  38.             visit(node);  
  39.             s.push(node);  
  40.             node = node->left;  
  41.         }  
  42.         /*如果當前節點爲空,則到棧中取出上一個節點,並找出右子節點進行訪問*/  
  43.         else  
  44.         {  
  45.             node = s.pop();  
  46.             node = s.right;  
  47.         }  
  48.     }  
  49. }  



四:中序非遞歸

  1. /* 
  2. 中序遍歷非遞歸實現 
  3. 用棧來實現,這種方式可以用遞歸的思路來理解 
  4. */  
  5. void BT_InOrderNoRec(BitTree node)  
  6. {  
  7.     if(!node) return;  
  8.   
  9.     stack<BitTree> s;  
  10.     while(!s.empty())  
  11.     {  
  12.         /*如果當前節點不爲空,則不訪問,而是將它放入棧中,然後當前節點變爲左字節點; 
  13.           一直採取這種方式,根據棧先進後出的特點,將來訪問的時候左字節點在前,當前節點在後; 
  14.           正好是中序遍歷的特性 
  15.         */  
  16.         if(!node)  
  17.         {  
  18.             push(node);  
  19.             node = node->left();  
  20.         }  
  21.         /*如果當前節點爲空,則去棧裏取出節點訪問,然後訪問右子節點。 
  22.           這裏有些不好理解,其實這裏的開端是左字節點爲空了,所以訪問了當前節點,然後右子節點; 
  23.           同時當前節點爲根的二叉樹其實是上層的左字節點,依次類推正好是中序遍歷的特性 
  24.         */  
  25.         else  
  26.         {  
  27.             node = s.pop();  
  28.             visit(node);  
  29.             node = node->right;  
  30.         }  
  31.     }  
  32. }  



五:後序非遞歸

  1. /* 
  2. 後序遍歷非遞歸實現 
  3. 用棧來實現,不是很好理解,但是起碼不用藉助各種標誌位 
  4. 思路如註釋所寫 
  5. */  
  6. void BT_PostOrderNoRec(BitTree node)  
  7. {  
  8.     if(!node) return;  
  9.   
  10.     stack<BitTree> s;  
  11.     BitTree tmp;//用來標誌剛剛訪問過的節點  
  12.     while(!node && !s.empty())  
  13.     {  
  14.         //如果當前節點不爲空,則壓入棧,當前節點變爲左字節點  
  15.         if(node)  
  16.         {  
  17.             s.push(node);  
  18.             node = node->left;  
  19.         }  
  20.         //如果爲空,則需要根據棧頂的節點來判定下一步  
  21.         else  
  22.         {  
  23.             //獲取棧頂節點,不是pop  
  24.             node = s.getPop();  
  25.             //如果棧頂節點有右子節點,並且(這不好理解,但很重要)右子節點不是我們剛剛訪問過的,  
  26.             //則,我們要去右子樹訪問  
  27.             if(node->right && node->right != tmp)  
  28.             {  
  29.                 //把右子樹當作一個新的開始進行訪問:根節點壓入棧,訪問左字節點  
  30.                 s.push(node->right);  
  31.                 node = node->right->left;  
  32.             }  
  33.             //如果棧頂節點沒有右子節點,或者我們剛剛訪問過右子節點,則達到後序遍歷的要求,我們可以訪問當前節點  
  34.             else  
  35.             {  
  36.                 //訪問當前節點,設置標誌節點(tmp)爲當前節點,當前節點置爲空  
  37.                 node = s.pop();  
  38.                 visit(node);  
  39.                 tmp = node;  
  40.                 node = null;  
  41.             }  
  42.         }  
  43.     }  
  44. }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章