有没有一种方法可以在插入或删除节点时将一些信息添加到节点中。这样就有可能获得O(1)中的后继者和前任者。
答案 0 :(得分:2)
如果在每个节点中还存储了对父节点的引用,那么可以看到在给定节点的情况下如何找到下一个节点:
getNext(node):
if node.right is not null:
node = node.right
while node.left is not null:
node = node.left
return node
while node.parent is not null:
if node.parent.left == node: # node is a left child
return node.parent
node = node.parent # node was a right child
# no more nodes...
return null
如您所见,其中涉及到循环,因此这需要花费不同的时间。在最坏的情况下,跟随叶的节点可能是根,而跟随根的节点可能是深叶。因此,一次调用最多可能涉及到node
的 h 个重新分配,之后是树中的许多边缘( h 是树的高度)。
但是,如果您考虑从最左边的叶子开始在所有节点上进行完整遍历,则会看到每个边沿都精确地遍历了2次:第一次使用left
或right
,第二次与parent
。除了从根到最左边的叶子的路径上的边缘以外,这些边缘仅用parent
访问一次。但是为了简单起见,我们只说他们也被访问过两次(我们对工作进行了高估)。
这意味着对于对getNext
的 n 调用(先前的结果将馈入下一个调用,而最后一个调用返回null
),您将访问< em> 2(n-1)边缘,这意味着平均一个呼叫遍历 2(n-1)/ n 边缘,该边缘总是(略小于)2。 >
因此,这表示摊销后的 O(1)时间复杂度。
当然,getPrevious
的算法将是相似的,并且具有相同的时间复杂度注意事项。
可以轻松扩展用于插入和删除操作(包括自平衡树中的旋转)的算法,以在不增加时间复杂度的情况下也更新每个相关节点中的parent
参考。