题目描述:输入一棵二叉树和一个整数(假如为N),打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶子节点所经过的节点形成一条路径。
例如 输入整数22和如下二元树
10
/ \
5 12
/ \
4 7
则打印出两条路径:10, 12和10, 5, 7。
分析与解法:
使用前序遍历,因为要求所有的满足条件的路径,必须遍历完整棵树。我们使用vector容器来保存路径,维护保存路径和的变量curSum,第一次遍历到一个节点就加入vector,curSum加上当前节点的值,如果当前curSum大于等于指定的N,并且当前节点不是叶子节点,那么要调用pop_back。我们还需要更深入的考虑一下退出条件,发现只要从一个节点的左右子树返回,就要弹出节点,因为前序遍历当中,一个节点的左右子树返回意味着经过当前节点的所有路径我们都遍历过了,所以自然要pop_back当前节点。比如10->5->4,当前和不满足条件,我们要回退,这个时候要pop_back弹出4。然后进入5的右子树,找到10->5->7满足条件,回退的时候我们要pop_back弹出7。由于5的左右子树全都返回,所以我们也要pop_back弹出5。
输出条件:路径和满足条件,并且是叶子节点。
另外再分析下curSum是要定义为局部变量还是放到参数里面。因为更深层次的子树需要知道这个值,所以放到参数里面。定义为int类型还是int&(c里面当然用int*代替啦)类型?其实无所谓,这个对算法正确性没有影响。
根据上述分析,代码如下:
struct Node
{
Node* m_pLeft;
Node* m_pRight;
int m_value;
};
void allPath(Node *pRoot,vector<int>& v,int curSum,int expectedSum)
{
if(pRoot==NULL)
{
return;
}
v.push_back(pRoot->m_value);
curSum+=pRoot->m_value;
//当前路径和大于等于指定值,且不是叶子节点
if(curSum>=expectedSum && (pRoot->m_pLeft || pRoot->m_pRight))
{
v.pop_back();
curSum-=pRoot->m_value;
}
//输出条件
if(curSum==expectedSum && pRoot->m_pLeft==NULL && pRoot->m_pRight==NULL)
{
for(int i=0;i<v.size();i++)
cout<<v[i]<<" ";
cout<<endl;
}
//if判定条件可以不加,加上只是少一层递归而已,当然最好加上啦
if(pRoot->m_pLeft)
allPath(pRoot->m_pLeft,v,curSum,expectedSum);
if(pRoot->m_pRight);
allPath(pRoot->m_pRight,v,curSum,expectedSum);
v.pop_back();
curSum-=pRoot->m_value;
}