在二元树中找出和为某一值的所有路径(树),满足一下要求:
*该路径是从树的根节点到叶节点的一条路径
* 路径之和恰好等于一个给定的整数,路径的定义是节点的data值之和,允许有负数。
* 打印所有满足条件的路径
其实这是某公司电话面试我的一道题,自己当时答得不是很好,思考一番之后想到了比较完善的解法。可惜面试已经过去了,算了,当做是一种经历的记录吧~一共有三种,下面来一一给出。其实就是树的后序遍历。
1、作为一个二逼青年,首先想到的是递归吧,好吧,我连二逼青年都不如,因为我当时压根没往这方面想啊!!太紧张了,伤不起啊。在这一节,为了后序代码更简洁,也给出一些公共的函数,后面将不会再给了。
#include<stdio.h>
#include<string.h>
struct NODE
{
int data;
NODE *Left;
NODE *Right;
};
const int N = 30;
NODE node[N];
NODE *stack[N];
int top;
int goal;//目标数值
//往二叉查找树里面加节点,公共函数1
void Add(NODE *root, int v)
{
if(!root)
return;
if(root->data < v)
{
if(root->Right)
Add(root->Right, v);
else
{
root->Right = &node[++top];
node[top].data = v;
}
}
else if(root->data > v)
{
if(root->Left)
Add(root->Left, v);
else
{
root->Left = &node[++top];
node[top].data = v;
}
}
else
printf("重复加入节点%d\n", v);
}
//打印路径,公共函数2
void Print(NODE **stack, int top)
{
if(!stack)
return;
for(int i = 0; i <= top; ++i)
printf("%d ", stack[i]->data);
printf("\n");
}
//递归得到路径
void GetPath(NODE *root, int sum)
{
if(!root)
return;
stack[++top] = root;//将根节点压到栈中
sum += root->data;
if(!root->Left && !root->Right)
{
if(sum == goal)//goal为全局变量
Print(stack, top);
}
else
{
if(root->Left)
GetPath(root->Left, sum);
if(root->Right)
GetPath(root->Right, sum);
}
--top;
}
2、好吧,文艺一点的解法是什么呢??肯定是用栈来解决啦,但是栈来实现树的后序遍历需要flag标记,所以把NODE的数据结构重新定义一下。
struct NODE
{
int data;
NODE *Left;
NODE *Right;
bool flag;
};
//用栈来得到路径,NODE的定义中包含flag标记
void GetPath(NODE *root)
{
NODE *p = root;
top = -1;//重置栈顶
int sum = 0;
while(p != NULL || top > -1)
{
while(p != NULL)
{
stack[++top] = p;
sum += p->data;//入栈的时候加
p = p->Left;
}
if(stack[top]->Right == NULL && sum == goal)//是叶节点并且满足条件
{
Print(stack, top);
sum -= stack[top]->data;//出栈的时候减
--top;
}
while(top > -1 && stack[top]->flag)
{
sum -= stack[top]->data;//出栈的时候减
--top;
}
if(top > -1)
{
p = stack[top]->Right;
stack[top]->flag = true;//标记左子树已访问完毕
}
}
}
3、更高富帅的版本呢?在节点的定义中加入flag,这就使得定义的数据类型比较大,OK,不加就不加呗!那用什么方法来标记已经访问过左子树的节点呢?用一个辅助栈就可以啦!辅助栈的栈顶元素对应stack的栈顶元素的访问情况,下面给出代码:
//用辅助栈来标记节点,NODE节点的定义中不需要flag
void GetPathWithStack(NODE *root)
{
NODE *p = root;
top = -1;//重置栈顶
int sum = 0;
memset(FlagStack, 0, sizeof(FlagStack));
while(p != NULL || top > -1)
{
while(p != NULL)
{
stack[++top] = p;
sum += p->data;//入栈加
p = p->Left;
}
if(stack[top]->Right == NULL && sum == goal)
{
Print(stack, top);
sum -= stack[top]->data;//退栈减
--top;
}
while(top > -1 && FlagStack[top])
{
sum -= stack[top]->data;//退栈减
--top;
}
if(top > -1)
{
p = stack[top]->Right;
FlagStack[top] = true;
}
}
}
4、下面给出各种方法的main函数调用,如果不需要的,可以直接pass
int main()
{
int n,i,v;
while(scanf("%d", &n) != EOF)
{
memset(node, 0, sizeof(node));
top = 0;//top是node数组的顶
scanf("%d", &v);
node[0].data = v;
for(i = 1; i < n; ++i)
{
scanf("%d", &v);
Add(&node[0], v);
}
printf("输入需要查找的路径长度:");
scanf("%d",&goal);
//top = -1;//方法1的调用
//GetPath(&node[0],0);//方法1的调用
//GetPath(&node[0]);//方法2的调用
GetPathWithStack(&node[0]);//方法3的调用
}
}