我刚刚从“Learn you a Haskell”一书中读到了二元搜索树,我想知道使用这棵树搜索多个元素是否有效?例如,假设我有一堆对象,其中每个对象都有一些索引,
5
/ \
3 7
/ \ / \
1 4 6 8
如果我需要通过索引8找到一个元素,我只需要执行三个步骤5 -> 7 -> 8
,而不是遍历整个列表直到结束。但是如果我需要找到几个对象,比如1,4,6,8呢?我似乎需要为每个元素5-> 3 -> 1
5 -> 3 -> 4
,5 -> 7 -> 6
和5 -> 7 -> 8
重复相同的操作。
所以我的问题是:使用二叉搜索树来查找多个元素是否仍然有意义?可能比检查每个元素的条件更好(在最坏的情况下只导致O(n))?
此外,如果我需要检查多个属性,最好使用哪种数据结构。例如。在上面的例子中,我只关注id
属性,但如果我还需要按name
或color
等搜索呢?
答案 0 :(得分:1)
假设您的二叉树是平衡的,如果您有一个常数k个搜索项,那么总搜索时间为k(k * log(n))的k搜索仍然优于单个O(n)搜索,在每个角色的位置,你仍然需要进行k次比较,使其成为O(k * n)。即使对搜索项列表进行了排序,并且您可以在O(log(k))时间内进行二进制搜索以查看当前项是否匹配,您仍然处于O(n * log(k)),除非k是Theta(n),否则比树更糟。
答案 1 :(得分:1)
搜索多个元素时,一个完全可以接受的解决方案是使用最有效的算法(在您的情况下为O(log n))一次搜索一个。但是,逐步遍历整个树并汇集符合特定条件的所有元素可能非常有利,这实际上取决于您在代码中搜索的位置和频率。如果您只搜索代码中的一个点,那么一次性收集树中的所有元素而不是逐个搜索它们是有意义的。如果您决定选择该解决方案,那么您可以使用其他数据结构,例如列表。
如果您需要检查多个属性,我建议将“id”替换为包含所有不同可能标识符(id,color,...)的元组。然后,您可以解压缩元组并比较您想要的任何标识符。
答案 2 :(得分:1)
没有
单个搜索是O(log n)。 4次搜索是(4 log n)。线性搜索将获取所有项目,即O(n)。 btree的树结构意味着找到多个数据需要散步(实际上比列表行走更糟)。
答案 3 :(得分:1)
您可以分享一些工作。请参阅members
,其中包含值列表并输出树中输入列表的确切值列表。注意:输出列表的顺序未在输出列表中保留。
编辑:我实际上不确定你是否可以通过members
而不是map member
获得更好的表现(从理论角度来看)。我认为如果输入列表已经排序,那么你可以通过三个(lss,eqs,gts)分割列表来轻松完成。
data BinTree a
= Branch (BinTree a) a (BinTree a)
| Leaf
deriving (Show, Eq, Ord)
empty :: BinTree a
empty = Leaf
singleton :: a -> BinTree a
singleton x = Branch Leaf x Leaf
add :: (Ord a) => a -> BinTree a -> BinTree a
add x Leaf = singleton x
add x tree@(Branch left y right) = case compare x y of
EQ -> tree
LT -> Branch (add x left) y right
GT -> Branch left y (add x right)
member :: (Ord a) => a -> BinTree a -> Bool
member x Leaf = False
member x (Branch left y right) = case compare x y of
EQ -> True
LT -> member x left
GT -> member x right
members :: (Ord a) => [a] -> BinTree a -> [a]
members xs Leaf = []
members xs (Branch left y right) = eqs ++ members lts left ++ members gts right
where
comps = map (\x -> (compare x y, x)) xs
grab ordering = map snd . filter ((ordering ==) . fst)
eqs = grab EQ comps
lts = grab LT comps
gts = grab GT comps