题目:输入一个整数和一棵二元树。从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。打印出和与输入整数相等的所有路径。
例如输入整数22和如下二元树
10
/ \
5 12
/ \
4 7
则打印出两条路径:10, 12和10, 5, 7。
二元树结点的数据结构定义为:
struct BinaryTreeNode // a node in the binary tree
{
int m_nValue; // value of node
BinaryTreeNode *m_pLeft; // left child of node
BinaryTreeNode *m_pRight; // right child of node
};
分析:这是百度的一道笔试题,考查对树这种基本数据结构以及递归函数的理解。
前序遍历访问这个二叉树,访问到某一节点时,把该节点添加到路径上,并保存该节点的值。
如果该节点为叶子节点,并且路径中节点值之和刚好等于 输入的整数,则当前路径符合要求,打印之;
如果当前节点不是叶子节点,则继续访问他的子节点。
当前节点访问结束后,递归函数需要自动回到他的父节点。
因此,在函数退出之前要在路径上删除当前节点,并减去当前节点的值,以确保返回父节点时路径刚好是从根节点到父节点的路径。
保存路径使用栈,因为路径要与递归调用一致。(递归调用本身是一个压栈和出栈的过程)
<pre name="code" class="cpp">struct binaryTree {
int value;
binaryTree *left;
binaryTree *right;
};
void findPath(binaryTree *root, int expectedSum, vector<int> &path, int currentSum) {
currentSum += root->value;
path.push_back(root->value);
// 如果expectedSum等于路径中记录的值,且当前节点是叶子节点,则找到该路径
bool isLeaf = root->left == NULL && root->right == NULL;
if(currentSum == expectedSum && isLeaf) {
cout << "the path has been found: "<< endl;
vector<int>::iterator iter = path.begin();
for(; iter != path.end(); iter ++) {
cout << *iter << "\t";
}
cout << endl;
}
// 如果不是叶子节点,则遍历其左右孩子
if(root->left != NULL)
findPath(root->left, expectedSum, path, currentSum);
if(root->right != NULL)
findPath(root->right, expectedSum, path, currentSum);
// 返回到父节点时,在路径上删除当前节点
currentSum -= root->value;<span style="color:#ff0000;">// 这句话让我很纳闷,我在vc上单步调试的时候, 不写这句话,也会currentSum也会减,不解</span>
path.pop_back();
}
void find(binaryTree *root, int expectedSum) {
if(root == NULL)
return;
vector<int> path;
int currentSum = 0;
findPath(root, expectedSum, path, currentSum);
}