面试100题系列之11在树中找到符合条件的路径

在二元树中找出和为某一值的所有路径(树),满足一下要求:
*该路径是从树的根节点到叶节点的一条路径
* 路径之和恰好等于一个给定的整数,路径的定义是节点的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的调用
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值