找出二叉树中和为某一值的所有路径

转自:http://s.sousb.com/2011/04/06/%e6%89%be%e5%87%ba%e4%ba%8c%e5%8f%89%e6%a0%91%e4%b8%ad%e5%92%8c%e4%b8%ba%e6%9f%90%e4%b8%80%e5%80%bc%e7%9a%84%e6%89%80%e6%9c%89%e8%b7%af%e5%be%84/

 

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

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

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

  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. };  
struct BSTreeNode
{
	struct BSTreeNode()
	{
		m_pLeft = NULL;
		m_pRight = NULL;
	}
	int m_nValue;			// value of node
	BSTreeNode *m_pLeft;	// left child of node
	BSTreeNode *m_pRight;	// right child of node
};

递归求解代码如下:

  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;   
  39.     path.pop_back();   
  40. }  
///////////////////////////////////////////////////////////////////////
// Find paths whose sum equal to expected sum
///////////////////////////////////////////////////////////////////////
void FindPath
(
 BSTreeNode*		pTreeNode,		// a node of binary tree
 int				expectedSum,	// the expected sum
 std::vector&	path,			// a path from root to current node
 int&				currentSum		// the sum of path
 )
{
	if(!pTreeNode)
		return;

	currentSum += pTreeNode->m_nValue;
	path.push_back(pTreeNode->m_nValue);

	// if the node is a leaf, and the sum is same as pre-defined,
	// the path is what we want. print the path
	bool isLeaf = (!pTreeNode->m_pLeft && !pTreeNode->m_pRight);
	if(currentSum == expectedSum && isLeaf)
	{
		std::vector::iterator iter = path.begin();
		for(; iter != path.end(); ++ iter)
			printf("%d\t",*iter);
		printf("\n");
	}

	// if the node is not a leaf, goto its children
	if(pTreeNode->m_pLeft)
		FindPath(pTreeNode->m_pLeft, expectedSum, path, currentSum);
	if(pTreeNode->m_pRight)
		FindPath(pTreeNode->m_pRight, expectedSum, path, currentSum);

	// when we finish visiting a node and return to its parent node,
	// we should delete this node from the path and
	// minus the node's value from the current sum
	currentSum -= pTreeNode->m_nValue;
	path.pop_back();
}

扩展题:如果将条件放宽,计算和的路径改为从根节点到叶子节点路径上任意连续子路径呢?
条件改变之后,难度有所增加,堆栈中光存放从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. };  
class StackElement
{
public:
	StackElement(struct BSTreeNode* node, int s){pNode = node;sum = s;};

	void AddValue(int v){sum+=v;}
	int GetValue(){return sum;}

	struct BSTreeNode* pNode;	//二叉树节点指针,由于不采用递归,因此必须保持节点指针
	int sum;					//从当前遍历节点到*pNode这段路径的和
};

在这里不适用递归,而采用另外的一种求解方式。

  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. }  
void BSTreeSumWay(struct BSTreeNode* root,int sum)
{
	assert(root);

	vector way;

	while (root || !way.empty())
	{
		while(root)
		{

			StackElement temp(root,0);
			way.push_back(temp);

			//路径上增加了root,因此从way_iter->pNode到*root的路径sum要更新
			vector::iterator way_iter = way.begin();
			for (;way_iter != way.end(); way_iter++)
			{
				way_iter->AddValue(root->m_nValue);
				if (sum == way_iter->GetValue())
				{
					//打印路径
					vector::iterator print_iter = way_iter;
					for (;print_iter != way.end();print_iter++)
					{
						printf("%d\t",print_iter->pNode->m_nValue);
					}
					printf("\n");
				}
			}

			root = root->m_pLeft;
		}

		//右子树为空或者刚从右子树返回
		while (way.rbegin()->pNode->m_pRight==NULL || root==way.rbegin()->pNode->m_pRight)
		{

			root = way.rbegin()->pNode;

			//路径上减少了最后一个节点,因此路径sum要更新
			int v = -way.rbegin()->pNode->m_nValue;
			way.pop_back();
			vector::iterator way_iter = way.begin();
			for (;way_iter != way.end(); way_iter++)
			{
				way_iter->AddValue(v);
			}

			if (way.empty())
			{
				break;
			}

		}

		if (way.empty())
			break;

		root = way.rbegin()->pNode->m_pRight;

	}

}

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

并注明本文链接地址: 找出二叉树中和为某一值的所有路径

 
posted @ 2012-10-19 10:22  技术收集专用  阅读(1238)  评论(0编辑  收藏  举报