コンテンツにスキップ

2-3 フィンガーツリー

出典: フリー百科事典『ウィキペディア(Wikipedia)』
2-3 fingertreeから転送)

2-3(2-3 finger treefinger tree)2006Ralf HinzeRoss Paterson[1][2]

使Haskellcontainers[3]Data.Sequence[4]fingertree[5]Scalascalaz[6]

構造

[編集]

2-323(finger)[7] 辿辿辿(2-3)

辿22

2-3232314132-3
2-3

2-3Haskell
-- 2-3フィンガーツリー
data FingerTree a = Empty -- 空の木
                  | Single a -- 1つだけ要素を持つ木
                  | Deep (Digit a) (FingerTree (Node a)) (Digit a) -- より深い木

-- 左右の木の根。1から4つの要素を持つ。
data Digit a = One a | Two a a | Three a a a | Four a a a a

-- 左右の木の根以外。2つまたは3つの要素を持つ。
data Node a = Node2 a a | Node3 a a a

1DigitNode23DigitNodeNode Integer1Node (Node Integer)2Digit()

演算

[編集]

フィンガーツリーに対する要素の追加等の各種演算を示す。ここでは次のように図を混ぜた式でも表現する。

追加

[編集]



1
Empty ▷ a = Single a
(Single a) ▷ b = Deep (One a) Empty (One b)

Digit4Digit1
 (Deep pr m (One b)) ▷ c = Deep pr m (Two b c)

Digit4
 (Deep pr m (Four b c d e)) ▷ f = Deep pr (m ▷ (Node3 b c d)) (Two e f)

1Node

削除

[編集]

popRpopL

1
 popR (Single a) = (Empty, a)

Digit1
 popR (Deep pr m (Two b c)) = (Deep pr m (One b), c)

Digit1
 popR (Deep pr m (One b)) = (borrowR pr m, b)


 borrowR pr Empty = toTree pr

toTreepr


 borrowR pr m
   = let
       (m', node) = popR m
     in
       Deep pr m' (toDigit node)

toDigitNodeDigitNode23TwoThreeNode

popRpopRborrowR1





171Digit3

連結

[編集]

22append使

11
 append(pr, [a, b, c, d, e], Single f) = pr ▷ a ▷ b ▷ c ▷ d ▷ e ▷ f


 append(Deep pr m1 (Four a b c d), [e, f, g, h], Deep (Three i j k) m2 sf)
   = let
       m = append(m1, [Node3 a b c, Node3 d e f, Node3 g h i, Node j k], m2)
     in
       Deep pr m sf

分割

[編集]


class SizeMeasured a where size :: a -> Integer

instance SizeMeasured FingerTree where
  size Empty = 0
  size (Single a) = size a
  size (Deep pr m sf) = size pr + size m + size sf

instance SizeMeasured Digit where
  size (One a) = size a
  size (Two a b) = size a + size b
  -- その他のDigitは省略

instance SizeMeasured Node where
  size (Node2 a b) = size a + size b
  size (Node3 a b c) = size a + size b + size c

newtype Leaf a = Leaf a -- 葉はLeafでくるんでおく。
instance SizeMeasured Leaf where
  size (Leaf _) = 1




iiiisplitTreeAt使

1i0
 splitTreeAt i (Single a) = (Empty, a, Empty)

ii
 splitTreeAt i (Deep pr m sf)
   | i <= size pr -- i番目の葉は左に含まれる
     = let
         (pr1, a, pr2) = splitDigitAt i pr
       in
         (pr1, a, Deep pr2 m sf)
   | i > size pr + size m -- i番目の葉は右に含まれる
     = let
         (sf1, a, sf2) = splitDigitAt (i - size pr - size m) sf
       in
         (Deep pr m sf1, a, pr2)
   -- 続く

iii
 splitDigitAt i (One a) = (Empty, a, Empty)
 splitDigitAt i (Two a b) | i < size a = (Empty, a, Single b)
                          | otherwise = (Single a, b, Empty)
 -- 他のDigitについては略

iiNodeNode
   -- 続き
   | otherwise -- i番目の葉はより深い木に含まれる
       = let
           -- m1とm3はFingerTree、m2はNode。
           (ml, xs, mr) = splitTreeAt (i - size pr) m
           -- lとrはMaybe (Digit a)とする。
           (l, a, r) = splitNodeAt (i - size pr - size ml) xs
         in
           -- deepR, deepLは、rlがNothingの場合に繰り下がり処理をしてFingerTreeを作る関数
           (deepR pr ml l, a, deepL r mr sf)
 
 splitNodeAt i node = -- 省略
 
 deepR pr m Nothing = borrowR pr m
 deepR pr m (Just sf) = Deep pr m sf
 
 -- deepLは省略

分割の一般化

[編集]

i

#e

i使

i使

p0使i0

measurexp
 splitTreeAt p x (Single a) = (Empty, a, Empty)
 splitTreeAt p x (Deep pr m sf)
   | p (x ⊕ measure pr)
     = let
         (pr1, a, pr2) = splitDigitAt p x pr
       in
         (pr1, a, Deep pr2 m sf)
   | p (x ⊕ measure pr ⊕ measure m)
     = let
         (sf1, a, sf2) = splitDigitAt p (i ⊕ measure pr ⊕ measure m) sf
       in
         (Deep pr m sf1, a, pr2)
   | otherwise
       = let
           -- m1とm3はFingerTree、m2はNode。
           (ml, xs, mr) = splitTreeAt p (i ⊕ measure pr) m
           -- lとrはMaybe (Digit a)とする。
           (l, a, r) = splitNodeAt p (i ⊕ measure pr ⊕ measure ml) xs
         in
           -- deepR, deepLは、lrがNothingの場合に繰り下がり処理をしてFingerTreeを作る関数
           (deepR pr ml l, a, deepL r mr sf)

1

実行時間

[編集]


implicit recursive slowdown

[編集]

2-3implicit recursive slowdownimplicit recursive slowdownrecursive slowdownrecursive slowdownnnm2-3



応用

[編集]

ここでは#分割の一般化で示した分割演算を使った応用例を示す。

優先度付きキュー

[編集]

measureHaskellscalaz


探索木

[編集]

measurekkkk

統計量の計算

[編集]

()[8]

measure×(en:Algorithms for calculating variance#Parallel algorithm)


参考文献

[編集]
  1. ^ Ralf Hinze and Ross Paterson, “Finger Trees: A Simple General-purpose Data Structure”, In Journal of Functional Programming Vol. 16, No. 2, 2006, pp. 197–217, doi:10.1017/S0956796805005769
  2. ^ Finger Trees: A Simple General-purpose Data Structure
  3. ^ containers: Assorted concrete container types
  4. ^ Data.Sequence
  5. ^ fingertree: Generic finger-tree structure, with example instances
  6. ^ FingerTree - scalaz-core_2.13 javadoc
  7. ^ Leo J. Guibas, Edward M. McCreight, Michael F. Plass, and Janet R. Roberts, “A new representation for linear lists”, In Proceedings of the ninth annual ACM symposium on Theory of computing (STOC '77), New York, NY, USA: ACM, 1977, pp. 49–60. DOI=10.1145/800105.803395 http://doi.acm.org/10.1145/800105.803395
  8. ^ sigfpe, “Statistical Fingertrees”, A Neighborhood of Infinity, http://blog.sigfpe.com/2010/11/statistical-fingertrees.html 2011年6月5日アクセス