在二元树中找出和为某一值的所有路径

本文详细介绍了如何通过递归和回溯+剪枝的方法解决二元树路径匹配问题,实现与特定整数相等的所有路径打印。通过优化减少不必要的遍历,提高算法效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

微软的一道面试题,难度系数较低,题目描述如下:
题目:输入一个整数和一棵二元树。 
从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。 
打印出和与输入整数相等的所有路径。 
例如输入整数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 

}; 



逻辑分析:

1、既然是树,那么第一想法肯定是递归,而这题用递归解也确实是一目了然,类似树的深度遍历,只需要每一次将传入的num-root.m_nValue作为子问题的参数一路向北即可。

2、因为是所有路径,并不是找出某一条路径就结束,所以,考虑回溯+剪枝,解决问题。也就是说,我们需要一个容器,用来存放路径上的每一个点,每当递归遍历,则将路径点存入容器,而当不满足要求的时候,则将该点删除,显然,我们需要一个栈。而当sum==0的时候,则将栈依次打印出来,到此,问题完美解决。


给出代码样本:

///@copyright 玉涵
///updated 2013/12/21

#include <stdio.h>
#define MAX_HEIGHT 10

struct BinaryTreeNode
{
	int m_nValue;
	BinaryTreeNode *m_pLeft;
	BinaryTreeNode *m_pRight;
};

void helper(BinaryTreeNode *root, int sum, int path[], int top);

void printPaths(BinaryTreeNode *root, int sum)
{
	int path[MAX_HEIGHT];
	helper(root,sum,path,0);
}

void helper(BinaryTreeNode *root, int sum, int path[], int top)
{
	path[top++] = root->m_nValue;
	sum -= root->m_nValue;

	if(root->m_pLeft == NULL && root->m_pRight == NULL)
	{
		if(sum == 0)
		{
			for(int i=0; i<top;i++)
			{
				printf("%d\t",path[i]);
			}
			printf("\n");
		}
	}
	else
	{
		if(root->m_pLeft != NULL)
			helper(root->m_pLeft,sum,path,top);
		if(root->m_pRight != NULL)
			helper(root->m_pRight,sum,path,top);
	}
	sum += root->m_nValue;
	top--;
}

老规矩,写一个很不规范,纯粹是为了测试的主函数:

int main()
{
	BinaryTreeNode T10,T5,T12,T4,T7;
	T10.m_nValue = 10;
	T10.m_pLeft = &T5;
	T10.m_pRight = &T12;
	
	T5.m_nValue = 5;
	T5.m_pLeft = &T4;
	T5.m_pRight = &T7;

	T12.m_nValue = 12;
	T12.m_pLeft = NULL;
	T12.m_pRight = NULL;

	T4.m_nValue = 4;
	T4.m_pLeft = T4.m_pRight = NULL;

	T7.m_nValue = 7;
	T7.m_pLeft = T7.m_pRight = NULL;

	printPaths(&T10,22);
	return 0;
}

输出结果:



3、下午有位道友提出了这样的一个问题,如果在处理到某一中间结点的时候,sum的值直接越变,比如本例子传入的22,如果根节点左孩子是13,那么遍历到13的时候,10+13=23>22,那么是否我们就可以停止向下遍历,显然,从时间复杂度的角度考虑,上述算法的时间复杂度为O(Σleaf[i]*height[i]),其中leaf为叶子个数,height对应个叶结点的深度,那么如果经上述优化,时间复杂度的最差情况则与上式相同。但是这里存在一个问题,结点的域值不一定都是正数,如果存在负数,那么就不得不完全遍历了。


4、由此想到一点,如果二叉树是二叉查找树,那么上述的优化方案显然是可行的,而且是势必要进行的。我们知道二叉查找树的特点是,左子树小于等于根,右子树大于根,这样在遍历的时候,就加了很多判断条件,通过判断条件剪掉部分路径,优化了时间。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值