Clojure 作为一个数据容器,vector和list的主要区别是什么
假设我们需要一个数字列表,有两种定义:Clojure 作为一个数据容器,vector和list的主要区别是什么,clojure,Clojure,假设我们需要一个数字列表,有两种定义: (def vector1 [1 2 3]) (def list2 '(1 2 3)) 那么主要的区别是什么呢?的[1 2 3]是a,而'(1 2 3)是a。这两种数据结构具有不同的性能特征 向量提供对其元素的快速、索引的随机访问(v34)在O(1)时间内,在索引34处返回向量v的元素。另一方面,修改向量通常更昂贵 列表很容易在开头和/或结尾进行修改(取决于实现),但提供了对元素的线性访问:(第n个(列表1、2、3、4、5)3)需要对列表进行顺序扫描 有关
(def vector1 [1 2 3])
(def list2 '(1 2 3))
那么主要的区别是什么呢?的
[1 2 3]
是a,而'(1 2 3)
是a。这两种数据结构具有不同的性能特征
向量提供对其元素的快速、索引的随机访问(v34)
在O(1)
时间内,在索引34
处返回向量v
的元素。另一方面,修改向量通常更昂贵
列表很容易在开头和/或结尾进行修改(取决于实现),但提供了对元素的线性访问:(第n个(列表1、2、3、4、5)3)
需要对列表进行顺序扫描
有关性能权衡的更多信息,您可以在谷歌上搜索“vector vs.list performance”或类似内容
[后续行动]
好的,让我们进入更多的细节。首先,向量和列表是不特定于Clojure的概念。与映射、队列等一起,它们是数据集合的抽象类型。根据这些抽象定义了对数据进行操作的算法。向量和列表是由我在上面简要描述的行为定义的(即,如果某个东西有大小,那么它就是一个向量,你可以访问它的元素,并在固定时间内建立索引等)
Clojure和其他任何语言一样,在提供以这种方式命名的数据结构时,希望满足这些期望。如果您查看,您将看到对方法的arrayFor调用,该方法的复杂性为O(log32N),在Java数组中的查找为O(1)
为什么我们可以说(v34)
实际上是O(1)?因为Javaint
的log32的最大值约为7。这意味着对向量的随机访问实际上是恒定时间
总之,向量
和列表
之间的主要区别实际上是性能特征。此外,正如Jeremy Heiler所指出的,Clojure在行为上存在逻辑上的差异,也就是说,随着集合的增加,向量评估时间不是O(1),而是log32N
向量(IPersistentVector)
向量是由连续整数索引的值的集合。向量支持通过log32N跃点中的索引访问项。计数为O(1)。conj将该项放在向量的末尾。向量还支持rseq,它以相反的顺序返回项目。向量实现IFn,用于一个参数的invoke(),它们假定该参数是一个索引,并在自身中查找,就好像在第n步一样,即向量是其索引的函数。列表和向量之间有两个主要区别
列表逻辑上在头部增长,而向量逻辑上在尾部增长。在使用conj
功能时,您可以看到这一点。它将根据提供给它的集合类型来增加集合。虽然您可以在任何一方增加集合,但这样做是非常有效的
为了检索列表中的第n项,需要从头部遍历该列表。另一方面,向量不被遍历并返回O(1)中的第n项。(这实际上是O(log32n),但这是由于集合是如何作为持久集合实现的。)
- 向量保存内存相邻区域中的所有数据项,使
整个向量的转移以及项目的插入或删除
与列表相比,价格昂贵
- 列表保存的项目是内存中不相交的区域,进行数据传输
整个列表很昂贵,但插入和删除单个项目
相对便宜
- 经典向量的大小也是固定的,并且限制为N项,而
列表可以动态地增长和收缩
- 向量还提供对元素项的索引访问。清单上没有。
经典向量的前身是数组
- 向量的现代实现通常旨在提供类似的
特性,但底层数据结构实际上可能是
列表或散列,这些向量通常支持动态
重新调整尺寸
你的意思是log2N
?。但是根据clojure的备忘单,(我的vec idx)→ (第n个my vec idx)
,将(my vec idx)
转换为第n个调用。而且,从第N个
的文档中,访问元素是O(N)
。@xiaowl,请仔细阅读文档。O(n)时间是指序列的第n项,由于抽象的要求,必须遍历该项。对于向量,在所有密集用途中,它是O(1)。嗨,Pawel,似乎复杂性不是O(1)
。原因(my vec idx)
被翻译成(nth my vec idx)
@xiaowlnth
是一个用于向量和列表的函数,它提供了对向量的快速访问。仅供参考,我在Clojure的上下文中看到的术语实际上是恒定时间,而不是事实上的恒定时间。