完全二叉树的权值(利用二叉树存储的特点轻松解题)

完全二叉树的权值问题

文章目录

  • 完全二叉树的权值问题
    • 前言
    • 题目描述
    • 知识预备【二叉树的存储】
      • 定义【官方】
      • 自定义
    • 题目分析
    • 按部就班的代码
    • 精简优化的代码
    • 总结

前言

许多小伙伴刚刚接触二叉树的时候对二叉树的存储不太敏感,对于如何利用二叉树的性质解题存在盲区,这篇博客将会带领大家了解二叉树的存储性质在解题当中的作用。同时将会给出两种不同风格的代码【当然核心的原理上都是一样的】供大家参考,喜欢的小伙伴可以点个赞啦!
其他二叉树有关的题目如下:
动态求连续区间和+数列区间最大值(快速掌握线段树的基本性质及应用)

题目描述

给定一棵包含 N 个节点的完全二叉树,树上每个节点都有一个权值,按从上到下、从左到右的顺序依次是 A1,A2,⋅⋅⋅AN,如下图所示:
完全二叉树的权值(利用二叉树存储的特点轻松解题)_第1张图片

现在小明要把相同深度的节点的权值加在一起,他想知道哪个深度的节点权值之和最大

如果有多个深度的权值和同为最大,请你输出其中最小的深度。

注:根的深度是 1。

输入格式
第一行包含一个整数 N。

第二行包含 N 个整数 A1,A2,⋅⋅⋅AN。

输出格式
输出一个整数代表答案。

数据范围
1≤N≤105,
−105≤Ai≤105
输入样例:

7
1 6 5 4 3 2 1

输出样例:

2

知识预备【二叉树的存储】

定义【官方】

二叉树是一种常见的树状数据结构,它由一组称为节点的元素组成,这些节点通过指向其他节点的引用(通常称为左子节点和右子节点)来建立层次关系。

二叉树的特点包括:

  • 每个节点最多有两个子节点,分别称为左子节点和右子节点。
  • 左子节点的值小于或等于父节点的值,右子节点的值大于父节点的值。
  • 每个节点最多有一个父节点,除了根节点没有父节点。
  • 二叉树可以是空树,即没有任何节点。

以下是一个二叉树的示例图形表示:

      A
     / \
    B   C
   / \      \
  D   E   F

在这个示例中,节点A是根节点,节点B和C是A的子节点,节点D和E是B的子节点,节点F是C的子节点。

二叉树可以用不同的方式来实现,包括链式存储和数组存储。链式存储是指使用节点对象和引用来表示二叉树,而数组存储是指使用数组来表示二叉树

自定义

上面的解释比较抽象,这里会给出图片帮助大家理解:以题目中的输入数据为例
完全二叉树的权值(利用二叉树存储的特点轻松解题)_第2张图片
二叉树的存储
可能有小伙伴看到二叉树是二维图形,所以需要一个二维数组去储存。其实不是这样,看图
完全二叉树的权值(利用二叉树存储的特点轻松解题)_第3张图片

总结出来的规律如下,看图
完全二叉树的权值(利用二叉树存储的特点轻松解题)_第4张图片

题目分析

将二叉树看成两个部分,叶子结点所在的那一层【叶子节点当中包含空节点】,除了叶子节点外的层数
每一层开始的数组下标都是 1 << (u-1) ,结束的下标都是 (1<
由此我们用递归去解决:用cnt数组记录每一层权值总和

void dfs(int u){
    if(n<=((1<<u)-1)) return;//这里是为了排除
    for(int i=1<<(u-1);i<(1<<u);i++){
        cnt[u]+=a[i];
    }
    dfs(u+1);
}

接着找到最后一层,计算最后一层的权值总和

for(int j=1;j<=n;j++){
        if((1<<j)-1>=n){
            flag=j;
            break;
        }
    }
    for(int i=(1<<(flag-1));i<=n;i++){
        cnt[flag]+=a[i];
    }

最后比较得出结论:

	ans=1;
    res=cnt[1];
    for(int i=2;i<=200;i++){
       if(!cnt[i]) break;
        if(cnt[i]>res){
            res=cnt[i];
            ans=i;
        }
    }

按部就班的代码

#include
using namespace std;
const int N = 1e5 + 7;
long long  n,res,ans;
long long a[N],cnt[N];
void dfs(int u){// u 代表层数
    if(n<=((1<<u)-1)) return;
    for(int i=1<<(u-1);i<(1<<u);i++){
        cnt[u]+=a[i];
    }
    dfs(u+1);
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    dfs(1);
    
    int flag=0;
    for(int j=1;j<=n;j++){
        if((1<<j)-1>=n){
            flag=j;
            break;
        }
    }
    for(int i=(1<<(flag-1));i<=n;i++){
        cnt[flag]+=a[i];
    }
    ans=1;
    res=cnt[1];
    for(int i=2;i<=200;i++){
       if(!cnt[i]) break;
        if(cnt[i]>res){
            res=cnt[i];
            ans=i;
        }
    }
    
    cout<<ans<<endl;
}

精简优化的代码

#include 

using namespace std;
const int N = 1e5 + 7;

long long a[N];

int main() {
    int n;
    cin >> n;
    
    for(int i=1;i<=n;i++) cin>>a[i];
    long long res=  -1e18;//记录最大值
    int depth=1;//记录层数
    int ans=1;//记录最终结果值
    long long sum;//记录每一层的和
    for(int i=1;i<=n;i*=2){//代表层数
        sum=0;//每次进入到下一层都要记得重置sum
        for(int j=i;j<=n && j<=i*2-1;j++){
            sum+=a[j];
        }
        if(sum>res){
            res=sum;
            ans=depth;
        }
        depth++;
    }
    cout<<ans<<endl;
}

总结

以上就是有关二叉树存储的介绍,其他更多高难度题目可以在前言中查看,喜欢的小伙伴可以点个关注啦!

你可能感兴趣的:(算法入门,图论,算法,蓝桥杯,c++,二叉树)