You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

层序二叉树(含完全二叉树)O(1)判断节点所属子树的方法

判断层序完全二叉树节点所属子树的方法

嘿,这个问题问到点子上了!层序完全二叉树的结构化特性刚好能让我们避开遍历,用数学方法实现O(1)时间复杂度的判断。我来一步步给你讲明白:

一、基础逻辑(针对层序存储的完全二叉树)

首先得明确:层序完全二叉树的节点是严格按「从上到下、从左到右」的顺序排列的,我们可以给每个节点分配一个全局编号(整棵树的根为1,左子节点是2,右子节点是3,下一层左到右依次是4、5、6、7,以此类推)。这个编号和节点位置有固定的数学关系:

  • 编号为n的节点,父节点编号是floor(n/2)
  • 左子节点编号是2n,右子节点是2n+1

如果你的树节点值是按层序顺序赋值的(比如整树根是2,左子3、右子4,再下一层左到右5、6、7、8...),那节点值和全局编号的对应关系很简单:节点值 = 整树根值 + 全局编号 - 1

要判断某个值v属于当前根节点(值为root_val)的左/右子树,核心就是先把值转换成全局编号,再利用编号的特性判断。

二、O(1)时间复杂度的实现方案

不用遍历的关键,是利用二进制编码的路径特性——完全二叉树的全局编号转成二进制后,去掉最高位的1,剩下的每一位其实就是从根到该节点的路径(0代表左,1代表右)。结合这个特性,我们可以直接定位:

步骤1:把节点值转成全局编号

假设整棵树的根节点值是global_root(比如你例子里的整树根是2),那任意节点值对应的全局编号可以这么算:

全局编号 = 节点值 - global_root + 1

拿你的例子验证:

  • 根节点2的全局编号:2 - 2 + 1 = 1
  • 节点15的全局编号:15 - 2 + 1 = 14
  • 节点3的全局编号:3 - 2 + 1 = 2
  • 节点10的全局编号:10 - 2 + 1 = 9

步骤2:先确认v是当前根的后代

首先得排除v根本不是当前根节点后代的情况。我们可以把两个全局编号转成二进制字符串:

  • 如果v的二进制长度比当前根的短,肯定不是后代
  • 否则,看v的二进制前缀是否和当前根的二进制完全一致——一致的话就是后代,否则不是

比如:

  • 当前根2的二进制是1,节点15的二进制是1110,前缀匹配,是后代
  • 当前根3的二进制是10,节点10的二进制是1001,前缀匹配,是后代

步骤3:判断左/右子树

如果确认是后代,我们只需要看v的二进制中,紧跟在当前根二进制后面的第一位

  • 这一位是0 → 左子树
  • 这一位是1 → 右子树

再拿你的例子验证:

  1. 根2(二进制1),v=15(二进制1110):
    去掉和根匹配的前缀1,剩下的字符串是110,第一位是1 → 右子树,完全符合你的预期。
  2. 根3(二进制10),v=10(二进制1001):
    去掉匹配的前缀10,剩下的字符串是01,第一位是0 → 左子树,也和你的例子一致。

伪代码实现

def judge_subtree(global_root, current_root_val, target_val):
    # 计算全局编号
    root_num = current_root_val - global_root + 1
    target_num = target_val - global_root + 1
    
    # 转成二进制字符串(去掉Python自带的'0b'前缀)
    root_bin = bin(root_num)[2:]
    target_bin = bin(target_num)[2:]
    
    root_len = len(root_bin)
    target_len = len(target_bin)
    
    # 先判断是否为后代节点
    if target_len <= root_len or target_bin[:root_len] != root_bin:
        return "该节点不是当前根的后代"
    
    # 判断左/右子树
    next_bit = target_bin[root_len]
    return "左子树" if next_bit == '0' else "右子树"

测试一下你给的案例:

  • judge_subtree(2, 2, 15) → 返回"右子树"
  • judge_subtree(2, 3, 10) → 返回"左子树"

补充说明

如果你的树节点值不是连续的,但仍然是严格按层序存储的(比如有固定的映射表对应节点值和全局编号),只需要把步骤1的全局编号计算替换成你的映射规则就行,核心的二进制判断逻辑是通用的。

内容的提问来源于stack exchange,提问作者Barshan Das

火山引擎 最新活动