我有问题,我无法弄清楚我必须决定我的函数indexJ
必须在每个步骤中选择哪个子树遍历我的平衡二叉树 - JoinList
。< / p>
想法是缓存每个子树的大小(数据元素的数量)。然后可以在每个步骤使用它来确定所需的索引是在左侧分支还是右侧分支。
我有这段代码:
data JoinList m a = Empty
| Single m a
| Append m (JoinList m a) (JoinList m a)
deriving (Eq, Show)
newtype Size = Size Int
deriving (Eq, Ord, Show, Num)
getSize :: Size -> Int
getSize (Size i) = i
class Sized a where
size :: a -> Size
instance Sized Size where
size = id
instance Monoid Size where
mempty = Size 0
mappend = (+)
我写函数:
tag :: Monoid m => JoinList m a -> m
tag Empty = mempty
tag (Single x dt) = x
tag (Append x l_list r_list) = x
(+++) :: Monoid m => JoinList m a -> JoinList m a -> JoinList m a
(+++) jl1 jl2 = Append (mappend (tag jl1) (tag jl2)) jl1 jl2
indexJ :: (Sized b, Monoid b) => Int -> JoinList b a -> Maybe a
indexJ _ Empty = Nothing
indexJ i jl | i < 0 || (i+1) > (sizeJl jl) = Nothing
where sizeJl = getSize . size . tag
indexJ 0 (Single m d) = Just d
indexJ 0 (Append m (Single sz1 dt1) jl2) = Just dt1
indexJ i (Append m jl1 jl2) = if (sizeJl jl1) >= (sizeJl jl2)
then indexJ (i-1) jl1
else indexJ (i-1) jl2
where sizeJl = getSize . size . tag
函数tag
和(+++)
运行良好,但我需要完成indexJ
函数,它必须从我的JoinList树返回第i个元素,i = [0..n]
我的函数indexJ
工作错误=)
如果我有空树 - 它是(大小0)
如果我有单一(大小1)“数据” - 它(大小1)
但是,如果我有附加(大小2)(单(大小1)'k')(单(大小1)'l')我必须选择哪个分支? i-1 = 1,我有两个分支,每个分支有1个数据元素。
更新:如果有人需要为JoinList的树提取和删除函数 我做到了:
dropJ :: (Sized b, Monoid b) => Int -> JoinList b a -> JoinList b a
dropJ _ Empty = Empty
dropJ n jl | n <= 0 = jl
dropJ n jl | n >= (getSize . size $ tag jl) = Empty
dropJ n (Append m jL1 jL2)
| n == s1 = jL2
| n < s1 = (dropJ n jL1) +++ jL2
| otherwise = dropJ (n - s1) jL2
where s1 = getSize . size $ tag jL1
takeJ :: (Sized b, Monoid b) => Int -> JoinList b a -> JoinList b a
takeJ _ Empty = Empty
takeJ n jl | n <= 0 = Empty
takeJ n jl | n >= (getSize . size $ tag jl) = jl
takeJ n (Append m jL1 jL2)
| n == s1 = jL1
| n < s1 = (takeJ n jL1)
| otherwise = jL1 +++ takeJ (n - s1) jL2
where s1 = getSize . size $ tag jL1
答案 0 :(得分:6)
我想在
Append m joinList1 joinList2
joinList1
的元素意味着占据第一个索引,然后是joinList2
的元素。
然后,在编制索引时
indexJ i (Append m jL1 jL2)
您必须将i
与jL1
的大小进行比较 - 让我们称之为s1
。然后jL1
的元素占据索引0到s1 - 1
,jL2
的元素占据从s1
到s1 + s2 - 1
的索引,因此
indexJ :: (Sized b, Monoid b) => Int -> JoinList b a -> Maybe a
indexJ _ Empty = Nothing
indexJ i (Single m d)
| i == 0 = Just d
| otherwise = Nothing
indexJ i (Append m jL1 jL2)
| i < 0 = Nothing
| i >= getSize (size m) = Nothing -- optional, more efficient to have it
| i < s1 = indexJ i jL1
| otherwise = indexJ (i - s1) jL2
where
s1 = getSize . size $ tag jL1
如果索引小于s1
,我们会查看第一个子列表,否则查看第二个子列表。
答案 1 :(得分:1)
通常,您将通过数字序列对树结构中的位置进行编码,而不仅仅是单个数字。例如(假设指数从0开始):
[] -- empty sequence = root of tree
[0,1] -- first follow the first child, then the second child
[0,0,0] -- go 3 levels down in the leftmost branch
这将使索引函数的实现更加简单。