二叉树和为某种所有路径

题目:输入一个整数和一棵二元树。打印出和与输入整数相等的所有路径,从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。

分析:这道题考查对二叉树遍历方式的理解,采用后序遍历,如果把二叉树看成图,就是图的深度遍历。使用变量存放当前遍历的路径和,当访问到某一结点时,把该结点添加到路径上,并累加当前结点的值。如果当前结点为叶结点并且当前路径的和刚好等于输入的整数,则当前的路径符合要求,我们把它打印出来。如果当前结点不是叶结点,则继续访问它的子结点。当前结点访问结束后,递归函数将自动回到父结点,因此我们在函数退出之前要在路径上删除当前结点并减去当前结点的值,以确保返回父结点时路径刚好是根结点到父结点的路径。

二元树结点的数据结构定义为:

  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>  

网络转载请注明:转载自程序员面试之家


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值