二叉树的子树 解题报告

                                                       二叉树的子树

                                                        Time Limit:3000MS  Memory Limit:65536K

Description



如上图所示,由正整数1,2,3……组成了一颗二叉树。我们已知这个二叉树的最后一个结点是n。现在的问题是,结点m所在的子树中一共包括多少个结点。
比如,n = 12,m = 3那么上图中的结点13,14,15以及后面的结点都是不存在的,结点m所在子树中包括的结点有3,6,7,12,因此结点m的所在子树中共有4个结点。

Input

输入数据包括多行,每行给出一组测试数据,包括两个整数m,n (1 <= m <= n <= 1000000000)。最后一组测试数据中包括两个0,表示输入的结束,这组数据不用处理。

Output

对于每一组测试数据,输出一行,该行包含一个整数,给出结点m所在子树中包括的结点的数目。

Sample Input

3 12

0 0

Sample Output

4

Hint

这一题如果从查询的点出发往下遍历它的左子树和右子树,是肯定会超时的,因此不应遍历每个点,而是逐层遍历。

以样例为例,从3出发逐层向下遍历,每次找它的右儿子结点,即3*2+1,以此类推找到每个当前点编号i的编号i*2+1点,直到i*2+1>n;这样就相当于把所有满结点的层遍历完了。

那么这些层包含了多少点呢?排除最后一层抽出来看其实它是一棵完全二叉树,假如有i层,它的点数为2的i-1次方-1,而层数可以通过遍历时求出;至于最后一层的结点,可以再回到m进行遍历,找到它最左方的叶子结点k,那么最后一层的结点数就为n-k+1.当然,如果n<k,最后一层就没有结点了。所以子树的总点数就显而易见了。

代码:

#include
#include
using namespace std;
	int n,m;
int main()
{
	while (true) 
	{
		scanf("%d%d",&m,&n);
		if (n==0&&m==0) break;
		int ans=0;
		int i=0;
		int m1=m; //m1用来找左子树叶子结点,而m遍历每层右子树叶子结点
		while (m<=n)
		{
			m=m*2+1;
			ans+=int(pow(double(2),i));
			i++;
		}
		m1*=int(pow(double(2),i-1));
		if (m1*2>n) printf("%d\n",ans); else printf("%d\n",ans+n-m1*2+1);
	}
}
#include
using namespace std;
	int n,m;
int main()
{
	while (true) 
	{
		scanf("%d%d",&m,&n);
		if (n==0&&m==0) break;
		int ans=0;
		int i=0;
		int m1=m; //m1用来找左子树叶子结点,而m遍历每层右子树叶子结点
		while (m<=n)
		{
			m=m*2+1;
			ans+=int(pow(double(2),i));
			i++;
		}
		m1*=int(pow(double(2),i-1));
		if (m1*2>n) printf("%d\n",ans); else printf("%d\n",ans+n-m1*2+1);
	}
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值