408真题-二叉树的带权路径长度

120 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 18 天,点击查看活动详情

Day46 2023/02/21

难度:简单

题目

image.png

示例1

输入:二叉树先序遍历的序列(12 13 0 0 14 0 0)=> 12 13 14 (用0填充成满二叉树) 
输出:27
说明:13*1 + 14*1 = 27 各个叶子节点的带权路径长度之和

示例2

输入:二叉树先序遍历的序列(5 6 11 0 0 13 0 0 8 4 0 0 0 0 0)=> 5 6 11 13 8 4 (用0填充成满二叉树)
输出:56
说明:11*2 +13*2 + 4*2 = 56 各个叶子节点的带权路径长度之和

思路


根据题目,二叉树的带权路径长度是二叉树所有叶节点的带权路径长度之和,所以我们只需要求每一个叶节点的带权路径长度,然后把所求的每一个叶节点的wpl做一个累加即可。基于此我们已经把一个大而复杂的问题分解成了若干个相同的小问题,这种情况下明显要使用递归。
具体步骤:

  1. 首先判断传入节点是不是叶节点(即判断是否存在左右孩子节点)
  2. 若是叶节点则计算其wpl值,用累加的形式
  3. 若该节点不是叶节点,则继续递归下去
  4. 递归结束时,递归栈底层返回最终的wpl值

关键点


  • 递归调用首次传入根节点且deep = 0;

算法实现


c++代码实现-递归法

#include <iostream>
using namespace std;

// 定义二叉树节点
typedef struct  BiTNode {
    int weight; // 权值
    BiTNode *left, *right; // 左右子树
    BiTNode(int val) : weight(val), left(nullptr), right(nullptr){}; // 构造函数
}   BiTNode, *BiTree;

/**
 * @function 创建二叉树
 * @param T BiTree结构体
 */
void CreateBTree(BiTree& T) {
    int weight = 0; // 权值
    cin >> weight;
    if (weight == 0) T = nullptr; // 如果weight == 0表示没有该左或者右孩子
    else {
        T = new BiTNode(weight); // 申请新节点,并初始化
        CreateBTree(T->left);
        CreateBTree(T->right);
    }
}

/**
 * @function 计算二叉数的WPL
 * @param T BiTree结构体 
 * @param deep 整型 该节点的深度(与根节点的路径长度)
 * @return int 整型 WPL值
 */
int CalWpl(BiTree T, int deep) {
    static int wpl = 0; // 定义整型静态变量,效果类似全局变量
    if (!T->left && !T->right) wpl += T->weight*deep;  // 判断该节点是否为叶子节点,如果是则计算其wpl值
    if(T->left) CalWpl(T->left, deep + 1); // 递归计算每个叶节点的wpl值
    if(T->right) CalWpl(T->right, deep + 1 );
    return wpl;
}



// 测试一下
int main() {
    // 按照先序遍历的方式(根左右)创建二叉树,例如:12 13 0 0 14 0 0 最后先序遍历结果就是 12 13 14
    BiTree T;
    CreateBTree(T); 
    // 计算该二叉书权值 (即12*0 + 13*1 + 14*1 = 27)
    cout << "该二叉树的权值为:" << CalWpl(T, 0); // 初始传入根节点
}
  • 时间复杂度 O(n)O(n)--- 递归访问所有的节点,其中n为二叉树节点个数
  • 空间复杂度 O(n)O(n)--- 最坏情况下二叉树呈链状,递归栈空间等于二叉树节点总数,其中n为二叉树节点个数

总结

  • 二叉树这种数据结构,其相关的基本操作的实现如:先,中,后遍历,深度等基本都离不开递归的使用。