我在Haskell中寻找类似于Python的bisect
和朋友的bisect_left()
操作。输入将是下限,上限,非递减函数(Ord a)=>(Int-> a),其必须针对下限和上限之间的所有整数以及搜索值来定义。返回值是i
和lower <= i <= upper
的最高整数f(i) < search_term
。性能应为O(log(n))。
为此感到高兴:
(Ord a)=>(Int->a)->Int->Int->a->Int
不会产生任何结果。
某个库中是否有标准的通用二进制搜索运算符?
答案 0 :(得分:7)
Ross Paterson关于Hackage的binary-search软件包可以满足您的需求。具体来说,请参阅searchFromTo,其中包含类型签名
searchFromTo :: Integral a => (a -> Bool) -> a -> a -> Maybe a
正如Tikhon指出的那样,Haskell中的[a]
是链表而不是数组。由于链接列表仅支持顺序访问,因此无法在[a]
数据结构上进行对数时间搜索。相反,您应该使用真正的数组数据结构 - 请参阅vector库以获取数组的首选实现。
Dan Doel为矢量包中的 mutable 向量编写了一系列二进制搜索函数:请参阅Data.Vector.Algorithms.Search库中的vector-algorithms。与提供纯API的Ross Paterson库相比,Data.Vector.Algorithms.Search
中的API是monadic(即,它必须在ST
monad或IO
monad中运行。 / p>
答案 1 :(得分:3)
像bisect_left
这样的函数(假设我正确阅读了它的文档)对于列表来说并不存在。
这是有道理的 - 因为你没有在列表中的O(1)中进行随机访问(记住Haskell列表是链表,而Python使用的东西更像是向量),你无法真正获得O(logn)二进制搜索。
特别是,只是到达列表的中间需要O(n / 2)(这只是O(n))步骤,因此涉及列表中间的算法(如二进制搜索)必须是在Ω(n)。
简而言之 - 二进制搜索在列表上没有意义。如果您正在进行大量搜索,则可能需要不同的数据结构。特别是,请查看内部使用二叉树的Data.Set
。
答案 2 :(得分:0)
binary_search :: Ord a, Integral b => (b -> a) -> b -> b -> a -> b
binary_search f low hi a = go low hi
where
go low hi | low + 1 == hi = low
go low hi = go low' hi'
where
mid = (low + hi) `div` 2
(low',hi') = if f mid < a then (mid,hi) else (low, mid)
(这可能有一个错误。)