理解BST、Python的顺序遍历逻辑
我正在学习编写采访代码,并处理许多不同的数据结构 我对树问题比较陌生,每天都做问题练习 记住公式是一回事,真正理解公式是另一回事。当我理解了一些东西,就很容易将这种理解应用到更困难的问题上 递归解决方案对我来说更难想象,虽然直觉上它们是有意义的,但我正试图深入理解堆栈上发生的事情 我有一棵树,想按顺序遍历。没问题 我创建了数据变量以打印出每次通过该方法时存储的内容 它是印刷的理解BST、Python的顺序遍历逻辑,python,algorithm,tree,Python,Algorithm,Tree,我正在学习编写采访代码,并处理许多不同的数据结构 我对树问题比较陌生,每天都做问题练习 记住公式是一回事,真正理解公式是另一回事。当我理解了一些东西,就很容易将这种理解应用到更困难的问题上 递归解决方案对我来说更难想象,虽然直觉上它们是有意义的,但我正试图深入理解堆栈上发生的事情 我有一棵树,想按顺序遍历。没问题 我创建了数据变量以打印出每次通过该方法时存储的内容 它是印刷的 [] [1] [1] [1, 2] [1, 2, 3] [1, 2, 3] [1, 2, 3] [1, 2, 3, 4
[]
[1]
[1]
[1, 2]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
我试图从逻辑上看待正在发生的事情,并想知道我的逻辑是否正确
共有15个打印结果和7个节点。然而,我们得到了15,因为有8个节点被检查,其中节点是None
。这发生在节点1、3、5、7上
我们正在检查树的左半部分,在右半部分之前
[]
#nothing stored because we move onto Node 2 as we don't hit the base case.
[1]
#1 stored because Node 1 doesn't have a left value. So we move onto the append call.
[1]
#1 returned because Node 1 doesn't have a right value.
[1, 2]
#2 stored because because we finished checking the left side and moved onto append data.
[1, 2, 3]
#3 is stored because we are calling the in order traversal on the right side of two now.
[1, 2, 3]
#3 is returned again because it doesn't have a root.left
[1, 2, 3]
#3 is returned again because it doesn't have a root.right
[1, 2, 3, 4]
# we hit the append method for 4, now we move onto the in order traversal on the right
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
右边会像左边一样被检查,所以我没有写我的逻辑,因为它是多余的
我只是想澄清一下,如果我在正确的格式看这个问题
谢谢你对我的帮助 输出中的注释并不总是正确的 第一个输出(
[]
)发生在函数调用结束时。发生这种情况的第一个调用是当root
是节点1时,从那里进行第一个递归调用。该调用将None
作为参数,因此这是调用第一次到达print
语句
所以我们有这些持续的电话:
checkBST(4)
checkBST(2) # left child of 4
checkBST(1) # left child of 2
checkBST(None) # left child of 1
print # --> []
当最深的调用完成时,具有节点1的函数将向数据列表追加1,然后对正确的子级进行递归调用,该子级也是None
,并且打印[1]
下面是过程的可视化。列表示递归的深度,行表示随着时间的推移(向下)事件的顺序。最后一列保留用于显示数据的当前值。当它有黄色背景时,表示它已打印
浅蓝色表示代码在该递归深度执行。深蓝色表示相应的函数调用挂起(在堆栈上),等待嵌套递归调用返回
从这张图中,您还可以看到为什么同一输出有时会重复:当算法回溯时,它以不同的递归级别打印。输出中的注释并不总是正确的
第一个输出([]
)发生在函数调用结束时。发生这种情况的第一个调用是当root
是节点1时,从那里进行第一个递归调用。该调用将None
作为参数,因此这是调用第一次到达print
语句
所以我们有这些持续的电话:
checkBST(4)
checkBST(2) # left child of 4
checkBST(1) # left child of 2
checkBST(None) # left child of 1
print # --> []
当最深的调用完成时,具有节点1的函数将向数据列表追加1,然后对正确的子级进行递归调用,该子级也是None
,并且打印[1]
下面是过程的可视化。列表示递归的深度,行表示随着时间的推移(向下)事件的顺序。最后一列保留用于显示数据的当前值。当它有黄色背景时,表示它已打印
浅蓝色表示代码在该递归深度执行。深蓝色表示相应的函数调用挂起(在堆栈上),等待嵌套递归调用返回
从这幅图中,您还可以看到为什么有时重复相同的输出:当算法回溯时,它以不同的递归级别打印。我发现当打印
是递归方法的第一行时,输出更容易理解。它可以帮助打印一些东西,例如root.data
,作为路标,让您知道自己在树中的位置。因此,print root.data,data
作为第一行是我的建议。我发现当print
是递归方法的第一行时,输出更容易理解。它可以帮助打印一些东西,例如root.data
,作为路标,让您知道自己在树中的位置。所以我的建议是打印root.data,data
作为第一行。我没想到会有这么彻底的答案。这把一切都清理干净了!我没想到会有这么彻底的回答。这把一切都清理干净了!