vlambda博客
学习文章列表

【算法游戏】判断完全二叉树的节点是否存在

CV不会灰飞烟灭
这里是坚信CV可以玩下去的地方,旨在以好玩且务实(结合代码)的风格分享计算机视觉技术,內容包括但不仅限于:传统图像处理、机器学习与深度学习领域的分类、检测、分割等,以及算法和開發技巧,欢迎各位前来一起玩~
1篇原创内容
Official Account

一起来玩个游戏吧:已知一棵完全二叉树的高度,其中的节点已按层序遍历的次序进行编号,当前你仅能看到根节点而不知树的全貌,如何判断某编号对应的节点是否存在?

【算法游戏】判断完全二叉树的节点是否存在


HALO!我是CW。

第一次见面,不搞太复杂的内容,有关CV领域的内容会在后续输出(先酿一酿,更香~)。这次先分享个算法方面的技巧,相关的数据结构是coder们都熟悉的二叉树,大家怀着轻松愉快的心情当作玩游戏就好。

OK,大家现在就和CW一起来玩玩吧~!【算法游戏】判断完全二叉树的节点是否存在



01

游戏规则


假设一棵完全二叉树高度为h(h1),其中每个节点按照层序遍历的次序进行编号(从1开始,即根节点的编号为1),比如像下面这样:

【算法游戏】判断完全二叉树的节点是否存在


当前你只知道根节点的存在(比如你只能看到上图那棵树中编号为1的节点),通过根节点你可以到达树中的任意节点,每个节点的数据结构表示为如下形式:

class TreeNode:    def __init__(self, num, left=None, right=None):     # 节点编号     self.num = num     # 左孩子     self.left = left        # 右孩子     self.right = right

请你设计一种算法,判断在这棵树中编号为i(i ≥1)的节点是否存在。


02

脑洞


当然,“勤奋”的孩子会用暴力解法,从根节点出发,将所有路径都搜索一遍(也是不怕累哦..【算法游戏】判断完全二叉树的节点是否存在)。不过,CW是叫你来玩游戏的,别搞这种无聊的风格,不好玩【算法游戏】判断完全二叉树的节点是否存在【算法游戏】判断完全二叉树的节点是否存在

想要好玩,当然得动脑!我们可以脑洞一下,看看根据当前情况,有哪些东西是可以利用的,或者说,根据已知条件可以计算出哪些有利于我们通关的辅助条件。

首先,我们要理解游戏规则,从已知条件中明确一些重要信息。比如,完全二叉树有什么特点?CW觉得,最明显的是:

叶子结点只会出现在最底层和次底层,且最底层的叶子结点仅会集中在树的左部。并且,除最底层以外,其余层的节点数一定达到最大值(当然,最底层的节点数也可能达到最大值,此时的完全二叉树也称为满二叉树)。


来张图更形象些:

【算法游戏】判断完全二叉树的节点是否存在


另外,层序遍历的次序来编号就是怎样?CW就引用幼儿园的话术来解释下吧:

对树中的节点按从上至下、从左到右的顺序进行编号


例如:

【算法游戏】判断完全二叉树的节点是否存在


OK,规则中的术语理解得差不多了,我们不妨大胆些。比如,如果我们知道树中的节点数量为n(n≥1),那么树中的节点编号范围就是[1, n],咦!那这岂不是变成了白痴问题了吗..【算法游戏】判断完全二叉树的节点是否存在(i大于n的话节点就肯定不存在了)

尽管有些天真,但我们还是可以往这个点上靠:当前已知完全二叉树的高度为h,根据完全二叉树的性质,可知这棵树至少有2^(h-1)个节点、至多有2^h - 1个节点。进一步,这就隐含着:位于最底层的节点,其编号范围为[2^(h-1), 2^h - 1]。

你看啊,看似天真的想法,靠一靠还是能靠出些东西来的【算法游戏】判断完全二叉树的节点是否存在。因此,千万不要嘲笑任何一个看似愚蠢的idea,如果你有这种态度,就恰恰说明了你的愚蠢!

既然我们已经计算出最底层节点的编号范围,那么只要确定i与这个范围的关系,差不多就可以通关了:

  • 若i ≤ 2^(h-1),那么节点i一定存在;
  • 若i > 2^h - 1,那么节点i一定不存在;
  • 若2^(h-1) < i ≤ 2^h - 1,此是节点i位于最底层,需要进一步判断其存在性


于是,我们的目标转为对上述最后一组种情况进行求解。



03

基于位运算的路径搜索


当节点i位于最底层时,我们需要从根节点出发,搜索到节点i的路径,若最终返回空,则说明节点不存在。

这里分享一个好玩的trick,使得在路径搜索过程中每一步都能按正确的方向走。

这个trick使用一种很妙的做法:将i转换为二进制表示,除最高位以外,其余每位都指示着从根节点去往节点i的路径方向——0表示往左子树走,1表示往右子树走。

为了形象说明,这里举个例子,比如当前树的高度h=3,让你判断节点i=6是否存在。具体来说,是这样做的:

  1. 将i转换为二进制,这里i=6,转换结果就是101,去掉最高位剩下01,记为j;
  2. 设置一个模式串,其最高位与j对齐,且为1,其余位都是0,记为bits,于是bits=10;
  3. 从根节点出发,将j与bits按位进行与(and&)操作,结果为0,于是走向左子树,同时bits右移一位,于是bits更新为01;
  4. 继续将j与bits按位进行与操作,结果为1,于是这次向右子树走,bits再右移一位之后已经没有任何位剩下了,于是结束搜索;
  5. 此时,若走到的节点为空,则说明节点i不存在;否则,这个节点就是节点i


以上过程,可用以下代码来表示:

node = rootbits = 1 << (h - 2)while node and bits: if bits & j:        node = node.right    else:        node = node.left        bits >>= 1    return node



04

通关


现在来将上述过程汇总下,就可以实现通关了。

首先利用已知条件中树的高度h计算出最底层节点的编号范围是[2^(h-1), 2^h - 1],然后根据目标节点的编号i与该区间的关系来执行相应操作:

  • 若i ≤ 2^(h-1),则直接通关:节点i存在;
  • 类似地,若i > 2^h,则同样可以直接通关:节点i不存在;
  • 若2^(h-1) < i ≤ 2^h,则使用上一节的trick来确定节点i是否存在



05

结语


初次见面,没有什么高大上的内容,仅本着好玩且务实(结合代码)的风格和大家学习和交流,文章排版什么的也挺low,还请各位不要介意【算法游戏】判断完全二叉树的节点是否存在


【算法游戏】判断完全二叉树的节点是否存在



点击下方卡片,让我们成为好朋友一起玩~

CV不会灰飞烟灭
这里是坚信CV可以玩下去的地方,旨在以好玩且务实(结合代码)的风格分享计算机视觉技术,內容包括但不仅限于:传统图像处理、机器学习与深度学习领域的分类、检测、分割等,以及算法和開發技巧,欢迎各位前来一起玩~
1篇原创内容
Official Account