我正在研究一个需要循环缓冲区的Haskell中的一个小概念项目。我已经设法使用具有O(1)旋转的数组创建缓冲区,但是当然需要O(N)来插入/删除。我发现了一个使用列表的实现,它看起来需要O(1)来插入和删除,但由于它保持了左右列表,所以在旋转时会跨越一定的边界需要O(N)时间。在命令式语言中,我可以实现带有O(1)插入,删除和旋转的双向循环缓冲区。我认为这不可能像Haskell这样的纯粹功能语言,但我很想知道我是否错了。O(1)haskell中的循环缓冲区?
回答
monad允许在Haskell中描述和执行命令式算法。您可以使用STRef
s作为双向链表的可变指针。
使用ST
描述的自足算法使用runST
执行。不同的runST
执行可能不会共享ST
数据结构(STRef
,STArray
,..)。
如果算法不是“自包含”的,并且数据结构需要在其使用之间执行IO操作时维护,则可以使用stToIO
在IO
monad中访问它。
关于这是纯粹的功能与否 - 我猜这不是?
如果你能处理摊销 O(1)操作,你很可能要么Data.Sequence
从容器包装,或Data.Dequeue
从出队包。前者使用finger trees,而后者使用来自Okasaki的Purely Functional Data Structures(先前版本在线here)的“Banker's Dequeue”。
这听起来像你可能需要一些比这更复杂的东西(因为你提到了双链表),但也许这会有所帮助。这个功能就像map
在一个可变循环列表:
mapOnCycling f = concat . tail . iterate (map f)
使用,如:
*Main> (+1) `mapOnCycling` [3,2,1]
[4,3,2,5,4,3,6,5,4,7,6,5,8,7,6,9,8,7,10,9...]
这里还有一个就像mapAccumL:
mapAccumLOnCycling f acc xs =
let (acc', xs') = mapAccumL f acc xs
in xs' ++ mapAccumLOnCycling f acc' xs'
无论如何,如果你愿意细说甚至更重要的是你的数据结构需要能够“做什么”,我真的很有兴趣听到它。
编辑:如camccann提到的,你可以使用Data.Sequence
用于此目的,根据文档应该给你O1的时间复杂度(出现这样的事,作为O1摊销时间?)观看或添加元素同时向序列的左侧和右侧,以及沿途修改末端。这是否会有你需要的表现,我不确定。
您可以将“当前位置”视为序列的左端。在这里,我们沿着一个序列来回穿梭,产生无限的价值清单。很抱歉,如果它不能编译,我没有GHC的时刻:
shuttle (viewl-> a <: as) = a : shuttle $ rotate (a+1 <| as)
where rotate | even a = rotateForward
| otherwise = rotateBack
rotateBack (viewr-> as' :> a') = a' <| as'
rotateForward (viewl-> a' <: as') = as' |> a'
查看关于原始问题的评论以获取更具体的功能。 – Edward 2010-02-10 12:57:26
更新了我的答案,我认为在纯粹的功能解决方案中为您提供了所需的东西 – jberryman 2010-02-10 17:14:35
顺便说一下,摊销O(1)是完全合理的 - 这只意味着可能会发生昂贵的操作,但频率与成反比他们的成本。例如,一个操作在大多数情况下可能是O(1),偶尔也可能是O(N),但只要后者不比每N次操作中的一次更普遍,分摊的复杂度仍然是O(1)。这对于大多数目的来说都很棒,但对于这里的问题的评论来说,软实时并不那么重要...... – 2010-02-10 18:55:00
- 1. 高效循环缓冲区?
- 2. 逆循环缓冲区
- 3. Java中的循环缓冲区?
- 4. VB.NET中的循环缓冲区
- 5. 为什么我的环形缓冲区/循环缓冲区在java打破?
- 6. 循环缓冲区的线程安全
- 7. 循环字符数组缓冲区 - c
- 8. C++简单循环缓冲区队列
- 9. Qt是否有循环缓冲区?
- 10. Qt和Boost循环缓冲区
- 11. 发布WEB音频缓冲区循环
- 12. 斯卡拉集合循环缓冲区
- 13. 如何在C中实现循环列表(环形缓冲区)?
- 14. 双缓冲区设计I/O同步
- 15. Java:I/O,read()不会填充缓冲区?
- 16. 在c#中的串行端口的循环缓冲区#
- 17. Java - 环形缓冲区
- 18. 如何在使用pthreads/cond_signal/cond_wait时占用1的循环缓冲区大小?
- 19. PHP模板循环缓冲
- 20. Java中的环形缓冲区(队列)
- 21. Recv环形缓冲区vs简单缓冲区
- 22. 如何在SelectListItems列表中实现循环缓冲区?
- 23. Emacs ido在循环列表中首先打开缓冲区
- 24. 区分Vim中的隐藏缓冲区和活动缓冲区
- 25. 用于调试日志记录的循环缓冲区
- 26. 作为“FIFO队列”的Javascript循环缓冲区队列实现
- 27. C + OpenCV:使用循环缓冲区的IplImage
- 28. 通过使用.each()的JQuery循环输出缓冲区()
- 29. 清除循环后的字符串缓冲区/构建器
- 30. 满/空缓冲器的区别在循环队列
如果“道口一定边界”时,转动需要O(N)时间,费用是多少,当它不跨边境?如果它是O(1),并且只有1/N的穿越边界概率,那么旋转平均需要O(1)次。 – finnw 2010-02-08 16:36:03
没错,但是做一个顺序操作,你可以保证你会在某个时候交叉它,而且时间复杂度对于每次轮换都很重要,因为这可能最终会成为一个软实时应用程序。 – Edward 2010-02-08 16:46:54
我从来没有使用过循环缓冲区;简单描述你的缓冲区在做什么很容易?在你的应用程序中是否应该“覆盖”元素? – jberryman 2010-02-09 17:46:19