在 BST 中,从节点左侧下降的所有值都小于(或等于,见后文)节点本身。类似地,在节点右侧下降的所有值都大于(或等于)该节点值(a)。
一些 BST 可能选择允许重复值,因此上面的“或等于”限定词。下面的例子可以说明:
14
/ \
13 22
/ / \
1 16 29
/ \
28 29
这显示了一个允许重复的 BST(b) - 你可以看到要找到一个值,你从根节点开始,根据你的搜索值是否沿着左子树或右子树小于或大于节点值。
这可以通过以下方式递归完成:
def hasVal (node, srchval):
if node == NULL:
return false
if node.val == srchval:
return true
if node.val > srchval:
return hasVal (node.left, srchval)
return hasVal (node.right, srchval)
并调用它:
foundIt = hasVal (rootNode, valToLookFor)
重复项会增加一点复杂性,因为一旦找到值,您可能需要继续搜索具有相同值的其他节点。显然,这对hasVal 无关紧要,因为有多少并不重要,只要至少存在一个即可。然而,这对于countVal 之类的东西很重要,因为它需要知道有多少。
(a) 如果您希望调整搜索特定键的方式,您可以实际上对它们进行排序。 BST 只需要维护某种排序顺序,无论是升序还是降序(甚至是一些奇怪的多层排序方法,例如所有奇数升序,然后所有偶数降序)都是无关紧要的。
(b) 有趣的是,如果您的排序键使用存储在节点上的 整个 值(因此包含相同键的节点具有 no 其他额外信息来区分它们),可以通过向每个节点添加计数而不是允许重复节点来提高性能。
主要好处是添加或删除重复项只会修改计数,而不是插入或删除新节点(可能需要重新平衡树的操作)。
所以,要添加一个项目,你首先要检查它是否已经存在。如果是这样,只需增加计数并退出。如果没有,则需要插入一个计数为 1 的新节点,然后重新平衡。
要删除一个项目,你找到它然后减少计数 - 只有当结果计数为零时,你才会从树中删除实际节点并重新平衡。
由于节点较少,搜索也更快,但这可能影响不大。
例如,以下两棵树(左侧不计数,右侧计数)将等价(在计数树中,i.c 表示 c 项 i 的副本):
__14__ ___22.2___
/ \ / \
14 22 7.1 29.1
/ \ / \ / \ / \
1 14 22 29 1.1 14.3 28.1 30.1
\ / \
7 28 30
从左树中删除叶节点22 将涉及重新平衡(因为它现在有两个高度差)生成的22-29-28-30 子树如下所示(这是一个选项,还有其他也满足“高差必须为零或一”的规则):
\ \
22 29
\ / \
29 --> 28 30
/ \ /
28 30 22
在右树上执行相同的操作只是将根节点从22.2 修改为22.1(无需重新平衡)。