使用序数索引访问树

时间:2017-05-25 01:18:45

标签: haskell data-structures tree functional-programming binary-tree

我有一个右偏的红黑树结构,在给定元素总数的情况下总是会有一些形状。

给定元素k和序数元素n的大小,如何编写一个函数来获取大小为k的树中的第n个元素?

(size:1)
black { 1, 1 }(d:1)
+ 
+ 


(size:2)
black { 1, 1 }(d:1)
+ 
+ red { 2, 2 }(d:1)
  + 
  + 


(size:3)
black { 2, 2 }(d:2)
+ black { 1, 1 }(d:1)
  + 
  + 
+ black { 3, 3 }(d:1)
  + 
  + 


(size:4)
black { 2, 2 }(d:2)
+ black { 1, 1 }(d:1)
  + 
  + 
+ black { 3, 3 }(d:1)
  + 
  + red { 4, 4 }(d:1)
    + 
    + 


(size:5)
black { 2, 2 }(d:2)
+ black { 1, 1 }(d:1)
  + 
  + 
+ red { 4, 4 }(d:2)
  + black { 3, 3 }(d:1)
    + 
    + 
  + black { 5, 5 }(d:1)
    + 
    + 


(size:6)
black { 2, 2 }(d:2)
+ black { 1, 1 }(d:1)
  + 
  + 
+ red { 4, 4 }(d:2)
  + black { 3, 3 }(d:1)
    + 
    + 
  + black { 5, 5 }(d:1)
    + 
    + red { 6, 6 }(d:1)
      + 
      + 


(size:7)
black { 4, 4 }(d:3)
+ black { 2, 2 }(d:2)
  + black { 1, 1 }(d:1)
    + 
    + 
  + black { 3, 3 }(d:1)
    + 
    + 
+ black { 6, 6 }(d:2)
  + black { 5, 5 }(d:1)
    + 
    + 
  + black { 7, 7 }(d:1)
    + 
    + 


(size:8)
black { 4, 4 }(d:3)
+ black { 2, 2 }(d:2)
  + black { 1, 1 }(d:1)
    + 
    + 
  + black { 3, 3 }(d:1)
    + 
    + 
+ black { 6, 6 }(d:2)
  + black { 5, 5 }(d:1)
    + 
    + 
  + black { 7, 7 }(d:1)
    + 
    + red { 8, 8 }(d:1)
      + 
      + 


(size:9)
black { 4, 4 }(d:3)
+ black { 2, 2 }(d:2)
  + black { 1, 1 }(d:1)
    + 
    + 
  + black { 3, 3 }(d:1)
    + 
    + 
+ black { 6, 6 }(d:2)
  + black { 5, 5 }(d:1)
    + 
    + 
  + red { 8, 8 }(d:2)
    + black { 7, 7 }(d:1)
      + 
      + 
    + black { 9, 9 }(d:1)
      + 
      + 


(size:10)
black { 4, 4 }(d:3)
+ black { 2, 2 }(d:2)
  + black { 1, 1 }(d:1)
    + 
    + 
  + black { 3, 3 }(d:1)
    + 
    + 
+ black { 6, 6 }(d:2)
  + black { 5, 5 }(d:1)
    + 
    + 
  + red { 8, 8 }(d:2)
    + black { 7, 7 }(d:1)
      + 
      + 
    + black { 9, 9 }(d:1)
      + 
      + red { 10, 10 }(d:1)
        + 
        + 

1 个答案:

答案 0 :(得分:1)

我把一切都写在餐巾纸上并弄清楚了。对于红黑树,您不需要跟踪左侧的节点数量,因为如果它是正确偏置的(应该是),那么左节点的数量将始终形成一个mersenne系列(1,3,7,15,31 .. 。)或2^depth -1

考虑到这一点,我们可以写下递归获取节点的逻辑。这是elixir中的正确实现。对于package

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