【问题标题】:binary search tree for finding more than one object用于查找多个对象的二叉搜索树
【发布时间】:2012-07-13 15:13:26
【问题描述】:

我刚刚从“Learn You a Haskell”一书中读到了二叉搜索树,我想知道使用这棵树搜索多个元素是否有效?例如,假设我有一堆对象,其中每个对象都有一些索引,并且

        5
      /   \
     3     7
    / \   / \
   1   4 6   8

如果我需要通过索引 8 查找元素,我只需要执行三个步骤5 -> 7 -> 8,而不是遍历整个列表直到结束。但是如果我需要找到多个对象,比如 1、4、6、8,该怎么办?看来我需要对每个元素 5-> 3 -> 1 5 -> 3 -> 45 -> 7 -> 65 -> 7 -> 8 重复相同的操作。

所以我的问题是:使用二叉搜索树查找多个元素是否仍然有意义?是否比检查每个元素的条件更好(在最坏的情况下只会导致 O(n))?

另外,如果我需要检查多个属性,使用哪种数据结构更好。例如。在上面的示例中,我只查找id 属性,但如果我还需要通过namecolor 等进行搜索呢?

【问题讨论】:

    标签: algorithm data-structures


    【解决方案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
    

    【讨论】:

      【解决方案2】:

      没有。

      单次搜索是 O(log n)。 4 次搜索是 (4 log n)。将拾取所有项目的线性搜索是 O(n)。 btree 的树结构意味着查找多个数据需要遍历(实际上比列表遍历更糟糕)。

      【讨论】:

        【解决方案3】:

        假设你的二叉树是平衡的,如果你有一个常数 k 的搜索项,那么总时间为 O(k * log(n)) 的 k 次搜索仍然比单个 O(n) 搜索要好,在每个字符处,您仍然需要进行 k 次比较,使其成为 O(k*n)。即使搜索项目列表已排序,并且您可以在 O(log(k)) 时间内进行二进制搜索以查看当前项目是否匹配,但您仍然处于 O(n * log(k)),即比树差,除非 k 是 Theta(n)。

        【讨论】:

        • 对于第二个问题,没有太多好的选择。如果您正在执行 n 次搜索,那么在 n*log(n) 时间内创建一棵新树,然后每次在 log(n) 时间中进行 n 次搜索,而不是在常规清单。如果您一次只进行一次搜索,那么您最好将其保留为当前格式并满足最坏情况的 O(n) 搜索。
        【解决方案4】:

        在搜索多个元素时,一个完全可以接受的解决方案是使用最有效的算法(在您的情况下为 O(log n))一次搜索一个。但是,单步遍历整个树并汇集所有符合特定条件的元素可能非常有利,这实际上取决于您在代码中搜索的位置和频率。如果您只搜索代码中的一个点,那么一次性收集树中的所有元素而不是逐个搜索它们是有意义的。如果您决定选择该解决方案,那么您可以使用其他数据结构,例如列表。

        如果您需要检查多个属性,我建议将“id”替换为包含所有不同可能标识符(id、颜色、...)的元组。然后,您可以解压缩元组并比较您想要的任何标识符。

        【讨论】:

          猜你喜欢
          • 2011-03-10
          • 1970-01-01
          • 2023-03-09
          • 2021-01-01
          • 2012-06-05
          • 2021-11-27
          • 2023-03-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多