第一道题目是找出从二叉树中从根到某一结点的路径。
在一棵任意的二叉树(并非一定是二叉排序树)查找某一个结点,按照先序遍历去查找,如果要查找的结点就是根结点,那么返回;否则从左子树中查找,如果左子树中找到的话,就不去右子树中查找,如果查找不到的话,再去右子树中查找。
因此,我使用了一个bool返回值来判断是否查找成功。所以在查找过程中,检查子树的查找返回值,如果返回真找到了,那么直接返回,不继续查找。
其次,如果没有查找成功的话,需要将当前结点从路径向量中删除。没有查找成功的情况在最后处理,如果查找成功了就不会走到程序的最后部分。
上代码:
/*
* 获取树中从根到某个结点的路径
*/
bool GetPath(BiTree T, BiTNode *node, vector<BiTNode*> &pathVec)
{
if(!T)
return false;
//将当前结点添加入路径向量
pathVec.push_back(T);
//如果查找到了,就直接返回
if(T == node){
return true;
}
//如果node在左子树中被找到,直接返回。
if(T->lchild){
if(GetPath(T->lchild, node, pathVec))
{
return true;
}
}
//如果node在右子树中被找到,直接返回。
if(T->rchild){
if(GetPath(T->rchild, node, pathVec))
{
return true;
}
}
//该结点T和T的左右子树中都没有找到node,则将T从路径向量中删除
pathVec.pop_back();
return false;
}
编程之美3.8最后的总结提到,“在递归的实现中,往往需要假设后续的调用已经完成,在此基础之上,才实现递归的逻辑”。所以在程序的最后删除当前结点时,假设从当前结点和结点的左右子树中已经查找完node,并且没有找到。
第二道题是打印二叉树中从根结点到叶结点的路径上和为某值的路径。
这道题要查找二叉树中所有的结点,不存在找到一条路径就不继续下去的情况。代码来自剑指offer:
/*
* 面试题25 我们使用了vec和currentSum的引用,所有需要每次返回前减去当前的XXX和XXX
* */
void PrintVec(vector<int>& vec){
for(vector<int>::iterator iter= vec.begin(); iter!=vec.end(); ++iter){
printf("%d ", *iter);
}
printf("\n");
}
void printXXX(BiTree T, int& currentSum, int sum, vector<int>& vec){
if(!T)
return;
currentSum += T->data;
vec.push_back(T->data);
if(currentSum == sum && T->lchild==NULL && T->rchild==NULL ){
PrintVec(vec);
}
if(T->lchild){
printXXX(T->lchild, currentSum, sum, vec);
}
if(T->rchild){
printXXX(T->rchild, currentSum, sum, vec);
}
vec.pop_back();
currentSum -= T->data;
}
这道题也要假设当前结点处理完,从路径向量中删除该结点。
总结:
这两道题都是基于二叉树的先序遍历,只是又添加了一个保存访问结点的路径这一任务。这一任务的关键思想是:处理完当前结点,就将当前结点退出路径。