因此,我得到了AVL树。我试图找出至少伪代码,以找到两个值k1和k2之间的所有密钥中具有最小数据值的密钥。假设存储在每个节点中的字段数据是整数。我想确保我的伪代码在O(logn)时间运行。
我知道我可以通过在节点结构中存储一个额外的字段来做到这一点,并显示在更新过程中如何维护该字段,但是我不知道从那里去哪里。
假设节点结构看起来像这样(Java)。
class Node { Node left; Node right; int key; int value; int tree_max; }
复发的tree_maxIS
tree_max
node.tree_max == max(node.value, node.left.tree_max, node.right.tree_max),
通过滥用符号,我们忽略node.left.tree_maxwhen node.left为null并省略node.right.tree_maxwhen node.right为null。每次我们写入节点时,可能都必须更新其所有祖先。我不会编写伪代码,因为如果没有编译器,我很可能会弄错它。
node.left.tree_max
node.left
node.right.tree_max
node.right
为了找到键k1和k2包含键之间的最大值,我们首先找到那些节点的最小公共祖先。
k1
k2
Node lca = root; while (lca != null) { if (lca.key < k1) { lca = lca.left; } else if (k2 < lca.key) { lca = lca.right; } else { break; } }
现在,如果lca为null,则范围为空,我们应该返回负无穷大或抛出异常。否则,我们需要在三个范围来寻找最大:k1包容性,以lca独家,lca本身以及lca独家k2的包容性。我将把k1包容性代码赋予lca互斥性;其他两个范围分别是微不足道的和对称的。我们finger就像在寻找一样,将树向下移动k1,将最大值累加到中left_max。
lca
finger
left_max
int left_max = /* minus infinity */; Node finger = lca.left; while (finger != null) { if (k1 <= finger.key) { left_max = max(left_max, finger.value); if (finger.right != null) { left_max = max(left_max, finger.right.tree_max); } finger = finger.left; } else { finger = finger.right; } }