二叉树子树结点个数

简介: 二叉树子树结点个数

二叉树子树结点个数

描述

 

如上所示,由正整数1,2,3……组成了一颗特殊二叉树。我们已知这个二叉树的最后一个结点是n。现在的问题是,结点m所在的子树中一共包括多少个结点。


比如,n = 12,m = 3那么上图中的结点13,14,15以及后面的结点都是不存在的,结点m所在子树中包括的结点有3,6,7,12,因此结点m的所在子树中共有4个结点。

输入

 

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

输出

 

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

输入样例 1

3 7

142 6574

2 754

0 0

输出样例 1

3

63

498

 

题解:

解答这道题主要可以分为以下几步:

1、确定子树根结点所在层数

2、确定二叉树的总层数

3、计算子树左下角和右下角的结点数值分别是多少

4、判断子树最下方的左右结点和二叉树的右下结点的关系,确定子树最下层有多少个结点

5、计算总结点数

(1)第1、2步都是要确定层数,其实层数并不难确认,我们分析一下二叉树就可以得出规律

每一层的开始结点为2^(层数-1),所以我们只需要确定结点与2之间幂的次数,就可以确定结点所在层数

int count(long long int x)
{
  int ans = 0;
  while(x != 0){
    x/=2;
    ans++;
  }
  return ans;
}

(2)子树的左右下角的结点也是有规律的,我们以3为子树根结点来分析一下:

左下角的结点是其(根结点乘2)得来,右下角则等于(根结点*2+1)

long long left(long long int x,long long int y)
{
  while(y--)
  {
    x*=2;
  }
  return x;
}
long long right(long long int x,long long int y)
{
  while(y--)
  {
    x = x * 2 + 1;
  }
  return x;
}

(3)判断子树最下方的左右结点和二叉树的右下结点的关系,确定子树最下层有多少个结点

if(n <= right(m,q-p) && n >= left(m,q-p))
  sum += n-left(m,q-p)+1;
if(n > right(m,q-p))
  sum += right(m,q-p) - left(m,q-p) +1;

(4)确定子树的结点总个数,因为结点的个数是指数增长的,我们只需要知道子树的层数就可以计算出子树的结点个数,我通过快速幂的来计算

long long int quickPower(long long int x,long long int y)
{
    long long int result = 1; // 定义变量
    while (y > 0) // 当指数大于 0 时进行幂运算
    {
        if (y & 1) // y 和 1 做与运算,相当于对 2 求模
        {
            result = result * x; // 如果 y 为奇数,则结果成一个 x
        }
        x = x * x; // x 乘二次方,下次使用
        y = y >> 1; // y 右移一位,相当于除以 2
    }
    return result; // 返回结果 
}

完整代码如下:

#include<stdio.h>
int count(long long int x)
{
  int ans = 0;
  while(x != 0){
    x/=2;
    ans++;
  }
  return ans;
}
long long int quickPower(long long int x,long long int y)
{
    long long int result = 1; // 定义变量
    while (y > 0) // 当指数大于 0 时进行幂运算
    {
        if (y & 1) // y 和 1 做与运算,相当于对 2 求模
        {
            result = result * x; // 如果 y 为奇数,则结果成一个 x
        }
        x = x * x; // x 乘二次方,下次使用
        y = y >> 1; // y 右移一位,相当于除以 2
    }
    return result; // 返回结果 
}
long long left(long long int x,long long int y)
{
  while(y--)
  {
    x*=2;
  }
  return x;
}
long long right(long long int x,long long int y)
{
  while(y--)
  {
    x = x * 2 + 1;
  }
  return x;
}
int main()
{
  long long int m,n;
  while(scanf("%lld %lld",&m,&n)!=EOF){
    if(m+n==0) break;
    //printf("%d\n",count(m,n));
    int p = count(m);
    int q = count(n);
//    printf("p=%d,q=%d\n",p,q);
//    printf("l=%lld,r=%lld\n",left(m,q-p),right(m,q-p));
    long long int sum = quickPower(2,q-p)-1;
    if(n <= right(m,q-p) && n >= left(m,q-p))
      sum += n-left(m,q-p)+1;
    if(n > right(m,q-p))
      sum += right(m,q-p) - left(m,q-p) +1;
    printf("%lld\n",sum);
  }
  return 0;
}
目录
相关文章
|
6月前
|
存储
二叉树详解(深度优先遍历、前序,中序,后序、广度优先遍历、二叉树所有节点的个数、叶节点的个数)
二叉树详解(深度优先遍历、前序,中序,后序、广度优先遍历、二叉树所有节点的个数、叶节点的个数)
|
5月前
【树 - 平衡二叉树(AVL)】F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量
【树 - 平衡二叉树(AVL)】F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量
|
6月前
|
机器学习/深度学习 C++
初阶数据结构之---二叉树链式结构(二叉树的构建,二叉树的前序,中序,后序和层序遍历,计算二叉树结点个数,第k层结点个数,叶子结点个数,判断是否为完全二叉树)
初阶数据结构之---二叉树链式结构(二叉树的构建,二叉树的前序,中序,后序和层序遍历,计算二叉树结点个数,第k层结点个数,叶子结点个数,判断是否为完全二叉树)
计算左子树规模(结点个数),找出树的根结点
简单的计算公式教你找出左子树到底有多少个娃,也会与你一起寻找根结点,快来看看呀
计算左子树规模(结点个数),找出树的根结点
|
6月前
|
算法
二叉树的结点个数、叶子结点个数的代码实现<分治算法>
二叉树的结点个数、叶子结点个数的代码实现<分治算法>
|
算法 DataX
删除二叉树子树
删除二叉树子树
125 0
二叉树的层序遍历、二叉树叶节点输出算法、求二叉树的高度、层序创建一棵二叉树
二叉树的层序遍历、二叉树叶节点输出算法、求二叉树的高度、层序创建一棵二叉树
二叉树——222. 完全二叉树的节点个数
本专栏按照数组—链表—哈希—字符串—栈与队列—二叉树—回溯—贪心—动态规划—单调栈的顺序刷题,采用代码随想录所给的刷题顺序,一个正确的刷题顺序对算法学习是非常重要的,希望对大家有帮助
二叉树——222. 完全二叉树的节点个数