二叉樹和為某種所有路徑

sunmenggmail發表於2012-04-16

題目:輸入一個整數和一棵二元樹。列印出和與輸入整數相等的所有路徑,從樹的根結點開始往下訪問一直到葉結點所經過的所有結點形成一條路徑。

分析:這道題考查對二叉樹遍歷方式的理解,採用後序遍歷,如果把二叉樹看成圖,就是圖的深度遍歷。使用變數存放當前遍歷的路徑和,當訪問到某一結點時,把該結點新增到路徑上,並累加當前結點的值。如果當前結點為葉結點並且當前路徑的和剛好等於輸入的整數,則當前的路徑符合要求,我們把它列印出來。如果當前結點不是葉結點,則繼續訪問它的子結點。當前結點訪問結束後,遞迴函式將自動回到父結點,因此我們在函式退出之前要在路徑上刪除當前結點並減去當前結點的值,以確保返回父結點時路徑剛好是根結點到父結點的路徑。

二元樹結點的資料結構定義為:

  1. struct BSTreeNode  
  2. {  
  3.     struct BSTreeNode()  
  4.     {  
  5.         m_pLeft = NULL;  
  6.         m_pRight = NULL;  
  7.     }  
  8.     int m_nValue;           // value of node  
  9.     BSTreeNode *m_pLeft;    // left child of node  
  10.     BSTreeNode *m_pRight;   // right child of node  
  11. };  

遞迴求解程式碼如下:

  1. ///////////////////////////////////////////////////////////////////////  
  2. // Find paths whose sum equal to expected sum  
  3. ///////////////////////////////////////////////////////////////////////  
  4. void FindPath  
  5. (  
  6.  BSTreeNode*        pTreeNode,      // a node of binary tree  
  7.  int                expectedSum,    // the expected sum  
  8.  std::vector<int>&  path,           // a path from root to current node  
  9.  int&               currentSum      // the sum of path  
  10.  )  
  11. {  
  12.     if(!pTreeNode)  
  13.         return;  
  14.   
  15.     currentSum += pTreeNode->m_nValue;  
  16.     path.push_back(pTreeNode->m_nValue);  
  17.   
  18.     // if the node is a leaf, and the sum is same as pre-defined,  
  19.     // the path is what we want. print the path  
  20.     bool isLeaf = (!pTreeNode->m_pLeft && !pTreeNode->m_pRight);  
  21.     if(currentSum == expectedSum && isLeaf)  
  22.     {  
  23.         std::vector<int>::iterator iter = path.begin();  
  24.         for(; iter != path.end(); ++ iter)  
  25.             printf("%d\t",*iter);  
  26.         printf("\n");  
  27.     }  
  28.   
  29.     // if the node is not a leaf, goto its children  
  30.     if(pTreeNode->m_pLeft)  
  31.         FindPath(pTreeNode->m_pLeft, expectedSum, path, currentSum);  
  32.     if(pTreeNode->m_pRight)  
  33.         FindPath(pTreeNode->m_pRight, expectedSum, path, currentSum);  
  34.   
  35.     // when we finish visiting a node and return to its parent node,  
  36.     // we should delete this node from the path and  
  37.     // minus the node's value from the current sum  
  38.     currentSum -= pTreeNode->m_nValue;//我認為沒有必要傳currentSum的引用,所以在這裡也不需要減  
  39.     path.pop_back();  
  40. }  
  41. </int></int>  

擴充套件題:如果將條件放寬,計算和的路徑改為從根節點到葉子節點路徑上任意連續子路徑呢?
條件改變之後,難度有所增加,堆疊中光存放從root到當前節點的和顯然不夠,需要對堆疊中的元素做出改變,使之存放堆疊當前位置到當前遍歷節點的路徑和,元素型別定義如下:

  1. class StackElement  
  2. {  
  3. public:  
  4.     StackElement(struct BSTreeNode* node, int s){pNode = node;sum = s;};  
  5.   
  6.     void AddValue(int v){sum+=v;}  
  7.     int GetValue(){return sum;}  
  8.   
  9.     struct BSTreeNode* pNode;   //二叉樹節點指標,由於不採用遞迴,因此必須保持節點指標  
  10.     int sum;                    //從當前遍歷節點到*pNode這段路徑的和  
  11. };  

在這裡不適用遞迴,而採用另外的一種求解方式。

  1. void BSTreeSumWay(struct BSTreeNode* root,int sum)  
  2. {  
  3.     assert(root);  
  4.   
  5.     vector<stackelement> way;  
  6.   
  7.     while (root || !way.empty())  
  8.     {  
  9.         while(root)  
  10.         {  
  11.   
  12.             StackElement temp(root,0);  
  13.             way.push_back(temp);  
  14.   
  15.             //路徑上增加了root,因此從way_iter->pNode到*root的路徑sum要更新  
  16.             vector<stackelement>::iterator way_iter = way.begin();  
  17.             for (;way_iter != way.end(); way_iter++)  
  18.             {  
  19.                 way_iter->AddValue(root->m_nValue);  
  20.                 if (sum == way_iter->GetValue())  
  21.                 {  
  22.                     //列印路徑  
  23.                     vector<stackelement>::iterator print_iter = way_iter;  
  24.                     for (;print_iter != way.end();print_iter++)  
  25.                     {  
  26.                         printf("%d\t",print_iter->pNode->m_nValue);  
  27.                     }  
  28.                     printf("\n");  
  29.                 }  
  30.             }  
  31.   
  32.             root = root->m_pLeft;  
  33.         }  
  34.   
  35.         //右子樹為空或者剛從右子樹返回  
  36.         while (way.rbegin()->pNode->m_pRight==NULL || root==way.rbegin()->pNode->m_pRight)  
  37.         {  
  38.   
  39.             root = way.rbegin()->pNode;  
  40.   
  41.             //路徑上減少了最後一個節點,因此路徑sum要更新  
  42.             int v = -way.rbegin()->pNode->m_nValue;  
  43.             way.pop_back();  
  44.             vector<stackelement>::iterator way_iter = way.begin();  
  45.             for (;way_iter != way.end(); way_iter++)  
  46.             {  
  47.                 way_iter->AddValue(v);  
  48.             }  
  49.   
  50.             if (way.empty())  
  51.             {  
  52.                 break;  
  53.             }  
  54.   
  55.         }  
  56.   
  57.         if (way.empty())  
  58.             break;  
  59.   
  60.         root = way.rbegin()->pNode->m_pRight;  
  61.   
  62.     }  
  63.   
  64. }  
  65. </stackelement></stackelement></stackelement></stackelement>  

網路轉載請註明:轉載自程式設計師面試之家


相關文章