除了列表之外,我在haskell中使用数据结构。我的目标是在Data.Vector
,Data.Sequence
,Data.List
等中选择一个容器...我的问题如下:
我必须创建一个序列(从数学上讲)。序列从0开始。在每次迭代中,生成两个新元素,但是根据第一个元素是否已经在序列中,只应附加一个元素。因此,在每次迭代中都会调用elem
函数(请参阅下面的伪代码)。
appendNewItem :: [Integer] -> [Integer]
appendNewItem acc = let firstElem = someFunc
secondElem = someOtherFunc
newElem = if firstElem `elem` acc
then secondElem
else firstElem
in acc `append` newElem
sequenceUptoN :: Int -> [Integer]
sequenceUptoN n = (iterate appendNewItem [0]) !! n
append
和iterate
函数取决于您使用的集合(我在类型签名中使用列表以简化)。
问题是:我应该使用哪种数据结构?由于手指树的内部结构,此任务的Data.Sequence
更快吗?
非常感谢!!
答案 0 :(得分:6)
不,序列搜索速度不快。 Vector
只是一块平坦的内存,通常可以提供最佳的查找性能。如果要优化搜索,请使用Data.Vector.Unboxed
。 (普通的“盒装”变体也很不错,但它实际上只包含引用到平坦内存块中的元素,所以它的查找速度并不快。)
但是,由于内存布局平坦,Vector
不适合(纯功能)追加:基本上,无论何时添加新元素,整个数组都必须是复制,以免使旧的无效(其他人可能仍在使用)。如果你需要追加,Seq
是一个不错的选择,虽然它没有破坏性追加的速度快:为了获得最大的性能,你需要预先分配一个未初始化的{{3}使用ST
monad填充所需大小,并冻结结果。但这比纯功能替代方案更加繁琐,因此除非你需要挤出所有性能,否则Data.Sequence
是可行的方法。如果只想要追加,而不是查找元素,那么反向顺序的普通旧列表也可以做到。
答案 1 :(得分:4)
我建议将Data.Sequence
与Data.Set
结合使用。 Sequence
用于保存值序列,Set
用于跟踪集合。
Sequence
,List
和Vector
都是处理值的结构,其中结构中的位置在编制索引时具有最重要的意义。在列表中,我们可以有效地操纵前面的元素,在序列中我们可以根据最近端的距离对数来操纵元素,在矢量中我们可以在恒定时间内访问任何元素。但是,如果长度不断变化,那么矢量就不那么有用了,所以在这里排除它们的使用。
但是,您还需要在列表中查找某个值,这些结构对此没有帮助。您必须搜索整个列表/序列/向量以确定不存在新值。 Data.Map
和Data.Set
是您根据Ord
定义索引值的两种结构,并允许您在log(n)
中查找/插入。因此,以内存使用为代价,您可以在firstElem
时间内查看集合中log(n)
的存在,然后在常量时间内将newElem
添加到序列的末尾。只需确保在添加或获取新元素时保持这两个结构同步。