fucking-algorithm icon indicating copy to clipboard operation
fucking-algorithm copied to clipboard

如何计算完全二叉树的节点数 :: labuladong的算法小抄

Open utterances-bot opened this issue 2 years ago • 16 comments

文章链接点这里:如何计算完全二叉树的节点数

评论礼仪 见这里,违者直接拉黑。

utterances-bot avatar Jan 04 '22 15:01 utterances-bot

牛啊牛啊,学到了!

Gipbear avatar Jan 04 '22 15:01 Gipbear

或者这样, 容易理解一些:

完全二叉树节点总数是:

// 每一层都是2的(i-1)次幂
int res = 0;
for (int i = 1; i <= lo;i++) {
    res += Math.pow(2, i - 1);
}
return res;

z-ak-z avatar Jan 08 '22 14:01 z-ak-z

算法的时间复杂度怎么算的呀, 每次递归的复杂度是while循环(logN), 最后return的那个递归只有一个会被执行,因此return的复杂度相当于递归内容的复杂度(while循环logN), 最后相乘?

TimurJiangShan avatar Feb 15 '22 12:02 TimurJiangShan

递归的次数 x 每次递归的时间复杂度,递归次数就是树的高度 O(logN),每次递归所花费的时间就是 while 循环,需要 O(logN),所以总体的时间复杂度是 O(logN*logN)。

labuladong avatar Feb 16 '22 02:02 labuladong

dong哥的解释很详细

Xiazeyu0628 avatar Mar 08 '22 08:03 Xiazeyu0628

确实吊

happy2h avatar Apr 18 '22 13:04 happy2h

代码注释有个小错误,代码中的lh和rh代表的并不是左右子树的高度,而是一直沿最左和最右走的长度,如果lh == rh, 则说明完全二叉树是满二叉树。

strickland0702 avatar May 05 '22 17:05 strickland0702

@strickland0702 明白你的意思了,有道理,我改下表述

labuladong avatar May 09 '22 01:05 labuladong

看评论区没有说,我来说一下单纯计数的那一部分,没有返回0是怎么计算的,望斧正

按理说如果是单纯计数,到了null结点需要返回0,而东哥的代码并没有显式的返回0,其实已经囊括在

if (hl == hr) {
    return (int)Math.pow(2, hl) - 1;
}

这部分中,若是只有左右子树中的一个,比如左子树只有一个,右子树为空, 左子树:hl == hr == 1 --> return (int)Math.pow(2, hl) - 1 == 1, 右子树:hl == hr == 0 --> return (int)Math.pow(2, hl) - 1 == 0

d0odLe avatar Jun 01 '22 01:06 d0odLe

乖乖,又长见识了

LebronHarden1 avatar Jun 07 '22 12:06 LebronHarden1

我能理解你说的计算那部分full tree的计算,,但是另一半呢? 就是总有一条路径只有左孩子,没有右孩子的,不得还是一种naive的方式.我的理解是, 这条路径其实就是单独算, 复杂度是O(h)

zhangpanzhan avatar Jun 17 '22 15:06 zhangpanzhan

我觉得楼上说的在理呀,只有单独左/右孩子结点的遍历复杂度不能算作logN吧,要单独算。

sleepynoctua avatar Jun 18 '22 03:06 sleepynoctua

东哥我没理解非满二叉树子树的递归复杂度计算。对于满二叉树的子树遍历中有两个while,按照层数从上到下高度为log(n)因此复杂度为O(logn)没毛病,非满二叉树的子树相当于需要遍历该子树中的每一个节点吧?感觉递归次数并不是树的高度而是子树中节点的数目,递归函数每次执行的复杂度为O(logn),节点数目准确来说应该是N / 2 (因为子树包含一半的节点), 因此复杂度不应该是O(logn * n / 2)嘛? 如果我说的不对麻烦大佬指正,没太明白怎么计算出的log^2(n)

lhcezx avatar Jul 03 '22 14:07 lhcezx

非满二叉树的子树相当于需要遍历该子树中的每一个节点吧

@lhcezx 你说的这句话不对。注意代码,非满二叉树也只需要从根节点走到叶子节点,即遍历「高度」而不是「所有节点」,所以所需时间就是 logN,因此结果就是 O(logN*logN)。

labuladong avatar Jul 14 '22 03:07 labuladong

check in

deepbreath373 avatar Jul 16 '22 02:07 deepbreath373

  1. Complete BT必然从root开始,有一半是perfect BT(O(logN)),另一半可能也是perfect BT或者Complete BT
  2. 如果是Complete BT,那么又回到上一层的逻辑——即一半子树是perfect BT,另一半是Complete BT
  3. 那么最坏的情况下就是,每一层都是一半是perfect BT,另一半半complete BT。并且你需要继续去下一层去计算complete BT的那一半子树。
  4. 那么最多需要计算几次这种一半子树呢?就是整个树的深度/高度——O(logN)。每次计算量是多少呢?O(logN)。所以总的计算量是O((logN)^2)

举例子算一下,如果6层树,最坏情况下

  • 第一层,只有root
  • 第二层,一半是perfect BT,O(logN),另一半需要在第三层分左右子树计算
  • 第三层,一半是perfect BT,O(logN),另一半需要在第四层分左右子树计算
  • 第四层,一半是perfect BT,O(logN),另一半需要在第五层分左右子树计算
  • 第五层,一半是perfect BT,O(logN),另一半需要在第六层分左右子树计算
  • 第六层,是最后一层,怎么都是perfect BT,O(logN)

总计算量就是

O() = 5*O(logN) = (O(logN)-1)*O(logN) = O(logN)*O(logN) = O((logN)^2)

Goolloo avatar Aug 08 '22 09:08 Goolloo

滴滴滴打卡

LeeHaruYa avatar Aug 17 '22 11:08 LeeHaruYa

打卡

”完全二叉树的左右两边,总有一个是满的“ 有趣

yonggui-yan avatar Sep 05 '22 21:09 yonggui-yan