在二叉搜索树(BST)中,节点左侧下降的所有值都小于(或等于,稍后查看)该节点本身。同样,节点右侧下降的所有值都大于(或等于)该节点值(a)。
一些BST可能选择允许重复的值,因此上面的“或等于”限定符。以下示例可能会更清楚:
14
/ \
13 22
/ / \
1 16 29
/ \
28 29
这显示了一个允许重复的二叉搜索树(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)有趣的是,如果您的排序键使用存储在节点中的完整值(以便包含相同键的节点没有其他额外信息来区分它们),则添加每个节点的计数可能会带来性能提升,而不是允许重复节点。
主要好处是添加或删除副本将仅修改计数,而不是插入或删除新节点(这可能需要重新平衡树)。
因此,要添加项,您首先需要检查它是否已经存在。如果是,则只需增加计数并退出。如果没有,则需要插入一个计数为一的新节点,然后重新平衡。
要删除项,您找到它然后减少计数 - 仅当结果计数为零时,才从树中删除实际节点并重新平衡。
给定较少的节点,搜索也会更快,但这可能不会有很大的影响。
例如,以下两棵树(左侧为非计数树,右侧为计数树)将是等价的(在计数树中,i.c
表示项目i
的c
个副本):
__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
需要重新平衡(因为它现在的高度差为2),这将涉及到重新平衡结果为22-29-28-30
子树,如下所示(这是一个选项,还有其他选项也符合“高度差必须为零或一”的规则):
\ \
22 29
\ / \
29 --> 28 30
/ \ /
28 30 22
对右子树执行相同的操作只需要将根节点从22.2
修改为22.1
(无需重新平衡)。
{num = 1, count 5}
。我认为这对于基本数据类型和字符串来说很有效,但对于其他非原始数据类型则不适用。 - k4anubhav