我认为您的问题可能更多在于时间复杂度分析而不是实际算法。
我们知道,如果处理得当,在高度为log[2](n) 的结构良好的 AVL 树中搜索的时间将始终为log[2](n)。在这种情况下搜索丢失的项目与搜索现有项目没有什么不同。
假设您有一个 AVL 树 A,它包括 i 和 i+1。那么我们知道i+1要么是i的父节点,而i是左子节点,要么i+1是i的右子节点。所以我们可以得出结论:
if i ^ i+1 in A => i+1(l)=i v i(r)=i+1
所以如果你找到i 并且它的父节点不是i+1 它的右子节点必须是i+1。您可以在找到 i+1 后将其扩展到 i=i+1 并继续检查此情况。这里很酷的是,如果您跟踪遍历过的节点,那么在i 之后的每个值i+n 只需要查看一个位置。
如果你通过[i+7, i+4, i]你马上知道如果A包含i它不能包含i+1。这是由于i+1 < i+4 而i < i+1 < i+4。
如果你通过[i-6, i-2, i] 你也马上知道如果A 包含i+1 它不能包含i+1。这是由于i-2 < i+1 而i-2 < i < i+1。
如果你要通过[i+7, i+3, i+1, i],你会发现i,i+1,因为i+3不是i+2,你知道i+2必须是i+1的右子节点,因为它必须不是i+3 的孩子,因为它更小,但i+1 已经占据了左孩子的位置。所以你检查i+1的右孩子是否是i+2,你继续从i+3开始检查i+4,本质上是使用算法:
define stack //use your favourite stack implementaion
let n = root node
let i = yourval
while n.val != i
stack.push(n)
if i > n.val
n = n.right
else //equivalent to "else if i < n.val" since loop condition ensures they are not equal
n = n.left
while !stack.empty
if stack.peek.right.val != queue.peek.val + 1
//Implies parent holds value
temp = stack.pop.val + 1
if(temp != stack.peek.val) //If the parent does not hold the next value return it
return temp;
else //Right child holds value
stack.push(queue.peek.right)
i = stack.peek.val
return i+1 //if the stack is empty eventually return the next value
由于 AVL 树的形成方式,您的堆栈最多将是 2*logn[2](n) 元素大(如果 i 是 LHS 上的叶子,最后一个值是 RHS 上的叶子)。因此,总的来说,您的搜索将使用 log[2](n) 进行初始搜索 i 和另一个 2*log[2](n) 组合,从而生成 3*log[2](n),在 Big Omicron 中仍然是 O(log[2](n))。