我正在寻找一个通过封装元素提供最快的无序迭代的容器。换句话说,“添加一次,多次迭代”。
OCaml的标准模块中是否有一个足够快(这样进一步优化它将是无用的)?还是某种第三方GPL准备好的?
AFAIK只有一个OCaml编译器,所以快速的概念或多或少都清晰......
......但在我看到几个答案之后,它似乎并非如此。当然,有大量的数据结构允许O(n)迭代通过大小为n的容器。但我正在解决的任务之一是O(n)和O(2n)之间的区别很重要; - )。
我还看到数组和列表提供了有关添加元素的顺序的不必要信息,这是我不需要的。也许在“功能世界”中存在数据结构,这样可以以一点迭代速度交换这些信息。
在C中,我会直接选择一个普通数组。问题是,我应该在OCaml中选择什么?
答案 0 :(得分:10)
你不可能比内置数组和列表做得更好,因为它们是用C语言编写的,除非你绑定到你自己的迭代器本机实现。一个数组的行为几乎就像C中的一个数组(一个连续分配的内存块,包含一系列元素值),可能还有一些由于装箱引起的额外指针间接。列表完全按照您的预期实现:作为具有值和“下一个”指针的单元格。数组将为您提供未装箱类型的最佳位置(尤其是float
s,它具有超级特殊的未装箱实现)。
有关阵列和列表实施的信息,请参阅OCaml源代码中的Section 18.3 of the OCaml manual以及文件byterun/mlvalues.h
,byterun/array.c
和byterun/alloc.c
。
来自提问者:确实,Array
似乎是最快的解决方案。然而,它仅比List
高出7%。也许是因为数组元素的类型不够明确:它是一种代数类型。正如预期的那样Hashtbl
表现差了4倍。
所以,我会选择Array
,我接受这个。好。
答案 1 :(得分:8)
要确定,您将需要衡量。基于编译器可能生成的机器指令,我会尝试一个数组,然后是一个列表。
访问数组元素需要边界检查,地址算术和加载
对列表头部的访问需要加载,空列表测试和已知编译时偏移量的加载。
其详细信息更快可能取决于您的应用程序以及您计算机上发生的其他情况。它们还取决于元素的类型;例如,如果它们是浮点数,ocamlopt
可能足够聪明,可以创建一个未装箱的数组,这将为您节省一个间接级别。
哈希表或平衡树等其他常见数据结构通常要求您在某处分配一些上下文以跟踪您的位置。对于数组,保持跟踪只需要一个整数索引;使用列表,保持跟踪需要一个指针。我认为这在其他数据结构中很难被击败。
最后请注意,可能只有一个OCaml编译器,但它有两个后端:字节码和本机代码。当然,如果您关心此级别的性能,则使用的是本机代码ocamlopt
版本。正确?
请进行测量并将结果编辑到您的问题中。
答案 2 :(得分:6)
不要忘记Bigarray
,它们最接近C数组(只是一块平坦的内存),但不能包含任意的OCaml值。还要考虑切换边界检查(unsafe_set / get)。当然,你应该首先介绍一下。
答案 3 :(得分:3)
数组 - 按顺序访问项目的线性内存 - 最好地利用CPU的L1数据缓存。
答案 4 :(得分:1)
所有常见的数据结构都可以在O(n)时间内迭代,因此数据结构之间的差异只会是恒定的(很可能并不重要)。
至少列表和数组允许迭代而没有显着的开销。我想不出那种情况不够快的情况。