Algorithm 按顺序索引访问红黑树

Algorithm 按顺序索引访问红黑树,algorithm,binary-tree,complexity-theory,red-black-tree,Algorithm,Binary Tree,Complexity Theory,Red Black Tree,我有一棵红黑树(二叉树,所有的叶子都在2层之内)。 我可以在节点间导航:向左、向右或父节点。 我知道节点的全部计数 我必须找到树中第N个最小的元素。有没有比O(n)更快的方法?有没有通过索引优化访问的想法?您可以在每个节点中添加一个属性,显示该节点的子节点数。 使用此属性,您可以找到第N个最小的节点,其值为O(lgn) 现在,在树中插入(或删除)任何节点时,只需处理该属性。 如果没有旋转,那么它很容易处理,但当你有旋转,它有点困难,但你可以做到 在您应该存储的每个节点X中,有多少节点位于以X为根

我有一棵红黑树(二叉树,所有的叶子都在2层之内)。 我可以在节点间导航:向左、向右或父节点。 我知道节点的全部计数


我必须找到树中第N个最小的元素。有没有比O(n)更快的方法?有没有通过索引优化访问的想法?

您可以在每个节点中添加一个属性,显示该节点的子节点数。 使用此属性,您可以找到第N个最小的节点,其值为O(lgn)

现在,在树中插入(或删除)任何节点时,只需处理该属性。
如果没有旋转,那么它很容易处理,但当你有旋转,它有点困难,但你可以做到

在您应该存储的每个节点X中,有多少节点位于以X为根的子树中

count(LEAF) = 1
count(NODE) = count(NODE->LEFT) + count(NODE->RIGHT) + 1
在每次插入/删除期间,应使用此方程式更新受旋转影响的节点中的计数

在那之后,解决办法很简单

NODE nth(NODE root, int n) {
    if (root->left->count <= n) return nth(root->left, n);
    if ( root->left->count + 1 == n) return root;
    return nth(root->right, n - root->left->count - 1);
}
节点n(节点根,int n){
如果(根->左->左计数,n);
如果(root->left->count+1==n)返回root;
返回n(根->右,n-根->左->计数-1);
}

对于红黑树,您不需要跟踪左侧节点的数量,因为如果它是右偏的(应该是),则左侧节点的数量将始终形成一个梅森序列(1、3、7、15、31…)或
2^深度-1

考虑到这一点,我们可以写下递归获取节点的逻辑上述已接受答案的符号已切换。这是elixir中的正确实现。为了


谢谢实际上,我正在修改.NET
SortedDictionary
以进行排序,但是现在我发现没有简单的方法。这个实现是不正确的。标志切换。见下面我的答案。
def nth(%Rbtree{node: r}, n), do: do_nth(r, n)
defp do_nth({_,h,k,v,l,r}, n) do
  l_count = left_count(h)
  cond do
    l_count > n ->
      case l do
        nil -> {k,v}
        _ -> do_nth(l, n)
      end
    l_count == n -> {k,v}
    true ->
      case r do
        nil -> {k,v}
        _ -> do_nth(r, n - l_count - 1)
      end
  end
end
defp left_count(1), do: 0
defp left_count(0), do: 0
defp left_count(h), do: :math.pow(2,h-1)-1 |> round